about summary refs log tree commit diff
path: root/lib/libppmcmap.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-29 16:19:20 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-29 16:19:20 +0000
commit89973760e357aaf87b834f93e133ffb76b157d4b (patch)
tree2c24ce7e2601af9836726b0d5b91af8ef204c134 /lib/libppmcmap.c
parent3821270a4899d4d9915bcc9f105b65b849467a3f (diff)
downloadnetpbm-mirror-89973760e357aaf87b834f93e133ffb76b157d4b.tar.gz
netpbm-mirror-89973760e357aaf87b834f93e133ffb76b157d4b.tar.xz
netpbm-mirror-89973760e357aaf87b834f93e133ffb76b157d4b.zip
Add pm_errormsg(), pm_setusererrormsg(), pm_setusermessage(), release memory before longjmping
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@30 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libppmcmap.c')
-rw-r--r--lib/libppmcmap.c313
1 files changed, 229 insertions, 84 deletions
diff --git a/lib/libppmcmap.c b/lib/libppmcmap.c
index a9efccbc..c1243cb6 100644
--- a/lib/libppmcmap.c
+++ b/lib/libppmcmap.c
@@ -12,9 +12,11 @@
 ** implied warranty.
 */
 
-#include "ppm.h"
-#include "libppm.h"
+#include "pm_c_util.h"
+#include "nstring.h"
 #include "mallocvar.h"
+#include "libppm.h"
+#include "ppm.h"
 #include "ppmcmap.h"
 
 #define HASH_SIZE 20023
