]> git.imager.perl.org - imager.git/blobdiff - Imager.xs
avoid ignoring the result of i_io_getc()
[imager.git] / Imager.xs
index 42a94bc774e8edadef6e44e824015dc3da146b21..cac322d52548c1752aa8fe4fee48deec6f1393bb 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -52,22 +52,11 @@ typedef struct {
 
 START_MY_CXT
 
-im_context_t fallback_context;
-
 static void
 start_context(pTHX) {
   dMY_CXT;
   MY_CXT.ctx = im_context_new();
   sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", MY_CXT.ctx);
-
-  /* Ideally we'd free this reference, but the error message memory
-     was never released on exit, so the associated memory here is reasonable
-     to keep.
-     With logging enabled we always need at least one context, since
-     objects may be released fairly late and attempt to get the log file.
-  */
-  im_context_refinc(MY_CXT.ctx, "start_context");
-  fallback_context = MY_CXT.ctx;
 }
 
 static im_context_t
@@ -75,7 +64,7 @@ perl_get_context(void) {
   dTHX;
   dMY_CXT;
   
-  return MY_CXT.ctx ? MY_CXT.ctx : fallback_context;
+  return MY_CXT.ctx;
 }
 
 #else
@@ -85,7 +74,9 @@ static im_context_t perl_context;
 static void
 start_context(pTHX) {
   perl_context = im_context_new();
-  im_context_refinc(perl_context, "start_context");
+
+  /* just so it gets destroyed */
+  sv_setref_pv(get_sv("Imager::_context", GV_ADD), "Imager::Context", perl_context);
 }
 
 static im_context_t
@@ -124,15 +115,18 @@ Allocate memory that will be discarded when mortals are discarded.
 
 static void *
 malloc_temp(pTHX_ size_t size) {
-  SV *sv = sv_2mortal(newSV(size));
+  void *result;
+  Newx(result, size, char);
+  SAVEFREEPV(result);
 
-  return SvPVX(sv);
+  return result;
 }
 
 static void *
 calloc_temp(pTHX_ size_t size) {
-  void *result = malloc_temp(aTHX_ size);
-  memset(result, 0, size);
+  void *result;
+  Newxz(result, size, char);
+  SAVEFREEPV(result);
 
   return result;
 }
@@ -147,7 +141,7 @@ calloc_temp(pTHX_ size_t size) {
 #define i_img_dimPtr(size) ((i_img_dim *)calloc_temp(aTHX_ sizeof(i_img_dim) * (size)))
 #define SvI_img_dim(sv, pname) (SvIV(sv))
 
-#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color *) * (size)))
+#define i_colorPtr(size) ((i_color *)calloc_temp(aTHX_ sizeof(i_color) * (size)))
 
 #define SvI_color(sv, pname) S_sv_to_i_color(aTHX_ sv, pname)
 
@@ -543,18 +537,29 @@ do_io_new_cb(pTHX_ SV *writecb, SV *readcb, SV *seekcb, SV *closecb) {
 }
 
 struct value_name {
-  char *name;
+  const char *name;
   int value;
 };
-static int lookup_name(const struct value_name *names, int count, char *name, int def_value)
+static int
+lookup_name(const struct value_name *names, int count, char *name, int def_value, int push_errors, const char *id, int *failed)
 {
   int i;
+
+  if (push_errors)
+    *failed = 0;
+
   for (i = 0; i < count; ++i)
     if (strEQ(names[i].name, name))
       return names[i].value;
 
+  if (push_errors) {
+    i_push_errorf(0, "unknown value '%s' for %s", name, id);
+    *failed = 1;
+  }
+
   return def_value;
 }
+
 static struct value_name transp_names[] =
 {
   { "none", tr_none },
@@ -608,14 +613,14 @@ static struct value_name orddith_names[] =
 };
 
 /* look through the hash for quantization options */
-static void
-ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
+static int
+ip_handle_quant_opts_low(pTHX_ i_quantize *quant, HV *hv, int push_errors)
 {
-  /*** POSSIBLY BROKEN: do I need to unref the SV from hv_fetch ***/
   SV **sv;
   int i;
   STRLEN len;
   char *str;
+  int failed = 0;
 
   quant->mc_colors = mymalloc(quant->mc_size * sizeof(i_color));
 
@@ -623,7 +628,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   if (sv && *sv && (str = SvPV(*sv, len))) {
     quant->transp = 
       lookup_name(transp_names, sizeof(transp_names)/sizeof(*transp_names), 
-                 str, tr_none);
+                 str, tr_none, push_errors, "transp", &failed);
+    if (failed)
+       return 0;
     if (quant->transp != tr_none) {
       quant->tr_threshold = 127;
       sv = hv_fetch(hv, "tr_threshold", 12, 0);
@@ -633,13 +640,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
     if (quant->transp == tr_errdiff) {
       sv = hv_fetch(hv, "tr_errdiff", 10, 0);
       if (sv && *sv && (str = SvPV(*sv, len)))
-       quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+       quant->tr_errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "tr_errdiff", &failed);
+       if (failed)
+         return 0;
     }
     if (quant->transp == tr_ordered) {
       quant->tr_orddith = od_tiny;
       sv = hv_fetch(hv, "tr_orddith", 10, 0);
-      if (sv && *sv && (str = SvPV(*sv, len)))
-       quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random);
+      if (sv && *sv && (str = SvPV(*sv, len))) {
+       quant->tr_orddith = lookup_name(orddith_names, sizeof(orddith_names)/sizeof(*orddith_names), str, od_random, push_errors, "tr_orddith", &failed);
+       if (failed)
+          return 0;
+      }
 
       if (quant->tr_orddith == od_custom) {
        sv = hv_fetch(hv, "tr_map", 6, 0);
@@ -664,7 +676,9 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   sv = hv_fetch(hv, "make_colors", 11, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
     quant->make_colors = 
-      lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut);
+      lookup_name(make_color_names, sizeof(make_color_names)/sizeof(*make_color_names), str, mc_median_cut, push_errors, "make_colors", &failed);
+    if (failed)
+      return 0;
   }
   sv = hv_fetch(hv, "colors", 6, 0);
   if (sv && *sv && SvROK(*sv) && SvTYPE(SvRV(*sv)) == SVt_PVAV) {
@@ -681,6 +695,10 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        i_color *col = INT2PTR(i_color *, SvIV((SV*)SvRV(*sv1)));
        quant->mc_colors[i] = *col;
       }
+      else if (push_errors) {
+        i_push_errorf(0, "colors[%d] isn't an Imager::Color object", i);
+       return 0;
+      }
     }
   }
   sv = hv_fetch(hv, "max_colors", 10, 0);
@@ -693,11 +711,15 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
   quant->translate = pt_closest;
   sv = hv_fetch(hv, "translate", 9, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
-    quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest);
+    quant->translate = lookup_name(translate_names, sizeof(translate_names)/sizeof(*translate_names), str, pt_closest, push_errors, "translate", &failed);
+    if (failed)
+      return 0;
   }
   sv = hv_fetch(hv, "errdiff", 7, 0);
   if (sv && *sv && (str = SvPV(*sv, len))) {
-    quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd);
+    quant->errdiff = lookup_name(errdiff_names, sizeof(errdiff_names)/sizeof(*errdiff_names), str, ed_floyd, push_errors, "errdiff", &failed);
+    if (failed)
+      return 0;
   }
   if (quant->translate == pt_errdiff && quant->errdiff == ed_custom) {
     /* get the error diffusion map */
@@ -722,7 +744,12 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        for (i = 0; i < len; ++i) {
          SV **sv2 = av_fetch(av, i, 0);
          if (sv2 && *sv2) {
-           quant->ed_map[i] = SvIV(*sv2);
+           IV iv = SvIV(*sv2);
+           if (push_errors && iv < 0) {
+             i_push_errorf(0, "errdiff_map values must be non-negative, errdiff[%d] is negative", i);
+             return 0;
+           }
+           quant->ed_map[i] = iv;
            sum += quant->ed_map[i];
          }
        }
@@ -732,12 +759,18 @@ ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv)
        myfree(quant->ed_map);
        quant->ed_map = 0;
        quant->errdiff = ed_floyd;
