]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
update Changes
[imager.git] / Imager.xs
index 155e2c5f802c4ff393075a9a2f80a5905677f9ee..2b757fed6e3b830ac247e576fc266056b88dc66e 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -30,6 +30,10 @@ extern "C" {
 
 #include "imperl.h"
 
+#ifndef SV_COW_DROP_PV
+#define SV_COW_DROP_PV
+#endif
+
 /*
 
 Context object management
@@ -147,7 +151,7 @@ calloc_temp(pTHX_ size_t size) {
 static i_color
 S_sv_to_i_color(pTHX_ SV *sv, const char *pname) {
   if (!sv_derived_from(sv, "Imager::Color")) {
-    croak("%s: not a color object");
+    croak("%s: not a color object", pname);
   }
   return *INT2PTR(i_color *, SvIV((SV *)SvRV(sv)));
 }
@@ -234,9 +238,9 @@ static int getobj(void *hv_t,char *key,char *type,void **store) {
 
 UTIL_table_t i_UTIL_table={getstr,getint,getdouble,getvoid,getobj};
 
-void my_SvREFCNT_dec(void *p) {
-  dTHX;
-  SvREFCNT_dec((SV*)p);
+static void
+free_buffer(void *p) {
+  myfree(p);
 }
 
 
@@ -411,7 +415,6 @@ static int io_closer(void *p) {
   if (SvOK(cbd->closecb)) {
     dSP;
     I32 count;
-    SV *sv;
 
     ENTER;
     SAVETMPS;
@@ -422,8 +425,12 @@ static int io_closer(void *p) {
 
     SPAGAIN;
     
-    sv = POPs;
-    success = SvTRUE(sv);
+    if (count) {
+      SV *sv = POPs;
+      success = SvTRUE(sv);
+    }
+    else
+      success = 0;
 
     PUTBACK;
     FREETMPS;
@@ -444,14 +451,41 @@ static void io_destroyer(void *p) {
   myfree(cbd);
 }
 
+static bool
+im_SvREFSCALAR(SV *sv) {
+  svtype type = SvTYPE(sv);
+  return type == SVt_PV || type == SVt_PVIV || type == SVt_PVNV
+      || type == SVt_PVMG || type == SVt_IV || type == SVt_NV
+      || type == SVt_PVLV || type == SVt_REGEXP;
+}
+
 static i_io_glue_t *
 do_io_new_buffer(pTHX_ SV *data_sv) {
   const char *data;
+  char *data_copy;
   STRLEN length;
+  SV *sv;
 
-  data = SvPVbyte(data_sv, length);
-  SvREFCNT_inc(data_sv);
-  return io_new_buffer(data, length, my_SvREFCNT_dec, data_sv);
+  SvGETMAGIC(data_sv);
+  if (SvROK(data_sv)) {
+    if (im_SvREFSCALAR(data_sv)) {
+      sv = SvRV(data_sv);
+    }
+    else {
+      i_push_error(0, "data is not a scalar or a reference to scalar");
+      return NULL;
+    }
+  }
+  else {
+    sv = data_sv;
+  }
+
+  /* previously this would keep the SV around, but this is unsafe in
+     many ways, so always copy the bytes */
+  data = SvPVbyte(sv, length);
+  data_copy = mymalloc(length);
+  memcpy(data_copy, data, length);
+  return io_new_buffer(data_copy, length, free_buffer, data_copy);
 }
 
 static const char *
@@ -930,6 +964,7 @@ static im_pl_ext_funcs im_perl_funcs =
 
 #define IIM_new i_img_8_new
 #define IIM_DESTROY i_img_destroy
+typedef int SysRet;
 
 #ifdef IMEXIF_ENABLE
 #define i_exif_enabled() 1
@@ -1102,7 +1137,10 @@ Imager::IO
 io_new_buffer(data_sv)
          SV   *data_sv
        CODE:
+         i_clear_error();
          RETVAL = do_io_new_buffer(aTHX_ data_sv);
+         if (!RETVAL)
+           XSRETURN(0);
         OUTPUT:
           RETVAL
 
@@ -1112,7 +1150,6 @@ io_new_cb(writecb, readcb, seekcb, closecb, maxwrite = CBDATA_BUFSIZE)
         SV *readcb;
         SV *seekcb;
         SV *closecb;
-        int maxwrite;
       CODE:
         RETVAL = do_io_new_cb(aTHX_ writecb, readcb, seekcb, closecb);
       OUTPUT:
@@ -1174,7 +1211,10 @@ Imager::IO
 io_new_buffer(class, data_sv)
        SV *data_sv
     CODE:
+        i_clear_error();
         RETVAL = do_io_new_buffer(aTHX_ data_sv);