@@ -110,94 +112,124 @@ ppm_addtocolorhist( colorhist_vector chv,
 
 
 
-colorhash_table
-ppm_alloccolorhash(void)  {
+static colorhash_table
+alloccolorhash(void)  {
     colorhash_table cht;
     int i;
 
     MALLOCARRAY(cht, HASH_SIZE);
+    if (cht) {
+        for (i = 0; i < HASH_SIZE; ++i)
+            cht[i] = NULL;
+    }
+    return cht;
+}
+
+
+
+colorhash_table
+ppm_alloccolorhash(void)  {
+    colorhash_table cht;
+
+    cht = alloccolorhash();
+
     if (cht == NULL)
         pm_error( "out of memory allocating hash table" );
 
-    for (i = 0; i < HASH_SIZE; ++i)
-        cht[i] = NULL;
-
     return cht;
 }
 
 
 
-static colorhash_table
-computecolorhash(pixel ** const pixels, 
-                 const int cols, const int rows, 
-                 const int maxcolors, int * const colorsP,
-                 FILE * const ifp, pixval const maxval, int const format) {
-/*----------------------------------------------------------------------------
-   Compute a color histogram from an image.  The input is one of two types:
+static void
+readppmrow(FILE *        const fileP, 
+           pixel *       const pixelrow, 
+           int           const cols, 
+           pixval        const maxval, 
+           int           const format,
+           const char ** const errorP) {
 
-   1) a two-dimensional array of pixels 'pixels';  In this case, 'pixels'
-      is non-NULL and 'ifp' is NULL.
+    jmp_buf jmpbuf;
+    jmp_buf * origJmpbufP;
+    
+    if (setjmp(jmpbuf) != 0) {
+        pm_setjmpbuf(origJmpbufP);
+        asprintfN(errorP, "Failed to read row of image.");
+    } else {
+        pm_setjmpbufsave(&jmpbuf, &origJmpbufP);
 
-   2) an open file, positioned to the image data.  In this case,
-      'pixels' is NULL and 'ifp' is non-NULL.  ifp is the stream
-      descriptor for the input file, and 'maxval' and 'format' are
-      parameters of the image data in it.
-      
-      We return with the file still open and its position undefined.  
+        ppm_readppmrow(fileP, pixelrow, cols, maxval, format);
 
-   In either case, the image is 'cols' by 'rows'.
+        *errorP = NULL; /* Would have longjmped if anything went wrong */
+                
+        pm_setjmpbuf(origJmpbufP);
+    }
+}
 
-   Return the number of colors found as *colorsP.
 
-   However, if 'maxcolors' is nonzero and the number of colors is
-   greater than 'maxcolors', return a null return value and *colorsP
-   undefined.
+
+static void
+buildHashTable(FILE *          const ifP,
+               pixel **        const pixels,
+               unsigned int    const cols,
+               unsigned int    const rows,
+               pixval          const maxval,
+               int             const format,
+               unsigned int    const maxcolors,
+               colorhash_table const cht,
+               pixel *         const rowbuffer,
+               int *           const nColorsP,
+               bool *          const tooManyColorsP,
+               const char **   const errorP) {
+/*----------------------------------------------------------------------------
+  Look at all the colors in the file *ifP or array pixels[][] and add
+  them to the hash table 'cht'.
+
+  Even if we fail, we may add some colors to 'cht'.
+
+  As soon as we've seen more that 'maxcolors' colors, we quit.  In that
+  case, only, we return *tooManyColorsP == true.  That is not a failure.
+  'maxcolors' == 0 means infinity.
 -----------------------------------------------------------------------------*/
-    colorhash_table cht;
-    int row;
-    pixel * rowbuffer;  /* malloc'ed */
-        /* Buffer for a row read from the input file; undefined (but still
-           allocated) if input is not from a file.
-        */
-    
-    cht = ppm_alloccolorhash( );
-    *colorsP = 0;   /* initial value */
+    unsigned int row;
+    unsigned int nColors;
 
-    rowbuffer = ppm_allocrow(cols);
+    nColors = 0;   /* initial value */
+    *tooManyColorsP = FALSE; /* initial value */
+    *errorP = NULL;  /* initial value */
 
     /* Go through the entire image, building a hash table of colors. */
-    for (row = 0; row < rows; ++row) {
-        int col;
+    for (row = 0; row < rows && !*tooManyColorsP && !*errorP; ++row) {
+        unsigned int col;
         pixel * pixelrow;  /* The row of pixels we are processing */
 
-        if (ifp) {
-            ppm_readppmrow(ifp, rowbuffer, cols, maxval, format);
+        if (ifP) {
+            readppmrow(ifP, rowbuffer, cols, maxval, format, errorP);
             pixelrow = rowbuffer;
         } else 
             pixelrow = pixels[row];
 
-        for (col = 0; col < cols; ++col) {
+        for (col = 0; col < cols && !*tooManyColorsP && !*errorP; ++col) {
             const pixel apixel = pixelrow[col];
             const int hash = ppm_hashpixel(apixel);
             colorhist_list chl; 
 
             for (chl = cht[hash]; 
-                 chl != (colorhist_list) 0 && 
-                     !PPM_EQUAL(chl->ch.color, apixel);
+                 chl && !PPM_EQUAL(chl->ch.color, apixel);
                  chl = chl->next);
 
             if (chl)
-                chl->ch.value++;
+                ++chl->ch.value;
             else {
                 /* It's not in the hash yet, so add it (if allowed) */
-                ++(*colorsP);
-                if (maxcolors > 0 && *colorsP > maxcolors) {
-                    ppm_freecolorhash(cht);
-                    return NULL;
-                } else {
+                ++nColors;
+                if (maxcolors > 0 && nColors > maxcolors)
+                    *tooManyColorsP = TRUE;
+                else {
                     MALLOCVAR(chl);
                     if (chl == NULL)
-                        pm_error("out of memory computing hash table");
+                        asprintfN(errorP,
+                                  "out of memory computing hash table");
                     chl->ch.color = apixel;
                     chl->ch.value = 1;
                     chl->next = cht[hash];
@@ -206,31 +238,124 @@ computecolorhash(pixel ** const pixels,
             }
         }
     }
-    ppm_freerow(rowbuffer);
-    return cht;
+    *nColorsP = nColors;
+}
+
+
+
+static void
+computecolorhash(pixel **          const pixels, 
+                 unsigned int      const cols,
+                 unsigned int      const rows, 
+                 unsigned int      const maxcolors,
+                 int *             const nColorsP,
+                 FILE *            const ifP,
+                 pixval            const maxval,
+                 int               const format,
+                 colorhash_table * const chtP,
+                 const char **     const errorP) {
+/*----------------------------------------------------------------------------
+   Compute a color histogram from an image.  The input is one of two types:
+
+   1) a two-dimensional array of pixels 'pixels';  In this case, 'pixels'
+      is non-NULL and 'ifP' is NULL.
+
+   2) an open file, positioned to the image data.  In this case,
+      'pixels' is NULL and 'ifP' is non-NULL.  ifP is the stream
+      descriptor for the input file, and 'maxval' and 'format' are
+      parameters of the image data in it.
+      
+      We return with the file still open and its position undefined.  
+
+   In either case, the image is 'cols' by 'rows'.
+
+   Return the number of colors found as *colorsP.
+
+   However, if 'maxcolors' is nonzero and the number of colors is
+   greater than 'maxcolors', return a null return value and *colorsP
+   undefined.
+-----------------------------------------------------------------------------*/
+    pixel * rowbuffer;  /* malloc'ed */
+        /* Buffer for a row read from the input file; undefined (but still
+           allocated) if input is not from a file.
+        */
+
+    MALLOCARRAY(rowbuffer, cols);
+        
+    if (rowbuffer == NULL)
+        asprintfN(errorP, "Unable to allocate %u-column row buffer.", cols);
+    else {
+        colorhash_table cht;
+        bool tooManyColors;
+
+        cht = alloccolorhash();
+
+        if (cht == NULL)
+            asprintfN(errorP, "Unable to allocate color hash.");
+        else {
+            buildHashTable(ifP, pixels, cols, rows, maxval, format, maxcolors,
+                           cht, rowbuffer,
+                           nColorsP, &tooManyColors, errorP);
+                
+            if (tooManyColors) {
+                ppm_freecolorhash(cht);
+                *chtP = NULL;
+            } else
+                *chtP = cht;
+
+            if (*errorP)
+                ppm_freecolorhash(cht);
+        }
+        free(rowbuffer);
+    }
 }
 
 
 
 colorhash_table
 ppm_computecolorhash(pixel ** const pixels, 
-                     const int cols, const int rows, 
-                     const int maxcolors, int * const colorsP) {
+                     int      const cols,
+                     int      const rows, 
+                     int      const maxcolors,
+                     int *    const colorsP) {
+
+    colorhash_table cht;
+    const char * error;
+
+    computecolorhash(pixels, cols, rows, maxcolors, colorsP, 
+                     NULL, 0, 0, &cht, &error);
 
-    return computecolorhash(pixels, cols, rows, maxcolors, colorsP, 
-                            NULL, 0, 0);
+    if (error) {
+        pm_errormsg("%s", error);
+        strfree(error);
+        pm_longjmp();
+    }
+    return cht;
 }
 
 
 
 colorhash_table
-ppm_computecolorhash2(FILE * const ifp,
-                      const int cols, const int rows, 
-                      const pixval maxval, const int format, 
-                      const int maxcolors, int * const colorsP ) {
+ppm_computecolorhash2(FILE * const ifP,
+                      int    const cols,
+                      int    const rows, 
+                      pixval const maxval,
+                      int    const format, 
+                      int    const maxcolors,
+                      int *  const colorsP ) {
+
+    colorhash_table cht;
+    const char * error;
 
-    return computecolorhash(NULL, cols, rows, maxcolors, colorsP,
-                            ifp, maxval, format);
+    computecolorhash(NULL, cols, rows, maxcolors, colorsP,
+                     ifP, maxval, format, &cht, &error);
+
+    if (error) {
+        pm_errormsg("%s", error);
+        strfree(error);
+        pm_longjmp();
+    }
+    return cht;
 }
 
 
@@ -353,30 +478,50 @@ ppm_colorhashtocolorhist(colorhash_table const cht, int const maxcolors) {
 colorhash_table
 ppm_colorhisttocolorhash(colorhist_vector const chv, 
                          int              const colors) {
+
+    colorhash_table retval;
     colorhash_table cht;
-    int i, hash;
-    pixel color;
-    colorhist_list chl;
+    const char * error;
 
-    cht = ppm_alloccolorhash( );  /* Initializes to NULLs */
-
-    for (i = 0; i < colors; ++i) {
-        color = chv[i].color;
-        hash = ppm_hashpixel(color);
-        for (chl = cht[hash]; chl != (colorhist_list) 0; chl = chl->next)
-            if (PPM_EQUAL(chl->ch.color, color))
-                pm_error(
-                    "same color found twice - %d %d %d", PPM_GETR(color),
-                    PPM_GETG(color), PPM_GETB(color) );
-        MALLOCVAR(chl);
-        if (chl == NULL)
-            pm_error("out of memory");
-        chl->ch.color = color;
-        chl->ch.value = i;
-        chl->next = cht[hash];
-        cht[hash] = chl;
+    cht = alloccolorhash( );  /* Initializes to NULLs */
+    if (cht == NULL)
+        asprintfN(&error, "Unable to allocate color hash");
+    else {
+        unsigned int i;
+
+        for (i = 0, error = NULL; i < colors && !error; ++i) {
+            pixel const color = chv[i].color;
+            int const hash = ppm_hashpixel(color);
+            
+            colorhist_list chl;
+
+            for (chl = cht[hash]; chl && !error; chl = chl->next)
+                if (PPM_EQUAL(chl->ch.color, color))
+                    asprintfN(&error, "same color found twice: (%u %u %u)",
+                              PPM_GETR(color),
+                              PPM_GETG(color),
+                              PPM_GETB(color));
+            MALLOCVAR(chl);
+            if (chl == NULL)
+                asprintfN(&error, "out of memory");
+            else {
+                chl->ch.color = color;
+                chl->ch.value = i;
+                chl->next = cht[hash];
+                cht[hash] = chl;
+            }
+        }
+        if (error)
+            ppm_freecolorhash(cht);
     }
-    return cht;
+    if (error) {
+        pm_errormsg("%s", error);
+        strfree(error);
+        pm_longjmp();
+    } else
+        retval = cht;
+
+    return retval;
 }