+       if (push_errors) {
+         i_push_error(0, "error diffusion map must contain some non-zero values");
+         return 0;
+       }
       }
     }
   }
   sv = hv_fetch(hv, "perturb", 7, 0);
   if (sv && *sv)
     quant->perturb = SvIV(*sv);
+
+  return 1;
 }
 
 static void
@@ -747,6 +780,20 @@ ip_cleanup_quant_opts(pTHX_ i_quantize *quant) {
     myfree(quant->ed_map);
 }
 
+static int
+ip_handle_quant_opts2(pTHX_ i_quantize *quant, HV *hv) {
+  int result = ip_handle_quant_opts_low(aTHX_ quant, hv, 1);
+  if (!result) {
+     ip_cleanup_quant_opts(aTHX_ quant);
+  }
+  return result;
+}
+
+static void
+ip_handle_quant_opts(pTHX_ i_quantize *quant, HV *hv) {
+  (void)ip_handle_quant_opts_low(aTHX_ quant, hv, 0);
+}
+
 /* copies the color map from the hv into the colors member of the HV */
 static void
 ip_copy_colors_back(pTHX_ HV *hv, i_quantize *quant) {
@@ -792,7 +839,7 @@ S_get_poly_fill_mode(pTHX_ SV *sv) {
   else {
     return (i_poly_fill_mode_t)lookup_name
     (poly_fill_mode_names, ARRAY_COUNT(poly_fill_mode_names),
-     SvPV_nolen(sv), i_pfm_evenodd);
+     SvPV_nolen(sv), i_pfm_evenodd, 0, NULL, NULL);
   }
 }
 