+       if (!RETVAL)
+         XSRETURN(0);
     OUTPUT:
         RETVAL
 
@@ -1244,15 +1284,9 @@ i_io_raw_read(ig, buffer_sv, size)
       PPCODE:
         if (size <= 0)
          croak("size negative in call to i_io_raw_read()");
-        /* prevent an undefined value warning if they supplied an 
-          undef buffer.
-           Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
-#ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
-          sv_utf8_downgrade(buffer_sv, FALSE);
-#endif
+       if (SvTHINKFIRST(buffer_sv))
+         sv_force_normal_flags(buffer_sv, SV_COW_DROP_PV);
+       SvUPGRADE(buffer_sv, SVt_PV);
        buffer = SvGROW(buffer_sv, size+1);
         result = i_io_raw_read(ig, buffer, size);
         if (result >= 0) {
@@ -1375,15 +1409,9 @@ i_io_read(ig, buffer_sv, size)
       PPCODE:
         if (size <= 0)
          croak("size negative in call to i_io_read()");
-        /* prevent an undefined value warning if they supplied an 
-          undef buffer.
-           Orginally conditional on !SvOK(), but this will prevent the
-          downgrade from croaking */
-       sv_setpvn(buffer_sv, "", 0);
-#ifdef SvUTF8
-       if (SvUTF8(buffer_sv))
-          sv_utf8_downgrade(buffer_sv, FALSE);
-#endif
+       if (SvTHINKFIRST(buffer_sv))
+         sv_force_normal_flags(buffer_sv, SV_COW_DROP_PV);
+       SvUPGRADE(buffer_sv, SVt_PV);
        buffer = SvGROW(buffer_sv, size+1);
         result = i_io_read(ig, buffer, size);
         if (result >= 0) {
@@ -1738,39 +1766,18 @@ i_arc_out_aa(im,x,y,rad,d1,d2,val)
 
 
 void
-i_bezier_multi(im,xc,yc,val)
+i_bezier_multi(im,x,y,val)
     Imager::ImgRaw     im
-             Imager::Color  val
-            PREINIT:
-            double   *x,*y;
-            int       len;
-            AV       *av1;
-            AV       *av2;
-            SV       *sv1;
-            SV       *sv2;
-            int i;
-            PPCODE:
-            ICL_info(val);
-            if (!SvROK(ST(1))) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(1))) != SVt_PVAV) croak("Imager: Parameter 1 to i_bezier_multi must be a reference to an array\n");
-            if (!SvROK(ST(2))) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            if (SvTYPE(SvRV(ST(2))) != SVt_PVAV) croak("Imager: Parameter 2 to i_bezier_multi must be a reference to an array\n");
-            av1=(AV*)SvRV(ST(1));
-            av2=(AV*)SvRV(ST(2));
-            if (av_len(av1) != av_len(av2)) croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
-            len=av_len(av1)+1;
-            x=mymalloc( len*sizeof(double) );
-            y=mymalloc( len*sizeof(double) );
-            for(i=0;i<len;i++) {
-              sv1=(*(av_fetch(av1,i,0)));
-              sv2=(*(av_fetch(av2,i,0)));
-              x[i]=(double)SvNV(sv1);
-              y[i]=(double)SvNV(sv2);
-            }
-             i_bezier_multi(im,len,x,y,val);
-             myfree(x);
-             myfree(y);
-
+    double *x
+    double *y
+    Imager::Color  val
+  PREINIT:
+    STRLEN size_x;
+    STRLEN size_y;
+  PPCODE:
+    if (size_x != size_y)
+      croak("Imager: x and y arrays to i_bezier_multi must be equal length\n");
+    i_bezier_multi(im,size_x,x,y,val);
 
 int
 i_poly_aa(im,x,y,val)
@@ -2109,7 +2116,6 @@ i_map(im, pmaps_av)
     AV *pmaps_av
   PREINIT:
     unsigned int mask = 0;
-    AV *avmain;
     AV *avsub;
     SV **temp;
     int len;
@@ -2931,22 +2937,16 @@ DSO_call(handle,func_index,hv)
             PPCODE:
               DSO_call( (DSO_handle *)handle,func_index,hv);
 
-SV *
+Imager::Color
 i_get_pixel(im, x, y)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y;
-      PREINIT:
-        i_color *color;
       CODE:
