From 89973760e357aaf87b834f93e133ffb76b157d4b Mon Sep 17 00:00:00 2001 From: giraffedata Date: Tue, 29 Aug 2006 16:19:20 +0000 Subject: 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 --- lib/libppmcmap.c | 313 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 229 insertions(+), 84 deletions(-) (limited to 'lib/libppmcmap.c') 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; } -- cgit 1.4.1