@@ -1062,7 +1109,8 @@ static im_pl_ext_funcs im_perl_funcs =
   IMAGER_PL_API_LEVEL,
   ip_handle_quant_opts,
   ip_cleanup_quant_opts,
-  ip_copy_colors_back
+  ip_copy_colors_back,
+  ip_handle_quant_opts2
 };
 
 #define PERL_PL_SET_GLOBAL_CALLBACKS \
@@ -1111,7 +1159,10 @@ ICL_set_internal(cl,r,g,b,a)
                unsigned char     b
                unsigned char     a
           PPCODE:
-              ICL_set_internal(cl, r, g, b, a);
+              cl->rgba.r = r;
+              cl->rgba.g = g;
+              cl->rgba.b = b;
+              cl->rgba.a = a;
               EXTEND(SP, 1);
               PUSHs(ST(0));
 
@@ -1463,6 +1514,10 @@ int
 i_io_getc(ig)
        Imager::IO ig
 
+void
+i_io_nextc(ig)
+       Imager::IO ig
+
 int
 i_io_putc(ig, c)
        Imager::IO ig
@@ -2474,10 +2529,12 @@ i_tt_has_chars(handle, text_sv, utf8)
         work = mymalloc(len);
         count = i_tt_has_chars(handle, text, len, utf8, work);
         if (GIMME_V == G_ARRAY) {
-          EXTEND(SP, count);
-          for (i = 0; i < count; ++i) {
-            PUSHs(boolSV(work[i]));
-          }
+         if (count) {
+            EXTEND(SP, count);
+            for (i = 0; i < count; ++i) {
+              PUSHs(boolSV(work[i]));
+            }
+         }
         }
         else {
           EXTEND(SP, 1);
@@ -2513,7 +2570,6 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
         size_t len;
         size_t outsize;
         char name[255];
-       SSize_t count = 0;
       PPCODE:
         i_clear_error();
         text = SvPV(text_sv, work_len);
@@ -2535,16 +2591,14 @@ i_tt_glyph_name(handle, text_sv, utf8 = 0)
             ch = *text++;
             --len;
           }
-          EXTEND(SP, count+1);
+          EXTEND(SP, 1);
           if ((outsize = i_tt_glyph_name(handle, ch, name, sizeof(name))) != 0) {
-           ST(count) = sv_2mortal(newSVpv(name, 0));
+           PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
           else {
-           ST(count) = &PL_sv_undef;
+           PUSHs(&PL_sv_undef);
           }
-          ++count;
         }
-       XSRETURN(count);
 
 #endif 
 
@@ -2674,17 +2728,14 @@ i_get_anonymous_color_histo(im, maxc = 0x40000000)
         int col_cnt;
     PPCODE:
        col_cnt = i_get_anonymous_color_histo(im, &col_usage, maxc);