-       color = (i_color *)mymalloc(sizeof(i_color));
-       if (i_gpix(im, x, y, color) == 0) {
-          RETVAL = NEWSV(0, 0);
-          sv_setref_pv(RETVAL, "Imager::Color", (void *)color);
-        }
-        else {
-          myfree(color);
-          RETVAL = &PL_sv_undef;
+       RETVAL = (i_color *)mymalloc(sizeof(i_color));
+       if (i_gpix(im, x, y, RETVAL) != 0) {
+          myfree(RETVAL);
+         XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3103,11 +3103,10 @@ i_ppal_p(im, l, y, data)
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_addcolors(im, ...)
         Imager::ImgRaw  im
       PREINIT:
-        int index;
         i_color *colors;
         int i;
       CODE:
@@ -3125,17 +3124,7 @@ i_addcolors(im, ...)
             croak("i_addcolor: pixels must be Imager::Color objects");
           }
         }
-        index = i_addcolors(im, colors, items-1);
-        myfree(colors);
-        if (index == 0) {
-          RETVAL = newSVpv("0 but true", 0);
-        }
-        else if (index == -1) {
-          RETVAL = &PL_sv_undef;
-        }
-        else {
-          RETVAL = newSViv(index);
-        }
+        RETVAL = i_addcolors(im, colors, items-1);
       OUTPUT:
         RETVAL
 
@@ -3167,29 +3156,24 @@ i_setcolors(im, index, ...)
        RETVAL
 
 void
-i_getcolors(im, index, ...)
+i_getcolors(im, index, count=1)
         Imager::ImgRaw im
         int index
+       int count
       PREINIT:
         i_color *colors;
-        int count = 1;
         int i;
       PPCODE:
-        if (items > 3)
-          croak("i_getcolors: too many arguments");
-        if (items == 3)
-          count = SvIV(ST(2));
         if (count < 1)
           croak("i_getcolors: count must be positive");
-        colors = mymalloc(sizeof(i_color) * count);
+        colors = malloc_temp(aTHX_ sizeof(i_color) * count);
         if (i_getcolors(im, index, colors, count)) {
+         EXTEND(SP, count);
           for (i = 0; i < count; ++i) {
             SV *sv = make_i_color_sv(aTHX_ colors+i);
             PUSHs(sv);
           }
         }
-        myfree(colors);
-
 
 undef_neg_int
 i_colorcount(im)
@@ -3199,18 +3183,13 @@ undef_neg_int
 i_maxcolors(im)
         Imager::ImgRaw im
 
-SV *
+i_palidx
 i_findcolor(im, color)
         Imager::ImgRaw im
         Imager::Color color
-      PREINIT:
-        i_palidx index;
       CODE:
-        if (i_findcolor(im, color, &index)) {
-          RETVAL = newSViv(index);
-        }
-        else {
-          RETVAL = &PL_sv_undef;
+        if (!i_findcolor(im, color, &RETVAL)) {
+         XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3239,7 +3218,7 @@ i_gsamp(im, l, r, y, channels)
         i_img_dim count, i;
       PPCODE:
         if (l < r) {
-          data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count); /* XXX: memleak? */
+          data = mymalloc(sizeof(i_sample_t) * (r-l) * channels.count);
           count = i_gsamp(im, l, r, y, data, channels.channels, channels.count);
           if (GIMME_V == G_ARRAY) {
             EXTEND(SP, count);
@@ -3254,8 +3233,7 @@ i_gsamp(im, l, r, y, channels)
         }
         else {
           if (GIMME_V != G_ARRAY) {
-            EXTEND(SP, 1);
-            PUSHs(&PL_sv_undef);
+           XSRETURN_UNDEF;
           }
         }
 
@@ -3503,8 +3481,7 @@ i_gsampf(im, l, r, y, channels)
         }
         else {
           if (GIMME_V != G_ARRAY) {
-            EXTEND(SP, 1);
-            PUSHs(&PL_sv_undef);
+           XSRETURN_UNDEF;
           }
         }
 
@@ -3553,22 +3530,16 @@ i_plinf(im, l, y, ...)
       OUTPUT:
         RETVAL
 
-SV *
+Imager::Color::Float
 i_gpixf(im, x, y)
        Imager::ImgRaw im
        i_img_dim x
        i_img_dim y;
-      PREINIT:
-        i_fcolor *color;
       CODE:
-       color = (i_fcolor *)mymalloc(sizeof(i_fcolor));
-       if (i_gpixf(im, x, y, color) == 0) {
-          RETVAL = NEWSV(0,0);
-          sv_setref_pv(RETVAL, "Imager::Color::Float", (void *)color);
-        }
-        else {
-          myfree(color);
-          RETVAL = &PL_sv_undef;
+       RETVAL = (i_fcolor *)mymalloc(sizeof(i_fcolor));
+       if (i_gpixf(im, x, y, RETVAL) != 0) {
+          myfree(RETVAL);
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3664,16 +3635,18 @@ i_img_to_drgb(im)
        Imager::ImgRaw im
 
 undef_int
-i_tags_addn(im, name, code, idata)
+i_tags_addn(im, name_sv, code, idata)
         Imager::ImgRaw im
+       SV *name_sv
         int     code
         int     idata
       PREINIT:
         char *name;
         STRLEN len;
       CODE:
-        if (SvOK(ST(1)))
-          name = SvPV(ST(1), len);
+        SvGETMAGIC(name_sv);
+        if (SvOK(name_sv))
+          name = SvPV_nomg(name_sv, len);
         else
           name = NULL;
         RETVAL = i_tags_addn(&im->tags, name, code, idata);
@@ -3681,21 +3654,25 @@ i_tags_addn(im, name, code, idata)
         RETVAL
 
 undef_int
-i_tags_add(im, name, code, data, idata)
+i_tags_add(im, name_sv, code, data_sv, idata)
         Imager::ImgRaw  im
+       SV *name_sv
         int code
+       SV *data_sv
         int idata
       PREINIT:
         char *name;
         char *data;
         STRLEN len;
       CODE:
-        if (SvOK(ST(1)))
-          name = SvPV(ST(1), len);
+        SvGETMAGIC(name_sv);
+        if (SvOK(name_sv))
+          name = SvPV_nomg(name_sv, len);
         else
           name = NULL;
-        if (SvOK(ST(3)))
-          data = SvPV(ST(3), len);
+       SvGETMAGIC(data_sv);
+        if (SvOK(data_sv))
+          data = SvPV(data_sv, len);
         else {
           data = NULL;
           len = 0;
@@ -3704,7 +3681,7 @@ i_tags_add(im, name, code, data, idata)
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_find(im, name, start)
         Imager::ImgRaw  im
         char *name
@@ -3713,17 +3690,14 @@ i_tags_find(im, name, start)
         int entry;
       CODE:
         if (i_tags_find(&im->tags, name, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+         RETVAL = entry;
         } else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
 
-SV *
+SysRet
 i_tags_findn(im, code, start)
         Imager::ImgRaw  im
         int             code
@@ -3732,13 +3706,10 @@ i_tags_findn(im, code, start)
         int entry;
       CODE:
         if (i_tags_findn(&im->tags, code, start, &entry)) {
-          if (entry == 0)
-            RETVAL = newSVpv("0 but true", 0);
-          else
-            RETVAL = newSViv(entry);
+          RETVAL = entry;
         }
         else {
-          RETVAL = &PL_sv_undef;
+          XSRETURN_UNDEF;
         }
       OUTPUT:
         RETVAL
@@ -3852,19 +3823,21 @@ i_new_fill_solidf(cl, combine)
         int combine
 
 Imager::FillHandle
-i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color fg
         Imager::Color bg
         int combine
         int hatch
+       SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV_nomg(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3873,19 +3846,21 @@ i_new_fill_hatch(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
+i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch_sv, dx, dy)
         Imager::Color::Float fg
         Imager::Color::Float bg
         int combine
         int hatch
+        SV *cust_hatch_sv
         i_img_dim dx
         i_img_dim dy
       PREINIT:
         unsigned char *cust_hatch;
         STRLEN len;
       CODE:
-        if (SvOK(ST(4))) {
-          cust_hatch = (unsigned char *)SvPV(ST(4), len);
+        SvGETMAGIC(cust_hatch_sv);
+        if (SvOK(cust_hatch_sv)) {
+          cust_hatch = (unsigned char *)SvPV(cust_hatch_sv, len);
         }
         else
           cust_hatch = NULL;
@@ -3894,8 +3869,9 @@ i_new_fill_hatchf(fg, bg, combine, hatch, cust_hatch, dx, dy)
         RETVAL
 
 Imager::FillHandle
-i_new_fill_image(src, matrix, xoff, yoff, combine)
+i_new_fill_image(src, matrix_sv, xoff, yoff, combine)
         Imager::ImgRaw src
+       SV *matrix_sv
         i_img_dim xoff
         i_img_dim yoff
         int combine
@@ -3907,13 +3883,14 @@ i_new_fill_image(src, matrix, xoff, yoff, combine)
         SV *sv1;
         int i;
       CODE:
-        if (!SvOK(ST(1))) {
+        SvGETMAGIC(matrix_sv);
+        if (!SvOK(matrix_sv)) {
           matrixp = NULL;
         }
         else {
-          if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-            croak("i_new_fill_image: parameter must be an arrayref");
-         av=(AV*)SvRV(ST(1));
+          if (!SvROK(matrix_sv) || SvTYPE(SvRV(matrix_sv)) != SVt_PVAV)
+            croak("i_new_fill_image: matrix parameter must be an arrayref or undef");
+         av=(AV*)SvRV(matrix_sv);
          len=av_len(av)+1;
           if (len > 9)
             len = 9;