-        if (col_cnt > 0) {
-            EXTEND(SP, col_cnt);
-            for (i = 0; i < col_cnt; i++)  {
-                PUSHs(sv_2mortal(newSViv( col_usage[i])));
-            }
-            myfree(col_usage);
-            XSRETURN(col_cnt);
-        }
-        else {
-            XSRETURN_EMPTY;
+        if (col_cnt <= 0) {
+           XSRETURN_EMPTY;
+       }
+        EXTEND(SP, col_cnt);
+        for (i = 0; i < col_cnt; i++)  {
+            PUSHs(sv_2mortal(newSViv( col_usage[i])));
         }
+        myfree(col_usage);
 
 
 void
@@ -3000,7 +3051,7 @@ i_errors()
          if (!av_store(av, 1, sv)) {
            SvREFCNT_dec(sv);
          }
-         PUSHs(sv_2mortal(newRV_noinc((SV*)av)));
+         XPUSHs(sv_2mortal(newRV_noinc((SV*)av)));
          ++i;
        }
 
@@ -3044,9 +3095,9 @@ i_nearest_color(im, ...)
        num = num <= av_len(ac) ? num : av_len(ac);
        num++; 
        if (num < 2) croak("Usage: i_nearest_color array refs must have more than 1 entry each");
-       xo = mymalloc( sizeof(i_img_dim) * num );
-       yo = mymalloc( sizeof(i_img_dim) * num );
-       ival = mymalloc( sizeof(i_color) * num );
+       xo = malloc_temp(aTHX_ sizeof(i_img_dim) * num );
+       yo = malloc_temp(aTHX_ sizeof(i_img_dim) * num );
+       ival = malloc_temp(aTHX_ sizeof(i_color) * num );
        for(i = 0; i<num; i++) {
          xo[i]   = (i_img_dim)SvIV(* av_fetch(axx, i, 0));
          yo[i]   = (i_img_dim)SvIV(* av_fetch(ayy, i, 0));
@@ -3145,22 +3196,23 @@ i_img_pal_new(x, y, channels, maxpal)
        int     maxpal
 
 Imager::ImgRaw
-i_img_to_pal(src, quant)
+i_img_to_pal(src, quant_hv)
         Imager::ImgRaw src
+       HV *quant_hv
       PREINIT:
         HV *hv;
         i_quantize quant;
       CODE:
-        if (!SvROK(ST(1)) || ! SvTYPE(SvRV(ST(1))))
-          croak("i_img_to_pal: second argument must be a hash ref");
-        hv = (HV *)SvRV(ST(1));
         memset(&quant, 0, sizeof(quant));
        quant.version = 1;
         quant.mc_size = 256;
-       ip_handle_quant_opts(aTHX_ &quant, hv);
+       i_clear_error();
+       if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+          XSRETURN_EMPTY;
+       }
         RETVAL = i_img_to_pal(src, &quant);
         if (RETVAL) {
-          ip_copy_colors_back(aTHX_ hv, &quant);
+          ip_copy_colors_back(aTHX_ quant_hv, &quant);
         }
        ip_cleanup_quant_opts(aTHX_ &quant);
       OUTPUT:
@@ -3194,7 +3246,9 @@ i_img_make_palette(HV *quant_hv, ...)
         memset(&quant, 0, sizeof(quant));
        quant.version = 1;
        quant.mc_size = 256;
-        ip_handle_quant_opts(aTHX_ &quant, quant_hv);
+        if (!ip_handle_quant_opts2(aTHX_ &quant, quant_hv)) {
+         XSRETURN_EMPTY;
+       }
        i_quant_makemap(&quant, imgs, count);
        EXTEND(SP, quant.mc_count);
        for (i = 0; i < quant.mc_count; ++i) {
@@ -3202,6 +3256,7 @@ i_img_make_palette(HV *quant_hv, ...)
          PUSHs(sv_c);
        }
        ip_cleanup_quant_opts(aTHX_ &quant);
+        myfree(imgs);
        
 
 void
@@ -3303,6 +3358,7 @@ i_addcolors(im, ...)
           }
         }
         RETVAL = i_addcolors(im, colors, items-1);
+        myfree(colors);
       OUTPUT:
         RETVAL