diff --git a/analyzer/pgmtexture.c b/analyzer/pgmtexture.c index 5883327..eb8cf70 100644 --- a/analyzer/pgmtexture.c +++ b/analyzer/pgmtexture.c @@ -98,6 +98,8 @@ vector(unsigned int const nl, assert(nh >= nl); + overflow_add(nh - nl, 1); + MALLOCARRAY(v, (unsigned) (nh - nl + 1)); if (v == NULL) @@ -129,6 +131,7 @@ matrix (unsigned int const nrl, assert(nrh >= nrl); /* allocate pointers to rows */ + overflow_add(nrh - nrl, 1); MALLOCARRAY(m, (unsigned) (nrh - nrl + 1)); if (m == NULL) pm_error("Unable to allocate memory for a matrix."); @@ -137,6 +140,7 @@ matrix (unsigned int const nrl, assert (nch >= ncl); + overflow_add(nch - ncl, 1); /* allocate rows and set pointers to them */ for (i = nrl; i <= nrh; ++i) { MALLOCARRAY(m[i], (unsigned) (nch - ncl + 1)); diff --git a/converter/other/gemtopnm.c b/converter/other/gemtopnm.c index d862213..5f1a51a 100644 --- a/converter/other/gemtopnm.c +++ b/converter/other/gemtopnm.c @@ -36,7 +36,7 @@ * read 4-plane color IMG files. Therefore changed from PBM to PPM. * Bryan changed it further to use the PNM facilities so it outputs * both PBM and PPM in the Netpbm tradition. Name changed from - * gemtopbm to gemtopnm. + * gemtopbm to gemtopnm. */ #include @@ -50,106 +50,107 @@ char pattern[8]; static void getinit ARGS ((FILE *file, int *colsP, int *rowsP, int *padrightP, - int *patlenP, int *planesP)); + int *patlenP, int *planesP)); int main(argc, argv) - int argc; - char *argv[]; + int argc; + char *argv[]; { - int debug = 0; - FILE *f; + int debug = 0; + FILE *f; int row; - int rows, cols, padright, patlen, planes; + int rows, cols, padright, patlen, planes; /* attributes of input image */ int type; /* The format type (PBM/PPM) of the output image */ - bit *bitrow[4]; + bit *bitrow[4]; /* One row of input, one or four planes. (If one, only [0] is defined)*/ xel * xelrow; /* One row of output */ - const char * const usage = "[-debug] [gem IMG file]"; - int argn; + const char * const usage = "[-debug] [gem IMG file]"; + int argn; /* Process multiple planes by maintaining a separate row of bits for each - * plane. In a single-plane image, all we have to do is write out the + * plane. In a single-plane image, all we have to do is write out the * first plane; in a multiple-plane image, we combine them just before writing * out the row. */ - pnm_init( &argc, argv ); - + pnm_init( &argc, argv ); + argn = 1; - while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') - { - if (pm_keymatch(argv[1], "-debug", 2)) - debug = 1; - else - pm_usage (usage); - ++argn; - } + while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') + { + if (pm_keymatch(argv[1], "-debug", 2)) + debug = 1; + else + pm_usage (usage); + ++argn; + } - if (argc == argn) - f = stdin; - else { - f = pm_openr (argv[argn]); - ++argn; - } + if (argc == argn) + f = stdin; + else { + f = pm_openr (argv[argn]); + ++argn; + } - if (argn != argc) - pm_usage (usage); + if (argn != argc) + pm_usage (usage); - getinit (f, &cols, &rows, &padright, &patlen, &planes); + getinit (f, &cols, &rows, &padright, &patlen, &planes); - if (planes == 1) + if (planes == 1) type = PBM_TYPE; - else + else type = PPM_TYPE; - pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 ); + pnm_writepnminit( stdout, cols, rows, MAXVAL, type, 0 ); - { + overflow_add(cols, padright); + { /* allocate input row data structure */ int plane; - for (plane = 0; plane < planes; plane++) + for (plane = 0; plane < planes; plane++) bitrow[plane] = malloc (cols + padright); } xelrow = pnm_allocrow(cols+padright); /* Output row */ - for (row = 0; row < rows; ) { + for (row = 0; row < rows; ) { int linerep; int plane; - linerep = 1; - for (plane = 0; plane < planes; plane++) { + linerep = 1; + for (plane = 0; plane < planes; plane++) { int col; - col = 0; - while (col < cols) { + col = 0; + while (col < cols) { int c; - switch (c = getc(f)) { - case 0x80: /* Bit String */ + switch (c = getc(f)) { + case 0x80: /* Bit String */ { int j; - c = getc(f); /* Byte count */ - if (debug) + c = getc(f); /* Byte count */ + if (debug) pm_message("bit string of %d bytes", c); - - if (col + c * 8 > cols + padright) - pm_error ("bad byte count"); - for (j = 0; j < c; ++j) { + + if (col + c * 8 > cols + padright) + pm_error ("bad byte count"); + for (j = 0; j < c; ++j) { int cc, k; - cc = getc(f); - for (k = 0x80; k; k >>= 1) { - bitrow[plane][col] = (k & cc) ? 0 : 1; - ++col; - } - } + cc = getc(f); + for (k = 0x80; k; k >>= 1) { + bitrow[plane][col] = (k & cc) ? 0 : 1; + ++col; + } + } } break; - case 0: /* Pattern run */ + case 0: /* Pattern run */ { int j, l; - c = getc(f); /* Repeat count */ - if (debug) - pm_message("pattern run of %d repetitions", c); + c = getc(f); /* Repeat count */ + if (debug) + pm_message("pattern run of %d repetitions", c); /* line repeat */ if (c == 0) { c = getc(f); @@ -158,25 +159,25 @@ main(argc, argv) linerep = getc(f); break; } - fread (pattern, 1, patlen, f); - if (col + c * patlen * 8 > cols + padright) - pm_error ("bad pattern repeat count"); - for (j = 0; j < c; ++j) - for (l = 0; l < patlen; ++l) { + fread (pattern, 1, patlen, f); + if (col + c * patlen * 8 > cols + padright) + pm_error ("bad pattern repeat count"); + for (j = 0; j < c; ++j) + for (l = 0; l < patlen; ++l) { int k; - for (k = 0x80; k; k >>= 1) { - bitrow[plane][col] = (k & pattern[l]) ? 0 : 1; - ++col; - } + for (k = 0x80; k; k >>= 1) { + bitrow[plane][col] = (k & pattern[l]) ? 0 : 1; + ++col; + } } } break; - default: /* Solid run */ + default: /* Solid run */ { int l, j; - if (debug) - pm_message("solid run of %d bytes %s", c & 0x7f, + if (debug) + pm_message("solid run of %d bytes %s", c & 0x7f, c & 0x80 ? "on" : "off" ); /* each byte had eight bits DSB */ l = (c & 0x80) ? 0: 1; @@ -185,23 +186,23 @@ main(argc, argv) pm_error ("bad solid run repeat count"); for (j = 0; j < c; ++j) { bitrow[plane][col] = l; - ++col; + ++col; } } - break; + break; - case EOF: /* End of file */ - pm_error( "end of file reached" ); + case EOF: /* End of file */ + pm_error( "end of file reached" ); - } - } + } + } if ( debug ) pm_message( "EOL plane %d row %d", plane, row ); if (col != cols + padright) pm_error( "EOL beyond edge" ); - } + } - if (planes == 4) { + if (planes == 4) { /* Construct a pixel from the 4 planes of bits for this row */ int col; for (col = 0; col < cols; col++) { @@ -212,21 +213,21 @@ main(argc, argv) const int b_bit = !bitrow[2][col]; i = bitrow[3][col]; - /* Deal with weird GEM palette - white/black/gray are - encoded oddly + /* Deal with weird GEM palette - white/black/gray are + encoded oddly */ - if (r_bit == g_bit && g_bit == b_bit) { + if (r_bit == g_bit && g_bit == b_bit) { /* It's black, white, or gray */ - if (r_bit && i) r = LIGHT; - else if (r_bit) r = BLACK; - else if (i) r = MAXVAL; - else r = DARK; - g = b = r; - } else { + if (r_bit && i) r = LIGHT; + else if (r_bit) r = BLACK; + else if (i) r = MAXVAL; + else r = DARK; + g = b = r; + } else { /* It's one of the twelve colored colors */ if (!i) { /* Low intensity */ - r = r_bit * LIGHT; + r = r_bit * LIGHT; g = g_bit * LIGHT; b = b_bit * LIGHT; } else { @@ -237,21 +238,21 @@ main(argc, argv) } } PPM_ASSIGN(xelrow[col], r, g, b); - } - } else { + } + } else { int col; - for (col = 0; col < cols; col++) + for (col = 0; col < cols; col++) PNM_ASSIGN1(xelrow[col], bitrow[0][col]); } - while (linerep--) { - pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 ); - ++row; - } - } + while (linerep--) { + pnm_writepnmrow( stdout, xelrow, cols, MAXVAL, type, 0 ); + ++row; + } + } pnm_freerow(xelrow); - pm_close( f ); - pm_close( stdout ); - exit(0); + pm_close( f ); + pm_close( stdout ); + exit(0); } @@ -303,5 +304,3 @@ getinit (file, colsP, rowsP, padrightP, patlenP, planesP) } } - - diff --git a/converter/other/jpegtopnm.c b/converter/other/jpegtopnm.c index 98552c0..311298c 100644 --- a/converter/other/jpegtopnm.c +++ b/converter/other/jpegtopnm.c @@ -862,6 +862,8 @@ convertImage(FILE * const ofP, /* Calculate output image dimensions so we can allocate space */ jpeg_calc_output_dimensions(cinfoP); + overflow2(cinfoP->output_width, cinfoP->output_components); + /* Start decompressor */ jpeg_start_decompress(cinfoP); diff --git a/converter/other/pbmtopgm.c b/converter/other/pbmtopgm.c index 69b20fb..382a487 100644 --- a/converter/other/pbmtopgm.c +++ b/converter/other/pbmtopgm.c @@ -47,6 +47,7 @@ main(int argc, char *argv[]) { "than the image height (%u rows)", height, rows); outrow = pgm_allocrow(cols) ; + overflow2(width, height); maxval = MIN(PGM_OVERALLMAXVAL, width*height); pgm_writepgminit(stdout, cols, rows, maxval, 0) ; diff --git a/converter/other/pnmtoddif.c b/converter/other/pnmtoddif.c index ac02e42..a2f045b 100644 --- a/converter/other/pnmtoddif.c +++ b/converter/other/pnmtoddif.c @@ -629,6 +629,7 @@ main(int argc, char *argv[]) { switch (PNM_FORMAT_TYPE(format)) { case PBM_TYPE: ip.bits_per_pixel = 1; + overflow_add(cols, 7); ip.bytes_per_line = (cols + 7) / 8; ip.spectral = 2; ip.components = 1; @@ -644,6 +645,7 @@ main(int argc, char *argv[]) { ip.polarity = 2; break; case PPM_TYPE: + overflow2(cols, 3); ip.bytes_per_line = 3 * cols; ip.bits_per_pixel = 24; ip.spectral = 5; diff --git a/converter/other/pnmtojpeg.c b/converter/other/pnmtojpeg.c index 4482624..757d08d 100644 --- a/converter/other/pnmtojpeg.c +++ b/converter/other/pnmtojpeg.c @@ -606,7 +606,11 @@ read_scan_script(j_compress_ptr const cinfo, want JPOOL_PERMANENT. */ const unsigned int scan_info_size = nscans * sizeof(jpeg_scan_info); - jpeg_scan_info * const scan_info = + const jpeg_scan_info * scan_info; + + overflow2(nscans, sizeof(jpeg_scan_info)); + + scan_info = (jpeg_scan_info *) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, scan_info_size); @@ -938,6 +942,8 @@ compute_rescaling_array(JSAMPLE ** const rescale_p, const pixval maxval, const long half_maxval = maxval / 2; long val; + overflow_add(maxval, 1); + overflow2(maxval+1, sizeof(JSAMPLE)); *rescale_p = (JSAMPLE *) (cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_IMAGE, (size_t) (((long) maxval + 1L) * @@ -1016,6 +1022,7 @@ convert_scanlines(struct jpeg_compress_struct * const cinfo_p, */ /* Allocate the libpnm output and compressor input buffers */ + overflow2(cinfo_p->image_width, cinfo_p->input_components); buffer = (*cinfo_p->mem->alloc_sarray) ((j_common_ptr) cinfo_p, JPOOL_IMAGE, (unsigned int) cinfo_p->image_width * cinfo_p->input_components, diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index de0dfd8..09c28d5 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -294,17 +294,21 @@ parseCommandLine(int argc, const char ** argv, validateCompDimension(width, 72, "-width value"); validateCompDimension(height, 72, "-height value"); + overflow2(width, 72); cmdlineP->width = width * 72; + overflow2(height, 72); cmdlineP->height = height * 72; if (imagewidthSpec) { validateCompDimension(imagewidth, 72, "-imagewidth value"); + overflow2(imagewidth, 72); cmdlineP->imagewidth = imagewidth * 72; } else cmdlineP->imagewidth = 0; if (imageheightSpec) { - validateCompDimension(imagewidth, 72, "-imageheight value"); + validateCompDimension(imageheight, 72, "-imageheight value"); + overflow2(imageheight, 72); cmdlineP->imageheight = imageheight * 72; } else diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c index 97f271d..72b63d3 100644 --- a/converter/other/rletopnm.c +++ b/converter/other/rletopnm.c @@ -19,6 +19,8 @@ * If you modify this software, you should include a notice giving the * name of the person performing the modification, the date of modification, * and the reason for such modification. + * + * 2002-12-19: Fix maths wrapping bugs. Alan Cox */ /* * rletopnm - A conversion program to convert from Utah's "rle" image format diff --git a/converter/other/sirtopnm.c b/converter/other/sirtopnm.c index fafcc91..9fe49d0 100644 --- a/converter/other/sirtopnm.c +++ b/converter/other/sirtopnm.c @@ -69,6 +69,7 @@ char* argv[]; } break; case PPM_TYPE: + overflow3(cols, rows, 3); picsize = cols * rows * 3; planesize = cols * rows; if ( !( sirarray = (unsigned char*) malloc( picsize ) ) ) diff --git a/converter/other/tifftopnm.c b/converter/other/tifftopnm.c index c1e7af8..ef9253b 100644 --- a/converter/other/tifftopnm.c +++ b/converter/other/tifftopnm.c @@ -1372,7 +1372,9 @@ convertRasterByRows(pnmOut * const pnmOutP, if (scanbuf == NULL) pm_error("can't allocate memory for scanline buffer"); - MALLOCARRAY(samplebuf, cols * spp); + /* samplebuf is unsigned int * !!! */ + samplebuf = (unsigned int *) malloc3(cols , sizeof(unsigned int) , spp); + if (samplebuf == NULL) pm_error("can't allocate memory for row buffer"); diff --git a/converter/other/xwdtopnm.c b/converter/other/xwdtopnm.c index df3c737..6c19ade 100644 --- a/converter/other/xwdtopnm.c +++ b/converter/other/xwdtopnm.c @@ -210,6 +210,10 @@ processX10Header(X10WDFileHeader * const h10P, *colorsP = pnm_allocrow(2); PNM_ASSIGN1((*colorsP)[0], 0); PNM_ASSIGN1((*colorsP)[1], *maxvalP); + overflow_add(h10P->pixmap_width, 15); + if(h10P->pixmap_width < 0) + pm_error("assert: negative width"); + overflow2((((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width), 8); *padrightP = (((h10P->pixmap_width + 15) / 16) * 16 - h10P->pixmap_width) * 8; *bits_per_itemP = 16; @@ -635,6 +639,7 @@ processX11Header(X11WDFileHeader * const h11P, *colsP = h11FixedP->pixmap_width; *rowsP = h11FixedP->pixmap_height; + overflow2(h11FixedP->bytes_per_line, 8); *padrightP = h11FixedP->bytes_per_line * 8 - h11FixedP->pixmap_width * h11FixedP->bits_per_pixel; diff --git a/converter/pbm/mdatopbm.c b/converter/pbm/mdatopbm.c index d8e0657..12c7468 100644 --- a/converter/pbm/mdatopbm.c +++ b/converter/pbm/mdatopbm.c @@ -245,10 +245,13 @@ main(int argc, char **argv) { pm_readlittleshort(infile, &yy); nInCols = yy; } + overflow2(nOutCols, 8); nOutCols = 8 * nInCols; nOutRows = nInRows; - if (bScale) + if (bScale) { + overflow2(nOutRows, 2); nOutRows *= 2; + } data = pbm_allocarray(nOutCols, nOutRows); diff --git a/converter/pbm/mgrtopbm.c b/converter/pbm/mgrtopbm.c index 9f7004a..60e8477 100644 --- a/converter/pbm/mgrtopbm.c +++ b/converter/pbm/mgrtopbm.c @@ -65,6 +65,8 @@ readMgrHeader(FILE * const ifP, if (head.h_high < ' ' || head.l_high < ' ') pm_error("Invalid width field in MGR header"); + overflow_add(*colsP, pad); + *colsP = (((int)head.h_wide - ' ') << 6) + ((int)head.l_wide - ' '); *rowsP = (((int)head.h_high - ' ') << 6) + ((int) head.l_high - ' '); *padrightP = ( ( *colsP + pad - 1 ) / pad ) * pad - *colsP; diff --git a/converter/pbm/pbmto4425.c b/converter/pbm/pbmto4425.c index 1d97ac6..c4c8cbb 100644 --- a/converter/pbm/pbmto4425.c +++ b/converter/pbm/pbmto4425.c @@ -2,6 +2,7 @@ #include "nstring.h" #include "pbm.h" +#include static char bit_table[2][3] = { {1, 4, 0x10}, @@ -160,7 +161,7 @@ main(int argc, char * argv[]) { xres = vmap_width * 2; yres = vmap_height * 3; - vmap = malloc(vmap_width * vmap_height * sizeof(char)); + vmap = malloc3(vmap_width, vmap_height, sizeof(char)); if(vmap == NULL) { pm_error( "Cannot allocate memory" ); diff --git a/converter/pbm/pbmtogem.c b/converter/pbm/pbmtogem.c index 9eab041..13b0257 100644 --- a/converter/pbm/pbmtogem.c +++ b/converter/pbm/pbmtogem.c @@ -79,6 +79,7 @@ putinit (int const rows, int const cols) bitsperitem = 0; bitshift = 7; outcol = 0; + overflow_add(cols, 7); outmax = (cols + 7) / 8; outrow = (unsigned char *) pm_allocrow (outmax, sizeof (unsigned char)); lastrow = (unsigned char *) pm_allocrow (outmax, sizeof (unsigned char)); diff --git a/converter/pbm/pbmtogo.c b/converter/pbm/pbmtogo.c index 23b2ee9..d2ee91f 100644 --- a/converter/pbm/pbmtogo.c +++ b/converter/pbm/pbmtogo.c @@ -158,6 +158,7 @@ main(int argc, bitrow = pbm_allocrow(cols); /* Round cols up to the nearest multiple of 8. */ + overflow_add(cols, 7); rucols = ( cols + 7 ) / 8; bytesperrow = rucols; /* GraphOn uses bytes */ rucols = rucols * 8; diff --git a/converter/pbm/pbmtolj.c b/converter/pbm/pbmtolj.c index 3cd7670..0b51932 100644 --- a/converter/pbm/pbmtolj.c +++ b/converter/pbm/pbmtolj.c @@ -120,7 +120,11 @@ parseCommandLine(int argc, char ** argv, static void allocateBuffers(unsigned int const cols) { + overflow_add(cols, 8); rowBufferSize = (cols + 7) / 8; + overflow_add(rowBufferSize, 128); + overflow_add(rowBufferSize, rowBufferSize+128); + overflow_add(rowBufferSize+10, rowBufferSize/8); packBufferSize = rowBufferSize + (rowBufferSize + 127) / 128 + 1; deltaBufferSize = rowBufferSize + rowBufferSize / 8 + 10; diff --git a/converter/pbm/pbmtomda.c b/converter/pbm/pbmtomda.c index 3ad5149..9efe5cf 100644 --- a/converter/pbm/pbmtomda.c +++ b/converter/pbm/pbmtomda.c @@ -179,6 +179,7 @@ int main(int argc, char **argv) nOutRowsUnrounded = bScale ? nInRows/2 : nInRows; + overflow_add(nOutRowsUnrounded, 3); nOutRows = ((nOutRowsUnrounded + 3) / 4) * 4; /* MDA wants rows a multiple of 4 */ nOutCols = nInCols / 8; diff --git a/converter/pbm/pbmtoppa/pbm.c b/converter/pbm/pbmtoppa/pbm.c index ae36e0d..1c8d236 100644 --- a/converter/pbm/pbmtoppa/pbm.c +++ b/converter/pbm/pbmtoppa/pbm.c @@ -11,185 +11,128 @@ #include #include #include -#include -#include "pm.h" -#include "nstring.h" #include "ppapbm.h" -int -make_pbm_stat(pbm_stat * const pbmStatP, - FILE * const ifP) { - - char line[1024]; - char * rc; - int retval; - - pbmStatP->fptr = ifP; - pbmStatP->version = none; - pbmStatP->current_line = 0; - pbmStatP->unread = 0; - - rc = fgets(line, 1024, ifP); - if (rc == NULL) - retval = 0; - else { - line[strlen(line)-1] = 0; - - if (streq(line,"P1")) - pbmStatP->version=P1; - if (streq(line,"P4")) - pbmStatP->version=P4; - - if (pbmStatP->version == none) { - pm_message("unknown PBM magic '%s'", line); - retval = 0; - } else { - do { - char * rc; - rc = fgets(line, 1024, ifP); - if (rc == NULL) - return 0; - } while (line[0] == '#'); - { - int rc; - rc = sscanf(line, "%d %d", - &pbmStatP->width, &pbmStatP->height); - if (rc != 2) - retval = 0; - else { - if (pbmStatP->width < 0) { - pm_message("Image has negative width"); - retval = 0; - } else if (pbmStatP->width > INT_MAX/2) { - pm_message("Uncomputeably large width: %d", - pbmStatP->width); - retval = 0; - } else if (pbmStatP->height < 0) { - pm_message("Image has negative height"); - retval = 0; - } else if (pbmStatP->height > INT_MAX/2) { - pm_message("Uncomputeably large height: %d", - pbmStatP->height); - retval = 0; - } else - retval = 1; - } - } - } - } - return retval; -} +int make_pbm_stat(pbm_stat* pbm,FILE* fptr) +{ + char line[1024]; + pbm->fptr=fptr; + pbm->version=none; + pbm->current_line=0; + pbm->unread = 0; + if (fgets (line, 1024, fptr) == NULL) + return 0; + line[strlen(line)-1] = 0; -static int -getbytes(FILE * const ifP, - unsigned int const width, - unsigned char * const data) { - - unsigned char mask; - unsigned char acc; - unsigned char * place; - unsigned int num; - int retval; - - if (width == 0) - retval = 0; - else { - for (mask = 0x80, acc = 0, num = 0, place = data; num < width; ) { - switch (getc(ifP)) { - case EOF: - return 0; - case '1': - acc |= mask; - /* fall through */ - case '0': - mask >>= 1; - ++num; - if (mask == 0x00) { /* if (num % 8 == 0) */ - *place++ = acc; - acc = 0; - mask = 0x80; - } - } - } - if (width % 8 != 0) - *place = acc; - - retval = 1; - } - return retval; -} + if(!strcmp(line,"P1")) pbm->version=P1; + if(!strcmp(line,"P4")) pbm->version=P4; + if(pbm->version == none) + { + fprintf(stderr,"pbm_readheader(): unknown PBM magic '%s'\n",line); + return 0; + } + do + if (fgets (line, 1024, fptr) == NULL) + return 0; + while (line[0] == '#'); + if (2 != sscanf (line, "%d %d", &pbm->width, &pbm->height)) + return 0; -int -pbm_readline(pbm_stat * const pbmStatP, - unsigned char * const data) { -/*---------------------------------------------------------------------------- - Read a single line into data which must be at least (pbmStatP->width+7)/8 - bytes of storage. ------------------------------------------------------------------------------*/ - int retval; - - if (pbmStatP->current_line >= pbmStatP->height) - retval = 0; - else { - if (pbmStatP->unread) { - memcpy(data, pbmStatP->revdata, (pbmStatP->width+7)/8); - ++pbmStatP->current_line; - pbmStatP->unread = 0; - free(pbmStatP->revdata); - pbmStatP->revdata = NULL; - retval = 1; - } else { - switch (pbmStatP->version) { - case P1: - if (getbytes(pbmStatP->fptr, pbmStatP->width, data)) { - pbmStatP->current_line++; - retval = 1; - } else - retval = 0; - break; - case P4: { - int tmp, tmp2; - tmp = (pbmStatP->width+7)/8; - tmp2 = fread(data,1,tmp,pbmStatP->fptr); - if (tmp2 == tmp) { - ++pbmStatP->current_line; - retval = 1; - } else { - pm_message("error reading line data (%d)", tmp2); - retval = 0; - } - } break; - - default: - pm_message("unknown PBM version"); - retval = 0; - } - } - } - return retval; + return 1; } +static int getbytes(FILE *fptr,int width,unsigned char* data) +{ + unsigned char mask,acc,*place; + int num; + + if(!width) return 0; + for(mask=0x80, acc=0, num=0, place=data; num>=1; + num++; + if(!mask) /* if(num%8 == 0) */ + { + *place++ = acc; + acc=0; + mask=0x80; + } + } + } + if(width%8) + *place=acc; + return 1; +} +/* Reads a single line into data which must be at least (pbm->width+7)/8 + bytes of storage */ +int pbm_readline(pbm_stat* pbm,unsigned char* data) +{ + int tmp,tmp2; + + if(pbm->current_line >= pbm->height) return 0; + + if (pbm->unread) + { + memcpy (data, pbm->revdata, (pbm->width+7)/8); + pbm->current_line++; + pbm->unread = 0; + free (pbm->revdata); + pbm->revdata = NULL; + return 1; + } -void -pbm_unreadline(pbm_stat * const pbmStatP, - void * const data) { -/*---------------------------------------------------------------------------- - Push a line back into the buffer; we read too much! ------------------------------------------------------------------------------*/ - /* can store only one line in the unread buffer */ - - if (!pbmStatP->unread) { - pbmStatP->unread = 1; - pbmStatP->revdata = malloc ((pbmStatP->width+7)/8); - memcpy(pbmStatP->revdata, data, (pbmStatP->width+7)/8); - --pbmStatP->current_line; + switch(pbm->version) + { + case P1: + if(getbytes(pbm->fptr,pbm->width,data)) + { + pbm->current_line++; + return 1; } -} + return 0; + + case P4: + overflow_add(pbm->width, 7); + tmp=(pbm->width+7)/8; + tmp2=fread(data,1,tmp,pbm->fptr); + if(tmp2 == tmp) + { + pbm->current_line++; + return 1; + } + fprintf(stderr,"pbm_readline(): error reading line data (%d)\n",tmp2); + return 0; + default: + fprintf(stderr,"pbm_readline(): unknown PBM version\n"); + return 0; + } +} +/* push a line back into the buffer; we read too much! */ +void pbm_unreadline (pbm_stat *pbm, void *data) +{ + /* can only store one line in the unread buffer */ + if (pbm->unread) + return; + + pbm->unread = 1; + overflow_add(pbm->width, 7); + pbm->revdata = malloc ((pbm->width+7)/8); + memcpy (pbm->revdata, data, (pbm->width+7)/8); + pbm->current_line--; +} diff --git a/converter/pbm/pbmtoppa/pbmtoppa.c b/converter/pbm/pbmtoppa/pbmtoppa.c index ff4a599..aa510ec 100644 --- a/converter/pbm/pbmtoppa/pbmtoppa.c +++ b/converter/pbm/pbmtoppa/pbmtoppa.c @@ -453,6 +453,7 @@ main(int argc, char *argv[]) { pm_error("main(): unrecognized parameter '%s'", argv[argn]); } + overflow_add(Width, 7); Pwidth=(Width+7)/8; printer.fptr=out; diff --git a/converter/pbm/pbmtoxbm.c b/converter/pbm/pbmtoxbm.c index ecb72b3..fc0eb9c 100644 --- a/converter/pbm/pbmtoxbm.c +++ b/converter/pbm/pbmtoxbm.c @@ -352,6 +352,8 @@ convertRaster(FILE * const ifP, unsigned char * bitrow; unsigned int row; + + overflow_add(cols, padright); putinit(xbmVersion); diff --git a/converter/pbm/pktopbm.c b/converter/pbm/pktopbm.c index 712f339..b6fcb02 100644 --- a/converter/pbm/pktopbm.c +++ b/converter/pbm/pktopbm.c @@ -280,6 +280,7 @@ main(int argc, char *argv[]) { if (flagbyte == 7) { /* long form preamble */ integer packetlength = get32() ; /* character packet length */ car = get32() ; /* character number */ + overflow_add(packetlength, pktopbm_pkloc); endofpacket = packetlength + pktopbm_pkloc; /* calculate end of packet */ if ((car >= MAXPKCHAR) || !filename[car]) { diff --git a/converter/pbm/thinkjettopbm.l b/converter/pbm/thinkjettopbm.l index 5de4f2b..7f31de5 100644 --- a/converter/pbm/thinkjettopbm.l +++ b/converter/pbm/thinkjettopbm.l @@ -114,7 +114,9 @@ DIG [0-9] \033\*b{DIG}+W { int l; if (rowCount >= rowCapacity) { - rowCapacity += 100; + overflow_add(rowCapacity, 100); + rowCapacity += 100; + overflow2(rowCapacity, sizeof *rows); rows = realloc (rows, rowCapacity * sizeof *rows); if (rows == NULL) pm_error ("Out of memory."); @@ -226,6 +228,8 @@ yywrap (void) /* * Quite simple since ThinkJet bit arrangement matches PBM */ + + overflow2(maxRowLength, 8); pbm_writepbminit(stdout, maxRowLength*8, rowCount, 0); packed_bitrow = malloc(maxRowLength); diff --git a/converter/pbm/ybmtopbm.c b/converter/pbm/ybmtopbm.c index 2a42908..cf1ff03 100644 --- a/converter/pbm/ybmtopbm.c +++ b/converter/pbm/ybmtopbm.c @@ -43,6 +43,7 @@ getinit(FILE * const ifP, pm_error("EOF / read error"); *depthP = 1; + overflow_add(*colsP, 15); } diff --git a/converter/pgm/lispmtopgm.c b/converter/pgm/lispmtopgm.c index 40dd3fb..b5469f7 100644 --- a/converter/pgm/lispmtopgm.c +++ b/converter/pgm/lispmtopgm.c @@ -58,6 +58,7 @@ main( argc, argv ) pm_error( "depth (%d bits) is too large", depth); pgm_writepgminit( stdout, cols, rows, (gray) maxval, 0 ); + overflow_add(cols, 7); grayrow = pgm_allocrow( ( cols + 7 ) / 8 * 8 ); for ( row = 0; row < rows; ++row ) @@ -102,6 +103,8 @@ getinit( file, colsP, rowsP, depthP, padrightP ) if ( *depthP == 0 ) *depthP = 1; /* very old file */ + + overflow_add((int)colsP, 31); *padrightP = ( ( *colsP + 31 ) / 32 ) * 32 - *colsP; diff --git a/converter/pgm/psidtopgm.c b/converter/pgm/psidtopgm.c index 07417d1..25bb311 100644 --- a/converter/pgm/psidtopgm.c +++ b/converter/pgm/psidtopgm.c @@ -78,6 +78,7 @@ main(int argc, pm_error("bits/sample (%d) is too large.", bitspersample); pgm_writepgminit(stdout, cols, rows, maxval, 0); + overflow_add(cols, 7); grayrow = pgm_allocrow((cols + 7) / 8 * 8); for (row = 0; row < rows; ++row) { unsigned int col; diff --git a/converter/ppm/Makefile b/converter/ppm/Makefile index 003ef8d..b97349d 100644 --- a/converter/ppm/Makefile +++ b/converter/ppm/Makefile @@ -11,7 +11,7 @@ SUBDIRS = hpcdtoppm ppmtompeg PORTBINARIES = 411toppm eyuvtoppm gouldtoppm ilbmtoppm imgtoppm \ leaftoppm mtvtoppm neotoppm \ - pcxtoppm pc1toppm pi1toppm picttoppm pjtoppm \ + pcxtoppm pc1toppm pi1toppm pjtoppm \ ppmtoacad ppmtoapplevol ppmtoarbtxt ppmtoascii \ ppmtobmp ppmtoeyuv ppmtogif ppmtoicr ppmtoilbm \ ppmtoleaf ppmtolj ppmtomitsu ppmtoneo \ diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c index 92d4d6f..60853dd 100644 --- a/converter/ppm/ilbmtoppm.c +++ b/converter/ppm/ilbmtoppm.c @@ -608,6 +608,7 @@ decode_row(FILE * const ifP, rawtype *chp; cols = bmhdP->w; + overflow_add(cols, 15); bytes = RowBytes(cols); for( plane = 0; plane < nPlanes; plane++ ) { int mask; @@ -695,6 +696,23 @@ decode_mask(FILE * const ifP, Multipalette handling ****************************************************************************/ +static void * +xmalloc2(x, y) + int x; + int y; +{ + void *mem; + + overflow2(x,y); + if( x * y == 0 ) + return NULL; + + mem = malloc2(x,y); + if( mem == NULL ) + pm_error("out of memory allocating %d bytes", x * y); + return mem; +} + static void multi_adjust(ColorMap * const cmapP, @@ -1363,6 +1381,9 @@ dcol_to_ppm(FILE * const ifP, if( redmaxval != maxval || greenmaxval != maxval || bluemaxval != maxval ) pm_message("scaling colors to %d bits", pm_maxvaltobits(maxval)); + overflow_add(redmaxval, 1); + overflow_add(greenmaxval, 1); + overflow_add(bluemaxval, 1); MALLOCARRAY_NOFAIL(redtable, redmaxval +1); MALLOCARRAY_NOFAIL(greentable, greenmaxval +1); MALLOCARRAY_NOFAIL(bluetable, bluemaxval +1); @@ -1802,7 +1823,9 @@ PCHG_ConvertSmall(PCHGHeader * const pchgP, ChangeCount32 = *data++; remDataSize -= 2; + overflow_add(ChangeCount16, ChangeCount32); changes = ChangeCount16 + ChangeCount32; + overflow_add(changes, 1); for (i = 0; i < changes; ++i) { if (totalchanges >= pchgP->TotalChanges) goto fail; if (remDataSize < 2) goto fail; @@ -2067,6 +2090,9 @@ read_pchg(FILE * const ifP, cmap->mp_change[i] = NULL; if( PCHG.StartLine < 0 ) { int nch; + if(PCHG.MaxReg < PCHG.MinReg) + pm_error("assert: MinReg > MaxReg"); + overflow_add(PCHG.MaxReg-PCHG.MinReg, 2); nch = PCHG.MaxReg - PCHG.MinReg +1; MALLOCARRAY_NOFAIL(cmap->mp_init, nch + 1); for( i = 0; i < nch; i++ ) @@ -2143,6 +2169,7 @@ process_body( FILE * const ifP, if (typeid == ID_ILBM) { int isdeep; + overflow_add(bmhdP->w, 15); MALLOCARRAY_NOFAIL(ilbmrow, RowBytes(bmhdP->w)); *viewportmodesP |= fakeviewport; /* -isham/-isehb */ diff --git a/converter/ppm/ilbmtoppm.c.rej b/converter/ppm/ilbmtoppm.c.rej new file mode 100644 index 0000000..972cad0 --- /dev/null +++ b/converter/ppm/ilbmtoppm.c.rej @@ -0,0 +1,46 @@ +--- converter/ppm/ilbmtoppm.c ++++ converter/ppm/ilbmtoppm.c +@@ -694,6 +695,23 @@ decode_mask(FILE * const ifP, + Multipalette handling + ****************************************************************************/ + ++static void * ++xmalloc2(x, y) ++ int x; ++ int y; ++{ ++ void *mem; ++ ++ overflow2(x,y); ++ if( x * y == 0 ) ++ return NULL; ++ ++ mem = malloc2(x,y); ++ if( mem == NULL ) ++ pm_error("out of memory allocating %d bytes", x * y); ++ return mem; ++} ++ + + static void + multi_adjust(cmap, row, palchange) +@@ -1356,6 +1374,9 @@ dcol_to_ppm(FILE * const ifP, + if( redmaxval != maxval || greenmaxval != maxval || bluemaxval != maxval ) + pm_message("scaling colors to %d bits", pm_maxvaltobits(maxval)); + ++ overflow_add(redmaxval, 1); ++ overflow_add(greenmaxval, 1); ++ overflow_add(bluemaxval, 1); + MALLOCARRAY_NOFAIL(redtable, redmaxval +1); + MALLOCARRAY_NOFAIL(greentable, greenmaxval +1); + MALLOCARRAY_NOFAIL(bluetable, bluemaxval +1); +@@ -1785,7 +1806,9 @@ PCHG_ConvertSmall(PCHG, cmap, mask, datasize) + ChangeCount32 = *data++; + datasize -= 2; + ++ overflow_add(ChangeCount16, ChangeCount32); + changes = ChangeCount16 + ChangeCount32; ++ overflow_add(changes, 1); + for( i = 0; i < changes; i++ ) { + if( totalchanges >= PCHG->TotalChanges ) goto fail; + if( datasize < 2 ) goto fail; diff --git a/converter/ppm/imgtoppm.c b/converter/ppm/imgtoppm.c index 7078b88..eb8509e 100644 --- a/converter/ppm/imgtoppm.c +++ b/converter/ppm/imgtoppm.c @@ -84,6 +84,7 @@ main(int argc, char ** argv) { len = atoi((char*) buf ); if ( fread( buf, len, 1, ifp ) != 1 ) pm_error( "bad colormap buf" ); + overflow2(cmaplen, 3); if ( cmaplen * 3 != len ) { pm_message( @@ -105,6 +106,7 @@ main(int argc, char ** argv) { pm_error( "bad pixel data header" ); buf[8] = '\0'; len = atoi((char*) buf ); + overflow2(cols, rows); if ( len != cols * rows ) pm_message( "pixel data length (%d) does not match image size (%d)", diff --git a/converter/ppm/pcxtoppm.c b/converter/ppm/pcxtoppm.c index e252ba2..270ae3b 100644 --- a/converter/ppm/pcxtoppm.c +++ b/converter/ppm/pcxtoppm.c @@ -409,6 +409,7 @@ pcx_planes_to_pixels(pixels, bitplanes, bytesperline, planes, bitsperpixel) /* * clear the pixel buffer */ + overflow2(bytesperline, 8); npixels = (bytesperline * 8) / bitsperpixel; p = pixels; while (--npixels >= 0) @@ -470,6 +471,7 @@ pcx_16col_to_ppm(FILE * const ifP, } /* BytesPerLine should be >= BitsPerPixel * cols / 8 */ + overflow2(BytesPerLine, 8); rawcols = BytesPerLine * 8 / BitsPerPixel; if (headerCols > rawcols) { pm_message("warning - BytesPerLine = %d, " diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index b8fb864..177bc30 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -1,3 +1,4 @@ +#error "Unfixable. Don't ship me" /* * picttoppm.c -- convert a MacIntosh PICT file to PPM format. * diff --git a/converter/ppm/pjtoppm.c b/converter/ppm/pjtoppm.c index b8b94f7..62ce77e 100644 --- a/converter/ppm/pjtoppm.c +++ b/converter/ppm/pjtoppm.c @@ -11,87 +11,65 @@ */ #include "ppm.h" -#include "pm_c_util.h" #include "mallocvar.h" static char usage[] = "[paintjetfile]"; - - -static unsigned int -uintProduct(unsigned int const multiplicand, - unsigned int const multiplier) { - - if (UINT_MAX / multiplier < multiplicand) - pm_error("Airthmetic overflow"); - - return multiplicand * multiplier; -} - - - +static int egetc ARGS((FILE *fp)); static int -egetc(FILE * const ifP) { +egetc(fp) + FILE *fp; +{ int c; - - c = fgetc(ifP); - - if (c == -1) + if ((c = fgetc(fp)) == -1) pm_error("unexpected end of file"); - - return c; + return(c); } - - int -main(int argc, const char ** argv) { - +main(argc, argv) + int argc; + char *argv[]; +{ int cmd, val; char buffer[BUFSIZ]; int planes = 3, rows = -1, cols = -1; + int r = 0, c = 0, p = 0, i; unsigned char **image = NULL; int *imlen; - FILE * ifP; + FILE *fp = stdin; int mode; int argn; unsigned char bf[3]; - pixel * pixrow; - int c; - int row; - int plane; + pixel *pixrow; - pm_proginit(&argc, argv); + ppm_init(&argc, argv); argn = 1; if (argn != argc) - ifP = pm_openr(argv[argn++]); + fp = pm_openr(argv[argn++]); else - ifP = stdin; + fp = stdin; if (argn != argc) pm_usage(usage); - row = 0; /* initial value */ - plane = 0; /* initial value */ - - while ((c = fgetc(ifP)) != -1) { + while ((c = fgetc(fp)) != -1) { if (c != '\033') continue; - switch (c = egetc(ifP)) { + switch (c = egetc(fp)) { case 'E': /* reset */ break; - case '*': { - unsigned int i; - cmd = egetc(ifP); + case '*': + cmd = egetc(fp); for (i = 0; i < BUFSIZ; i++) { - if (!isdigit(c = egetc(ifP)) && c != '+' && c != '-') + if (!isdigit(c = egetc(fp)) && c != '+' && c != '-') break; buffer[i] = c; } if (i != 0) { buffer[i] = '\0'; - if (sscanf(buffer, "%d", &val) != 1) + if (sscanf(buffer, "%d", &val) != 1) pm_error("bad value `%s' at *%c%c", buffer, cmd, c); } else @@ -122,7 +100,7 @@ main(int argc, const char ** argv) { break; case 'U': /* planes */ planes = val; - if (planes != 3) + if (planes != 3) pm_error("can handle only 3 plane files"); break; case 'A': /* begin raster */ @@ -148,33 +126,40 @@ main(int argc, const char ** argv) { break; case 'V': /* send plane */ case 'W': /* send last plane */ - if (rows == -1 || row >= rows || image == NULL) { - if (rows == -1 || row >= rows) + if (rows == -1 || r >= rows || image == NULL) { + if (rows == -1 || r >= rows) { + overflow_add(rows, 100); rows += 100; + } + if (image == NULL) { - MALLOCARRAY(image, uintProduct(rows, planes)); - MALLOCARRAY(imlen, uintProduct(rows, planes)); - } else { - REALLOCARRAY(image, uintProduct(rows, planes)); - REALLOCARRAY(imlen, uintProduct(rows, planes)); + image = (unsigned char **) + malloc3(rows , planes , sizeof(unsigned char *)); + imlen = (int *) malloc3(rows , planes, sizeof(int)); } + else { + overflow2(rows,planes); + image = (unsigned char **) + realloc2(image, rows * planes, + sizeof(unsigned char *)); + imlen = (int *) realloc2(imlen, rows * planes, sizeof(int)); } } if (image == NULL || imlen == NULL) pm_error("out of memory"); - if (plane >= planes) + if (p == planes) pm_error("too many planes"); - cols = MAX(cols, val); - imlen[row * planes + plane] = val; - MALLOCARRAY(image[row * planes + plane], val); - if (image[row * planes + plane] == NULL) + cols = cols > val ? cols : val; + imlen[r * planes + p] = val; + MALLOCARRAY(image[r * planes + p], val); + if (image[r * planes + p] == NULL) pm_error("out of memory"); - if (fread(image[row * planes + plane], 1, val, ifP) != val) + if (fread(image[r * planes + p], 1, val, fp) != val) pm_error("short data"); if (c == 'V') - ++plane; + p++; else { - plane = 0; - ++row; + p = 0; + r++; } break; default: @@ -183,7 +168,7 @@ main(int argc, const char ** argv) { } break; case 'p': /* Position */ - if (plane != 0) + if (p != 0) pm_error("changed position in the middle of " "transferring planes"); switch (c) { @@ -192,15 +177,15 @@ main(int argc, const char ** argv) { break; case 'Y': if (buffer[0] == '+') - val = row + val; + val = r + val; if (buffer[0] == '-') - val = row - val; - for (; val > row; ++row) - for (plane = 0; plane < 3; ++plane) { - imlen[row * planes + plane] = 0; - image[row * planes + plane] = NULL; + val = r - val; + for (; val > r; r++) + for (p = 0; p < 3; p++) { + imlen[r * planes + p] = 0; + image[r * planes + p] = NULL; } - row = val; + r = val; break; default: pm_message("uninmplemented *%c%d%c", cmd, val, c); @@ -209,80 +194,65 @@ main(int argc, const char ** argv) { default: pm_message("uninmplemented *%c%d%c", cmd, val, c); break; - } - } /* case */ - } /* switch */ + } + } } - pm_close(ifP); - rows = row; + pm_close(fp); + rows = r; if (mode == 1) { - int const newcols = 10240; /* It could not be larger that that! */ - unsigned char * buf; - unsigned int row; - - for (row = 0, cols = 0; row < rows; ++row) { - unsigned int plane; - if (image[row * planes] == NULL) + unsigned char *buf; + int newcols = 0; + newcols = 10240; /* It could not be larger that that! */ + cols = 0; + for (r = 0; r < rows; r++) { + if (image[r * planes] == NULL) continue; - for (plane = 0; plane < planes; ++plane) { - unsigned int i; - unsigned int col; + for (p = 0; p < planes; p++) { MALLOCARRAY(buf, newcols); - if (buf == NULL) + if (buf == NULL) pm_error("out of memory"); - for (i = 0, col = 0; - col < imlen[plane + row * planes]; - col += 2) - for (cmd = image[plane + row * planes][col], - val = image[plane + row * planes][col+1]; - cmd >= 0 && i < newcols; cmd--, i++) + for (i = 0, c = 0; c < imlen[p + r * planes]; c += 2) + for (cmd = image[p + r * planes][c], + val = image[p + r * planes][c+1]; + cmd >= 0 && i < newcols; cmd--, i++) { buf[i] = val; - cols = MAX(cols, i); - free(image[plane + row * planes]); - /* - * This is less than what we have so it realloc should + overflow_add(i, 1); + } + cols = cols > i ? cols : i; + free(image[p + r * planes]); + /* + * This is less than what we have so it realloc should * not return null. Even if it does, tough! We will * lose a line, and probably die on the next line anyway */ - image[plane + row * planes] = realloc(buf, i); + image[p + r * planes] = (unsigned char *) realloc(buf, i); } } + overflow2(cols, 8); cols *= 8; } - + + ppm_writeppminit(stdout, cols, rows, (pixval) 255, 0); pixrow = ppm_allocrow(cols); - - for (row = 0; row < rows; ++row) { - if (image[row * planes] == NULL) { - unsigned int col; - for (col = 0; col < cols; ++col) - PPM_ASSIGN(pixrow[col], 0, 0, 0); + for (r = 0; r < rows; r++) { + if (image[r * planes] == NULL) { + for (c = 0; c < cols; c++) + PPM_ASSIGN(pixrow[c], 0, 0, 0); continue; } - { - unsigned int col; - unsigned int cmd; - for (cmd = 0, col = 0; col < cols; col += 8, ++cmd) { - unsigned int i; - for (i = 0; i < 8 && col + i < cols; ++i) { - unsigned int plane; - for (plane = 0; plane < planes; ++plane) - if (mode == 0 && cmd >= imlen[row * planes + plane]) - bf[plane] = 0; - else - bf[plane] = (image[row * planes + plane][cmd] & - (1 << (7 - i))) ? 255 : 0; - PPM_ASSIGN(pixrow[col + i], bf[0], bf[1], bf[2]); - } + for (cmd = 0, c = 0; c < cols; c += 8, cmd++) + for (i = 0; i < 8 && c + i < cols; i++) { + for (p = 0; p < planes; p++) + if (mode == 0 && cmd >= imlen[r * planes + p]) + bf[p] = 0; + else + bf[p] = (image[r * planes + p][cmd] & + (1 << (7 - i))) ? 255 : 0; + PPM_ASSIGN(pixrow[c + i], bf[0], bf[1], bf[2]); } - } - ppm_writeppmrow(stdout, pixrow, cols, 255, 0); + ppm_writeppmrow(stdout, pixrow, cols, (pixval) 255, 0); } pm_close(stdout); - - return 0; + exit(0); } - - - diff --git a/converter/ppm/ppmtoeyuv.c b/converter/ppm/ppmtoeyuv.c index f5ce115..6f072be 100644 --- a/converter/ppm/ppmtoeyuv.c +++ b/converter/ppm/ppmtoeyuv.c @@ -114,6 +114,7 @@ create_multiplication_tables(const pixval maxval) { int index; + overflow_add(maxval, 1); MALLOCARRAY_NOFAIL(mult299 , maxval+1); MALLOCARRAY_NOFAIL(mult587 , maxval+1); MALLOCARRAY_NOFAIL(mult114 , maxval+1); diff --git a/converter/ppm/ppmtolj.c b/converter/ppm/ppmtolj.c index 7ed814e..b4e7db1 100644 --- a/converter/ppm/ppmtolj.c +++ b/converter/ppm/ppmtolj.c @@ -182,6 +182,7 @@ int main(int argc, char *argv[]) { ppm_readppminit( ifp, &cols, &rows, &maxval, &format ); pixelrow = ppm_allocrow( cols ); + overflow2(cols, 6); obuf = (unsigned char *) pm_allocrow(cols * 3, sizeof(unsigned char)); cbuf = (unsigned char *) pm_allocrow(cols * 6, sizeof(unsigned char)); if (mode == C_TRANS_MODE_DELTA) diff --git a/converter/ppm/ppmtomitsu.c b/converter/ppm/ppmtomitsu.c index 5b0b324..11db755 100644 --- a/converter/ppm/ppmtomitsu.c +++ b/converter/ppm/ppmtomitsu.c @@ -685,6 +685,8 @@ main(int argc, char * argv[]) { medias = MSize_User; if (dpi300) { + overflow2(medias.maxcols, 2); + overflow2(medias.maxrows, 2); medias.maxcols *= 2; medias.maxrows *= 2; } diff --git a/converter/ppm/ppmtopcx.c b/converter/ppm/ppmtopcx.c index fa68edc..97dfb2b 100644 --- a/converter/ppm/ppmtopcx.c +++ b/converter/ppm/ppmtopcx.c @@ -425,6 +425,8 @@ ppmTo16ColorPcx(pixel ** const pixels, else Planes = 1; } } + overflow2(BitsPerPixel, cols); + overflow_add(BitsPerPixel * cols, 7); BytesPerLine = ((cols * BitsPerPixel) + 7) / 8; MALLOCARRAY_NOFAIL(indexRow, cols); MALLOCARRAY_NOFAIL(planesrow, BytesPerLine); diff --git a/converter/ppm/ppmtopict.c b/converter/ppm/ppmtopict.c index 36464b6..c91ccf2 100644 --- a/converter/ppm/ppmtopict.c +++ b/converter/ppm/ppmtopict.c @@ -450,6 +450,8 @@ main(int argc, const char ** argv) { putShort(stdout, 0); /* mode */ /* Finally, write out the data. */ + overflow_add(cols/MAX_COUNT, 1); + overflow_add(cols, cols/MAX_COUNT+1); outBuf = malloc((unsigned)(cols+cols/MAX_COUNT+1)); for (row = 0, oc = 0; row < rows; ++row) { unsigned int rowSize; diff --git a/converter/ppm/ppmtopj.c b/converter/ppm/ppmtopj.c index d116773..fc84cac 100644 --- a/converter/ppm/ppmtopj.c +++ b/converter/ppm/ppmtopj.c @@ -179,6 +179,7 @@ char *argv[]; pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); pm_close( ifp ); + overflow2(cols,2); obuf = (unsigned char *) pm_allocrow(cols, sizeof(unsigned char)); cbuf = (unsigned char *) pm_allocrow(cols * 2, sizeof(unsigned char)); diff --git a/converter/ppm/ppmtopjxl.c b/converter/ppm/ppmtopjxl.c index 90bcef0..72d0027 100644 --- a/converter/ppm/ppmtopjxl.c +++ b/converter/ppm/ppmtopjxl.c @@ -267,6 +267,9 @@ main(int argc, const char * argv[]) { if (maxval > PCL_MAXVAL) pm_error("color range too large; reduce with ppmcscale"); + if (cols < 0 || rows < 0) + pm_error("negative size is not possible"); + /* Figure out the colormap. */ pm_message("Computing colormap..."); chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors); @@ -286,6 +289,8 @@ main(int argc, const char * argv[]) { case 0: /* direct mode (no palette) */ bpp = bitsperpixel(maxval); /* bits per pixel */ bpg = bpp; bpb = bpp; + overflow2(bpp, 3); + overflow_add(bpp*3, 7); bpp = (bpp*3+7)>>3; /* bytes per pixel now */ bpr = (bpp<<3)-bpg-bpb; bpp *= cols; /* bytes per row now */ @@ -295,9 +300,13 @@ main(int argc, const char * argv[]) { case 3: case 7: pclindex++; default: bpp = 8/pclindex; + overflow_add(cols, bpp); + if(bpp == 0) + pm_error("assert: no bpp"); bpp = (cols+bpp-1)/bpp; /* bytes per row */ } } + overflow2(bpp,2); inrow = (char *)malloc((unsigned)bpp); outrow = (char *)malloc((unsigned)bpp*2); runcnt = (signed char *)malloc((unsigned)bpp); diff --git a/converter/ppm/ppmtowinicon.c b/converter/ppm/ppmtowinicon.c index c673798..af2b445 100644 --- a/converter/ppm/ppmtowinicon.c +++ b/converter/ppm/ppmtowinicon.c @@ -12,6 +12,7 @@ #include #include +#include #include "pm_c_util.h" #include "winico.h" @@ -214,6 +215,7 @@ createAndBitmap (gray ** const ba, int const cols, int const rows, MALLOCARRAY_NOFAIL(rowData, rows); icBitmap->xBytes = xBytes; icBitmap->data = rowData; + overflow2(xBytes, rows); icBitmap->size = xBytes * rows; for (y=0;yxBytes = xBytes; icBitmap->data = rowData; + overflow2(xBytes, rows); icBitmap->size = xBytes * rows; for (y=0;yxBytes = xBytes; icBitmap->data = rowData; + overflow2(xBytes, rows); icBitmap->size = xBytes * rows; for (y=0;ybitcount = bpp; entry->ih = createInfoHeader(entry, xorBitmap, andBitmap); entry->colors = palette->colors; - entry->size_in_bytes = + overflow2(4, entry->color_count); + overflow_add(xorBitmap->size, andBitmap->size); + overflow_add(xorBitmap->size + andBitmap->size, 40); + overflow_add(xorBitmap->size + andBitmap->size + 40, 4 * entry->color_count); + entry->size_in_bytes = xorBitmap->size + andBitmap->size + 40 + (4 * entry->color_count); if (verbose) pm_message("entry->size_in_bytes = %d + %d + %d = %d", diff --git a/converter/ppm/ppmtoxpm.c b/converter/ppm/ppmtoxpm.c index 0e31692..1b3923f 100644 --- a/converter/ppm/ppmtoxpm.c +++ b/converter/ppm/ppmtoxpm.c @@ -198,6 +198,7 @@ genNumstr(unsigned int const input, int const digits) { unsigned int i; /* Allocate memory for printed number. Abort if error. */ + overflow_add(digits, 1); if (!(str = (char *) malloc(digits + 1))) pm_error("out of memory"); @@ -315,6 +316,7 @@ genCmap(colorhist_vector const chv, unsigned int charsPerPixel; unsigned int xpmMaxval; + if (includeTransparent) overflow_add(ncolors, 1); MALLOCARRAY(cmap, cmapSize); if (cmapP == NULL) pm_error("Out of memory allocating %u bytes for a color map.", diff --git a/converter/ppm/qrttoppm.c b/converter/ppm/qrttoppm.c index 935463e..653084c 100644 --- a/converter/ppm/qrttoppm.c +++ b/converter/ppm/qrttoppm.c @@ -46,7 +46,7 @@ main( argc, argv ) ppm_writeppminit( stdout, cols, rows, maxval, 0 ); pixelrow = ppm_allocrow( cols ); - buf = (unsigned char *) malloc( 3 * cols ); + buf = (unsigned char *) malloc2( 3 , cols ); if ( buf == (unsigned char *) 0 ) pm_error( "out of memory" ); diff --git a/converter/ppm/sldtoppm.c b/converter/ppm/sldtoppm.c index 2dc049f..2a482be 100644 --- a/converter/ppm/sldtoppm.c +++ b/converter/ppm/sldtoppm.c @@ -154,127 +154,85 @@ vscale(int * const px, -static void -upcase(const char * const sname, - char * const uname) { - - unsigned int i; - const char * ip; - - for (i = 0, ip = sname; i < 31; ++i) { - char const ch = *ip++; - - if (ch != EOS) - uname[i] = islower(ch) ? toupper(ch) : ch; - } - uname[i] = EOS; -} - - - -static void -skipBytes(FILE * const fileP, - unsigned int const count) { - - unsigned int i; - - for (i = 0; i < count; ++i) - getc(fileP); -} - - - -static void -scanDirectory(FILE * const slFileP, - long const dirPos, - bool const dirOnly, - const char * const uname, - bool * const foundP) { -/*---------------------------------------------------------------------------- - Scan the directory at the current position in *slFileP, either listing - the directory ('dirOnly' true) or searching for a slide named - 'uname' ('dirOnly' false). - - 'dirPos' is the offset in the file of the directory, i.e. the current - position of *slFileP. - - In the latter case, return as *foundP whether the slide name is there. ------------------------------------------------------------------------------*/ - bool found; - bool eof; - long pos; - unsigned char libent[36]; - - for (found = false, eof = false, pos = dirPos; !found && !eof; ) { - size_t readCt; - readCt = fread(libent, 36, 1, slFileP); - if (readCt != 1) - eof = true; - else { - /* The directory entry is 32 bytes of NUL-terminated slide name - followed by 4 bytes of offset of the next directory entry. - */ - const char * const slideName = (const char *)(&libent[0]); - if (pm_strnlen(slideName, 32) == 32) - pm_error("Invalid input: slide name field is not " - "nul-terminated"); - else { - if (strlen(slideName) == 0) - eof = true; - else { - pos += 36; - if (dirOnly) { - pm_message(" %s", slideName); - } else if (streq(slideName, uname)) { - long const dpos = - (((((libent[35] << 8) | libent[34]) << 8) | - libent[33]) << 8) | libent[32]; - - if ((slFileP == stdin) || - (fseek(slFileP, dpos, 0) == -1)) { - - skipBytes(slFileP, dpos - pos); - } - found = true; - } - } - } - } - } - *foundP = found; -} - /* SLIDEFIND -- Find a slide in a library or, if DIRONLY is nonzero, print a directory listing of the library. If UCASEN is nonzero, the requested slide name is converted to upper case. */ static void -slidefind(const char * const slideName, - bool const dirOnly, +slidefind(const char * const sname, + bool const dironly, bool const ucasen) { - char uname[32]; /* upper case translation of 'slideName' */ - char header[32]; /* (supposed) header read from file */ + char uname[32]; + unsigned char libent[36]; + long pos; bool found; + bool eof; - if (dirOnly) + if (dironly) pm_message("Slides in library:"); else { - upcase(slideName, uname); + unsigned int i; + const char * ip; + + ip = sname; /* initial value */ + + for (i = 0; i < 31; ++i) { + char const ch = *ip++; + if (ch == EOS) + break; + + { + char const upperCh = + ucasen && islower(ch) ? toupper(ch) : ch; + + uname[i] = upperCh; + } + } + uname[i] = EOS; } /* Read slide library header and verify. */ - - if ((fread(header, 32, 1, slfile) != 1) || - (!STRSEQ(header, "AutoCAD Slide Library 1.0\r\n\32"))) { + + if ((fread(libent, 32, 1, slfile) != 1) || + (!streq((char *)libent, "AutoCAD Slide Library 1.0\015\012\32"))) { pm_error("not an AutoCAD slide library file."); } + pos = 32; + + /* Search for a slide with the requested name or list the directory */ + + for (found = false, eof = false; !found && !eof; ) { + size_t readCt; + readCt = fread(libent, 36, 1, slfile); + if (readCt != 1) + eof = true; + else if (strlen((char *)libent) == 0) + eof = true; + } + if (!eof) { + pos += 36; + if (dironly) { + pm_message(" %s", libent); + } else if (streq((char *)libent, uname)) { + long dpos; + + dpos = (((((libent[35] << 8) | libent[34]) << 8) | + libent[33]) << 8) | libent[32]; + + if ((slfile == stdin) || (fseek(slfile, dpos, 0) == -1)) { + dpos -= pos; + + while (dpos-- > 0) + getc(slfile); + } + found = true; + } + } - scanDirectory(slfile, 32, dirOnly, ucasen ? uname : slideName, &found); - - if (!found && !dirOnly) - pm_error("slide '%s' not in library.", slideName); + if (!found && !dironly) + pm_error("slide '%s' not in library.", sname); } @@ -392,7 +350,7 @@ slider(slvecfn slvec, /* Verify that slide format is compatible with this program. */ - if (!STRSEQ(slfrof.slh, slhi.slh)) + if (streq(slfrof.slh, slhi.slh)) pm_error("this is not an AutoCAD slide file."); /* Verify that the number format and file level in the header are @@ -506,6 +464,8 @@ slider(slvecfn slvec, /* Allocate image buffer and clear it to black. */ + overflow_add(ixdots, 1); + overflow_add(iydots, 1); pixels = ppm_allocarray(pixcols = ixdots + 1, pixrows = iydots + 1); PPM_ASSIGN(rgbcolor, 0, 0, 0); ppmd_filledrectangle(pixels, pixcols, pixrows, pixmaxval, 0, 0, diff --git a/converter/ppm/ximtoppm.c b/converter/ppm/ximtoppm.c index 75faac6..5758739 100644 --- a/converter/ppm/ximtoppm.c +++ b/converter/ppm/ximtoppm.c @@ -118,6 +118,7 @@ ReadXimHeader(FILE * const in_fp, header->bits_channel = atoi(a_head.bits_per_channel); header->alpha_flag = atoi(a_head.alpha_channel); if (strlen(a_head.author)) { + overflow_add(strlen(a_head.author),1); if (!(header->author = calloc((unsigned int)strlen(a_head.author)+1, 1))) { pm_message("ReadXimHeader: can't calloc author string" ); @@ -127,6 +128,7 @@ ReadXimHeader(FILE * const in_fp, strncpy(header->author, a_head.author, strlen(a_head.author)); } if (strlen(a_head.date)) { + overflow_add(strlen(a_head.date),1); if (!(header->date =calloc((unsigned int)strlen(a_head.date)+1,1))){ pm_message("ReadXimHeader: can't calloc date string" ); return(0); @@ -135,6 +137,7 @@ ReadXimHeader(FILE * const in_fp, strncpy(header->date, a_head.date, strlen(a_head.date)); } if (strlen(a_head.program)) { + overflow_add(strlen(a_head.program),1); if (!(header->program = calloc( (unsigned int)strlen(a_head.program) + 1, 1))) { pm_message("ReadXimHeader: can't calloc program string" ); @@ -161,6 +164,7 @@ ReadXimHeader(FILE * const in_fp, if (header->nchannels == 3 && header->bits_channel == 8) header->ncolors = 0; else if (header->nchannels == 1 && header->bits_channel == 8) { + overflow2(header->ncolors, sizeof(Color)); header->colors = (Color *)calloc((unsigned int)header->ncolors, sizeof(Color)); if (header->colors == NULL) { diff --git a/editor/pamcut.c b/editor/pamcut.c index db5b5b3..5fc0267 100644 --- a/editor/pamcut.c +++ b/editor/pamcut.c @@ -773,6 +773,8 @@ cutOneImage(FILE * const ifP, outpam = inpam; /* Initial value -- most fields should be same */ outpam.file = ofP; + overflow_add(rightcol, 1); + overflow_add(bottomrow, 1); outpam.width = rightcol - leftcol + 1; outpam.height = bottomrow - toprow + 1; diff --git a/editor/pnmgamma.c b/editor/pnmgamma.c index b357b0d..ec612d3 100644 --- a/editor/pnmgamma.c +++ b/editor/pnmgamma.c @@ -596,6 +596,7 @@ createGammaTables(enum transferFunction const transferFunction, xelval ** const btableP) { /* Allocate space for the tables. */ + overflow_add(maxval, 1); MALLOCARRAY(*rtableP, maxval+1); MALLOCARRAY(*gtableP, maxval+1); MALLOCARRAY(*btableP, maxval+1); diff --git a/editor/pnmhisteq.c b/editor/pnmhisteq.c index a339f73..c2c85a3 100644 --- a/editor/pnmhisteq.c +++ b/editor/pnmhisteq.c @@ -107,6 +107,7 @@ computeLuminosityHistogram(xel * const * const xels, unsigned int pixelCount; unsigned int * lumahist; + overflow_add(maxval, 1); MALLOCARRAY(lumahist, maxval + 1); if (lumahist == NULL) pm_error("Out of storage allocating array for %u histogram elements", diff --git a/editor/pnmindex.csh b/editor/pnmindex.csh index c6f1e84..c513a84 100755 --- a/editor/pnmindex.csh +++ b/editor/pnmindex.csh @@ -1,5 +1,7 @@ #!/bin/csh -f # +echo "Unsafe code, needs debugging, do not ship" +exit 1 # pnmindex - build a visual index of a bunch of anymaps # # Copyright (C) 1991 by Jef Poskanzer. diff --git a/editor/pnmpad.c b/editor/pnmpad.c index 55cdcd6..10da3af 100644 --- a/editor/pnmpad.c +++ b/editor/pnmpad.c @@ -654,6 +654,8 @@ main(int argc, const char ** argv) { computePadSizes(cmdline, cols, rows, &lpad, &rpad, &tpad, &bpad); + overflow_add(cols, lpad); + overflow_add(cols + lpad, rpad); newcols = cols + lpad + rpad; if (cmdline.reportonly) diff --git a/editor/pnmremap.c b/editor/pnmremap.c index 0c0096b..8b86cb7 100644 --- a/editor/pnmremap.c +++ b/editor/pnmremap.c @@ -468,6 +468,7 @@ fserr_init(struct pam * const pamP, unsigned int const fserrSize = pamP->width + 2; + overflow_add(pamP->width, 2); fserrP->width = pamP->width; MALLOCARRAY(fserrP->thiserr, pamP->depth); @@ -506,6 +507,7 @@ floydInitRow(struct pam * const pamP, unsigned int col; + overflow_add(pamP->width, 2); for (col = 0; col < pamP->width + 2; ++col) { unsigned int plane; for (plane = 0; plane < pamP->depth; ++plane) diff --git a/editor/pnmremap.c.rej b/editor/pnmremap.c.rej new file mode 100644 index 0000000..c627c20 --- /dev/null +++ b/editor/pnmremap.c.rej @@ -0,0 +1,10 @@ +--- editor/pnmremap.c ++++ editor/pnmremap.c +@@ -506,6 +507,7 @@ floydInitRow(struct pam * const pamP, struct Fserr * const fserrP) { + + int col; + ++ overflow_add(pamP->width, 2); + for (col = 0; col < pamP->width + 2; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) diff --git a/editor/pnmscalefixed.c b/editor/pnmscalefixed.c index 884ca31..747cd8f 100644 --- a/editor/pnmscalefixed.c +++ b/editor/pnmscalefixed.c @@ -214,6 +214,7 @@ compute_output_dimensions(const struct cmdline_info cmdline, const int rows, const int cols, int * newrowsP, int * newcolsP) { + overflow2(rows, cols); if (cmdline.pixels) { if (rows * cols <= cmdline.pixels) { *newrowsP = rows; @@ -265,6 +266,8 @@ compute_output_dimensions(const struct cmdline_info cmdline, if (*newcolsP < 1) *newcolsP = 1; if (*newrowsP < 1) *newrowsP = 1; + + overflow2(*newcolsP, *newrowsP); } @@ -446,6 +449,9 @@ main(int argc, char **argv ) { unfilled. We can address that by stretching, whereas the other case would require throwing away some of the input. */ + + overflow2(newcols, SCALE); + overflow2(newrows, SCALE); sxscale = SCALE * newcols / cols; syscale = SCALE * newrows / rows; diff --git a/editor/ppmdither.c b/editor/ppmdither.c index ec1b977..e701e09 100644 --- a/editor/ppmdither.c +++ b/editor/ppmdither.c @@ -356,6 +356,11 @@ dithMatrix(unsigned int const dithPower) { (dithDim * sizeof(*dithMat)) + /* pointers */ (dithDim * dithDim * sizeof(**dithMat)); /* data */ + + overflow2(dithDim, sizeof(*dithMat)); + overflow3(dithDim, dithDim, sizeof(**dithMat)); + overflow_add(dithDim * sizeof(*dithMat), dithDim * dithDim * sizeof(**dithMat)); + dithMat = malloc(dithMatSize); if (dithMat == NULL) diff --git a/editor/specialty/pamoil.c b/editor/specialty/pamoil.c index 6cb8d3a..6f4bde9 100644 --- a/editor/specialty/pamoil.c +++ b/editor/specialty/pamoil.c @@ -112,6 +112,7 @@ main(int argc, char *argv[] ) { tuples = pnm_readpam(ifp, &inpam, PAM_STRUCT_SIZE(tuple_type)); pm_close(ifp); + overflow_add(inpam.maxval, 1); MALLOCARRAY(hist, inpam.maxval + 1); if (hist == NULL) pm_error("Unable to allocate memory for histogram."); diff --git a/lib/libpam.c b/lib/libpam.c index a8f140b..e6986f1 100644 --- a/lib/libpam.c +++ b/lib/libpam.c @@ -225,7 +225,8 @@ allocPamRow(const struct pam * const pamP) { unsigned int const bytesPerTuple = allocationDepth(pamP) * sizeof(sample); tuple * tuplerow; - tuplerow = malloc(pamP->width * (sizeof(tuple *) + bytesPerTuple)); + overflow_add(sizeof(tuple *), bytesPerTuple); + tuplerow = malloc2(pamP->width, (sizeof(tuple *) + bytesPerTuple)); if (tuplerow != NULL) { /* Now we initialize the pointers to the individual tuples diff --git a/lib/libpammap.c b/lib/libpammap.c index 2222491..ba27a4c 100644 --- a/lib/libpammap.c +++ b/lib/libpammap.c @@ -108,7 +108,9 @@ allocTupleIntListItem(struct pam * const pamP) { */ struct tupleint_list_item * retval; - unsigned int const size = + overflow2(pamP->depth, sizeof(sample)); + overflow_add(sizeof(*retval)-sizeof(retval->tupleint.tuple), pamP->depth*sizeof(sample)); + unsigned int const size = sizeof(*retval) - sizeof(retval->tupleint.tuple) + pamP->depth * sizeof(sample); diff --git a/lib/libpm.c b/lib/libpm.c index 47a2f49..a263598 100644 --- a/lib/libpm.c +++ b/lib/libpm.c @@ -888,5 +888,53 @@ pm_parse_height(const char * const arg) { return height; } +/* + * Maths wrapping + */ +void __overflow2(int a, int b) +{ + if(a < 0 || b < 0) + pm_error("object too large"); + if(b == 0) + return; + if(a > INT_MAX / b) + pm_error("object too large"); +} + +void overflow3(int a, int b, int c) +{ + overflow2(a,b); + overflow2(a*b, c); +} + +void overflow_add(int a, int b) +{ + if( a > INT_MAX - b) + pm_error("object too large"); +} + +void *malloc2(int a, int b) +{ + overflow2(a, b); + if(a*b == 0) + pm_error("Zero byte allocation"); + return malloc(a*b); +} + +void *malloc3(int a, int b, int c) +{ + overflow3(a, b, c); + if(a*b*c == 0) + pm_error("Zero byte allocation"); + return malloc(a*b*c); +} + +void *realloc2(void * a, int b, int c) +{ + overflow2(b, c); + if(b*c == 0) + pm_error("Zero byte allocation"); + return realloc(a, b*c); +} diff --git a/lib/pm.h b/lib/pm.h index 3fc92fb..1e30ce9 100644 --- a/lib/pm.h +++ b/lib/pm.h @@ -441,5 +441,12 @@ pm_parse_height(const char * const arg); } #endif +void *malloc2(int, int); +void *malloc3(int, int, int); +#define overflow2(a,b) __overflow2(a,b) +void __overflow2(int, int); +void overflow3(int, int, int); +void overflow_add(int, int); + #endif diff --git a/lib/pm.h.orig b/lib/pm.h.orig new file mode 100644 index 0000000..471f445 --- /dev/null +++ b/lib/pm.h.orig @@ -0,0 +1,446 @@ +/* pm.h - interface to format-independent part of libpbm. +** +** Copyright (C) 1988, 1989, 1991 by Jef Poskanzer. +** +** Permission to use, copy, modify, and distribute this software and its +** documentation for any purpose and without fee is hereby granted, provided +** that the above copyright notice appear in all copies and that both that +** copyright notice and this permission notice appear in supporting +** documentation. This software is provided "as is" without express or +** implied warranty. +*/ + +#ifndef PM_H_INCLUDED +#define PM_H_INCLUDED + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#if 0 +} /* to fake out automatic code indenters */ +#endif + + +/* Definitions to make Netpbm programs work with either ANSI C or C + Classic. + + This is obsolete, as all compilers recognize the ANSI syntax now. + + We are slowly removing all the ARGS invocations from the programs + (and replacing them with explicit ANSI syntax), but we have a lot + of programs where we have removed ARGS from the definition but not + the prototype, and we have discovered that the Sun compiler + considers the resulting mismatch between definition and prototype + to be an error. So we make ARGS create the ANSI syntax + unconditionally to avoid having to fix all those mismatches. */ + +#if 0 +#if __STDC__ +#define ARGS(alist) alist +#else /*__STDC__*/ +#define ARGS(alist) () +#define const +#endif /*__STDC__*/ +#endif +#define ARGS(alist) alist + + +/* PM_GNU_PRINTF_ATTR lets the GNU compiler check pm_message() and pm_error() + calls to be sure the arguments match the format string, thus preventing + runtime segmentation faults and incorrect messages. +*/ +#ifdef __GNUC__ +#define PM_GNU_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +#define PM_GNU_PRINTF_ATTR(a,b) +#endif + + +/* PURE_FN_ATTR is the attribute you add to a function declaration + that indicates it's a true function -- has no side effects and return + value is not influenced by anything except its arguments. +*/ +#ifdef __GNUC__ +#define PURE_FN_ATTR __attribute__ ((const)) +#else +#define PURE_FN_ATTR +#endif + + +/* S_IRUSR is POSIX, defined in Some old BSD systems and Windows + systems have S_IREAD instead. Most Unix today (2011) has both. In 2011, + Android has S_IRUSR and not S_IREAD. + + Some Windows has _S_IREAD. + + We're ignoring S_IREAD now to see if anyone misses it. If there are still + users that need it, we can handle it here. +*/ +#if MSVCRT + #define PM_S_IWUSR _S_IWRITE + #define PM_S_IRUSR _S_IREAD +#else + #define PM_S_IWUSR S_IWUSR + #define PM_S_IRUSR S_IRUSR +#endif + + + +typedef struct { + /* Coordinates of a pixel within an image. Row 0 is the top row. + Column 0 is the left column. + */ + unsigned int row; + unsigned int col; +} pm_pixelcoord; + +extern int pm_plain_output; + /* Output functions are to produce plain (as opposed to raw) format + regardless of their 'plainformat' arguments. + */ +extern const char * pm_progname; + +void +pm_init(const char * const progname, unsigned int const flags); + +void +pm_proginit(int * const argcP, const char * argv[]); + +void +pm_setMessage(int const newState, int * const oldStateP); + +int +pm_getMessage(void); + +FILE * +pm_tmpfile(void); + +int +pm_tmpfile_fd(void); + +void +pm_make_tmpfile(FILE ** const filePP, + const char ** const filenameP); + +void +pm_make_tmpfile_fd(int * const fdP, + const char ** const filenameP); + +void +pm_nextimage(FILE * const file, int * const eofP); + +/* Variable-sized arrays definitions. */ + +char** +pm_allocarray (int const cols, int const rows, int const size ); + +void * +pm_allocrow(unsigned int const cols, + unsigned int const size); + +void +pm_freearray (char** const its, int const rows); + +void +pm_freerow(void * const row); + + +/* Obsolete -- use shhopt instead */ +int +pm_keymatch(const char * const str, + const char * const keyword, + int const minchars); + + +int PURE_FN_ATTR +pm_maxvaltobits(int const maxval); + +int PURE_FN_ATTR +pm_bitstomaxval(int const bits); + +unsigned int PURE_FN_ATTR +pm_lcm (unsigned int const x, + unsigned int const y, + unsigned int const z, + unsigned int const limit); + +void +pm_setjmpbuf(jmp_buf * const jmpbufP); + +void +pm_setjmpbufsave(jmp_buf * const jmpbufP, + jmp_buf ** const oldJmpbufPP); + +void +pm_longjmp(void); + +void +pm_fork(int * const iAmParentP, + pid_t * const childPidP, + const char ** const errorP); + +void +pm_waitpid(pid_t const pid, + int * const statusP, + int const options, + pid_t * const exitedPidP, + const char ** const errorP); + + +void +pm_waitpidSimple(pid_t const pid); + +typedef void pm_usermessagefn(const char * msg); + +void +pm_setusermessagefn(pm_usermessagefn * fn); + +typedef void pm_usererrormsgfn(const char * msg); + +void +pm_setusererrormsgfn(pm_usererrormsgfn * fn); + +void PM_GNU_PRINTF_ATTR(1,2) +pm_message (const char format[], ...); + +void PM_GNU_PRINTF_ATTR(1,2) +pm_errormsg(const char format[], ...); + +void PM_GNU_PRINTF_ATTR(1,2) +pm_error (const char reason[], ...); + +int +pm_have_float_format(void); + +/* Obsolete - use shhopt and user's manual instead */ +void +pm_usage (const char usage[]); + +FILE* +pm_openr (const char* const name); + +FILE* +pm_openw (const char* const name); + +FILE * +pm_openr_seekable(const char name[]); + +void +pm_close (FILE* const f); + +void +pm_closer (FILE* const f); + +void +pm_closew (FILE* const f); + + + +void +pm_readchar(FILE * const ifP, + char * const cP); + +static __inline__ void +pm_readcharu(FILE * const ifP, + unsigned char * const cP) { + pm_readchar(ifP, (char *) cP); +} + +void +pm_writechar(FILE * const ofP, + char const c); + +static __inline__ void +pm_writecharu(FILE * const ofP, + unsigned char const c) { + pm_writechar(ofP, (char) c); +} + +int +pm_readbigshort(FILE * const ifP, + short * const sP); + +static __inline__ int +pm_readbigshortu(FILE* const ifP, + unsigned short * const sP) { + return pm_readbigshort(ifP, (short *) sP); +} + +int +pm_writebigshort(FILE * const ofP, + short const s); + +static __inline__ int +pm_writebigshortu(FILE * const ofP, + unsigned short const s) { + return pm_writebigshort(ofP, (short) s); +} + +int +pm_readbiglong(FILE * const ifP, + long * const lP); + +static __inline__ int +pm_readbiglongu(FILE * const ifP, + unsigned long * const lP) { + return pm_readbiglong(ifP, (long *) lP); +} + +int +pm_readbiglong2(FILE * const ifP, + int32_t * const lP); + +static __inline__ int +pm_readbiglongu2(FILE * const ifP, + uint32_t * const lP) { + return pm_readbiglong2(ifP, (int32_t *) lP); +} + +int +pm_writebiglong(FILE * const ofP, + long const l); + +static __inline__ int +pm_writebiglongu(FILE * const ofP, + unsigned long const l) { + return pm_writebiglong(ofP, (long) l); +} + +int +pm_readlittleshort(FILE * const ifP, + short * const sP); + +static __inline__ int +pm_readlittleshortu(FILE * const ifP, + unsigned short * const sP) { + return pm_readlittleshort(ifP, (short *) sP); +} + +int +pm_writelittleshort(FILE * const ofP, + short const s); + +static __inline__ int +pm_writelittleshortu(FILE * const ofP, + unsigned short const s) { + return pm_writelittleshort(ofP, (short) s); +} + +int +pm_readlittlelong(FILE * const ifP, + long * const lP); + +static __inline__ int +pm_readlittlelongu(FILE * const ifP, + unsigned long * const lP) { + return pm_readlittlelong(ifP, (long *) lP); +} + +int +pm_readlittlelong2(FILE * const ifP, + int32_t * const lP); + +static __inline__ int +pm_readlittlelong2u(FILE * const ifP, + uint32_t * const lP) { + return pm_readlittlelong2(ifP, (int32_t *) lP); +} + +int +pm_writelittlelong(FILE * const ofP, + long const l); + +static __inline__ int +pm_writelittlelongu(FILE * const ofP, + unsigned long const l) { + return pm_writelittlelong(ofP, (long) l); +} + +int +pm_readmagicnumber(FILE * const ifP); + +char* +pm_read_unknown_size(FILE * const ifP, + long * const buf); + +void +pm_getline(FILE * const ifP, + char ** const bufferP, + size_t * const bufferSzP, + int * const eofP, + size_t * const lineLenP); + +short +pm_bs_short(short const s); + +long +pm_bs_long(long const l); + +unsigned int +pm_tell(FILE * const fileP); + +void +pm_tell2(FILE * const fileP, + void * const fileposP, + unsigned int const fileposSize); + +void +pm_seek2(FILE * const fileP, + const pm_filepos * const fileposP, + unsigned int const fileposSize); + +void +pm_seek(FILE * const fileP, unsigned long filepos); + +enum pm_check_code { + PM_CHECK_OK, + PM_CHECK_UNKNOWN_TYPE, + PM_CHECK_TOO_LONG, + PM_CHECK_UNCHECKABLE, + PM_CHECK_TOO_SHORT +}; + +enum pm_check_type { + PM_CHECK_BASIC +}; + +void +pm_check(FILE * const file, + enum pm_check_type const check_type, + pm_filepos const need_raster_size, + enum pm_check_code * const retval_p); + +void +pm_drain(FILE * const fileP, + unsigned int const limit, + unsigned int * const bytesReadP); + +char * +pm_arg0toprogname(const char arg0[]); + +unsigned int +pm_randseed(void); + +unsigned int +pm_parse_width(const char * const arg); + +unsigned int +pm_parse_height(const char * const arg); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/other/pnmcolormap.c b/other/pnmcolormap.c index 7da3122..dafa390 100644 --- a/other/pnmcolormap.c +++ b/other/pnmcolormap.c @@ -1002,6 +1002,7 @@ colormapToSquare(struct pam * const pamP, pamP->width = intsqrt; else pamP->width = intsqrt + 1; + overflow_add(intsqrt, 1); } { unsigned int const intQuotient = colormap.size / pamP->width; diff --git a/other/pnmcolormap.c.orig b/other/pnmcolormap.c.orig new file mode 100644 index 0000000..7da3122 --- /dev/null +++ b/other/pnmcolormap.c.orig @@ -0,0 +1,1143 @@ +/****************************************************************************** + pnmcolormap.c +******************************************************************************* + + Create a colormap file (a PPM image containing one pixel of each of a set + of colors). Base the set of colors on an input image. + + For PGM input, do the equivalent for grayscale and produce a PGM graymap. + + By Bryan Henderson, San Jose, CA 2001.12.17 + + Derived from ppmquant, originally by Jef Poskanzer. + + Copyright (C) 1989, 1991 by Jef Poskanzer. + Copyright (C) 2001 by Bryan Henderson. + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, provided + that the above copyright notice appear in all copies and that both that + copyright notice and this permission notice appear in supporting + documentation. This software is provided "as is" without express or + implied warranty. + +******************************************************************************/ + +#include +#include + +#include "pm_config.h" +#include "pm_c_util.h" +#include "mallocvar.h" +#include "nstring.h" +#include "shhopt.h" +#include "pam.h" +#include "pammap.h" + +enum MethodForLargest {LARGE_NORM, LARGE_LUM}; + +enum MethodForRep {REP_CENTER_BOX, REP_AVERAGE_COLORS, REP_AVERAGE_PIXELS}; + +enum MethodForSplit {SPLIT_MAX_PIXELS, SPLIT_MAX_COLORS, SPLIT_MAX_SPREAD}; + +struct Box { + unsigned int index; + unsigned int colorCt; + unsigned int sum; + unsigned int maxdim; + /* which dimension has the largest spread. RGB plane number. */ + sample spread; + /* spread in dimension 'maxdim' */ +}; + +struct BoxVector { + struct Box * box; /* malloc'ed array */ + unsigned int boxCt; + unsigned int capacity; +}; + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileNm; /* Name of input file */ + unsigned int allcolors; /* boolean: select all colors from the input */ + unsigned int newcolors; + /* Number of colors argument; meaningless if allcolors true */ + enum MethodForLargest methodForLargest; + /* -spreadintensity/-spreadluminosity options */ + enum MethodForRep methodForRep; + /* -center/-meancolor/-meanpixel options */ + enum MethodForSplit methodForSplit; + /* -splitpixelct/-splitcolorct/-splitspread options */ + unsigned int sort; + unsigned int square; + unsigned int verbose; +}; + + + +static void +parseCommandLine (int argc, const char ** argv, + struct CmdlineInfo *cmdlineP) { +/*---------------------------------------------------------------------------- + parse program command line described in Unix standard form by argc + and argv. Return the information in the options as *cmdlineP. + + If command line is internally inconsistent (invalid options, etc.), + issue error message to stderr and abort program. + + Note that the strings we return are stored in the storage that + was passed to us as the argv array. We also trash *argv. +-----------------------------------------------------------------------------*/ + optEntry *option_def; + /* Instructions to pm_optParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + + unsigned int spreadbrightness, spreadluminosity; + unsigned int center, meancolor, meanpixel; + unsigned int splitpixelct, splitcolorct, splitspread; + + MALLOCARRAY_NOFAIL(option_def, 100); + + option_def_index = 0; /* incremented by OPTENT3 */ + OPTENT3(0, "spreadbrightness", OPT_FLAG, + NULL, &spreadbrightness, 0); + OPTENT3(0, "spreadluminosity", OPT_FLAG, + NULL, &spreadluminosity, 0); + OPTENT3(0, "center", OPT_FLAG, + NULL, ¢er, 0); + OPTENT3(0, "meancolor", OPT_FLAG, + NULL, &meancolor, 0); + OPTENT3(0, "meanpixel", OPT_FLAG, + NULL, &meanpixel, 0); + OPTENT3(0, "splitpixelct", OPT_FLAG, + NULL, &splitpixelct, 0); + OPTENT3(0, "splitcolorct", OPT_FLAG, + NULL, &splitcolorct, 0); + OPTENT3(0, "splitspread", OPT_FLAG, + NULL, &splitspread, 0); + OPTENT3(0, "sort", OPT_FLAG, NULL, + &cmdlineP->sort, 0 ); + OPTENT3(0, "square", OPT_FLAG, NULL, + &cmdlineP->square, 0 ); + OPTENT3(0, "verbose", OPT_FLAG, NULL, + &cmdlineP->verbose, 0 ); + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */ + + pm_optParseOptions3( &argc, (char **)argv, opt, sizeof(opt), 0 ); + /* Uses and sets argc, argv, and some of *cmdline_p and others. */ + + + if (spreadbrightness && spreadluminosity) + pm_error("You cannot specify both -spreadbrightness and " + "spreadluminosity."); + if (spreadluminosity) + cmdlineP->methodForLargest = LARGE_LUM; + else + cmdlineP->methodForLargest = LARGE_NORM; + + if (center + meancolor + meanpixel > 1) + pm_error("You can specify only one of -center, -meancolor, and " + "-meanpixel."); + if (meancolor) + cmdlineP->methodForRep = REP_AVERAGE_COLORS; + else if (meanpixel) + cmdlineP->methodForRep = REP_AVERAGE_PIXELS; + else + cmdlineP->methodForRep = REP_CENTER_BOX; + + if (splitpixelct) + cmdlineP->methodForSplit = SPLIT_MAX_PIXELS; + else if (splitcolorct) + cmdlineP->methodForSplit = SPLIT_MAX_COLORS; + else if (splitspread) + cmdlineP->methodForSplit = SPLIT_MAX_SPREAD; + else + cmdlineP->methodForSplit = SPLIT_MAX_PIXELS; + + if (argc-1 > 2) + pm_error("Program takes at most two arguments: number of colors " + "and input file specification. " + "You specified %d arguments.", argc-1); + else { + if (argc-1 < 2) + cmdlineP->inputFileNm = "-"; + else + cmdlineP->inputFileNm = argv[2]; + + if (argc-1 < 1) + pm_error("You must specify the number of colors in the " + "output as an argument."); + else { + if (strcmp(argv[1], "all") == 0) + cmdlineP->allcolors = TRUE; + else { + char * tail; + long int const newcolors = strtol(argv[1], &tail, 10); + if (*tail != '\0') + pm_error("The number of colors argument '%s' is not " + "a number or 'all'", argv[1]); + else if (newcolors < 1) + pm_error("The number of colors must be positive"); + else if (newcolors == 1) + pm_error("The number of colors must be greater than 1."); + else { + cmdlineP->newcolors = newcolors; + cmdlineP->allcolors = FALSE; + } + } + } + } +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn compareplane; +#endif + +static unsigned int compareplanePlane; + /* This is a parameter to compareplane(). We use this global variable + so that compareplane() can be called by qsort(), to compare two + tuples. qsort() doesn't pass any arguments except the two tuples. + */ +static int +compareplane(const void * const arg1, + const void * const arg2) { + + const struct tupleint * const * const comparandPP = arg1; + const struct tupleint * const * const comparatorPP = arg2; + + sample const comparandSample = (*comparandPP) ->tuple[compareplanePlane]; + sample const comparatorSample = (*comparatorPP)->tuple[compareplanePlane]; + + return + comparandSample < comparatorSample ? -1 : + comparandSample > comparatorSample ? 1 : + 0; +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn sumcompare; +#endif + +static int +sumcompare(const void * const arg1, + const void * const arg2) { + + struct Box * const comparandP = (struct Box *)arg1; + struct Box * const comparatorP = (struct Box *)arg2; + + return + comparatorP->sum < comparandP->sum ? -1 : + comparatorP->sum > comparandP->sum ? 1 : + 0; +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn colcompare; +#endif + +static int +colcompare(const void * const arg1, + const void * const arg2) { + + struct Box * const comparandP = (struct Box *)arg1; + struct Box * const comparatorP = (struct Box *)arg2; + + return + comparatorP->colorCt < comparandP->colorCt ? -1 : + comparatorP->colorCt > comparandP->colorCt ? 1 : + 0; +} + + + +#ifndef LITERAL_FN_DEF_MATCH +static qsort_comparison_fn spreadcompare; +#endif + +static int +spreadcompare(const void * const arg1, + const void * const arg2) { + + struct Box * const comparandP = (struct Box *)arg1; + struct Box * const comparatorP = (struct Box *)arg2; + + return + comparatorP->spread < comparandP->spread ? -1 : + comparatorP->spread > comparandP->spread ? 1 : + 0; +} + + + +static void +sortBoxes(struct BoxVector * const boxVectorP, + enum MethodForSplit const methodForSplit) { + + qsort_comparison_fn * comparisonFn; + + switch (methodForSplit){ + case SPLIT_MAX_PIXELS: comparisonFn = &sumcompare; break; + case SPLIT_MAX_COLORS: comparisonFn = &colcompare; break; + case SPLIT_MAX_SPREAD: comparisonFn = &spreadcompare; break; + } + + qsort((char*) &boxVectorP->box[0], boxVectorP->boxCt, sizeof(struct Box), + comparisonFn); +} + + + +/* +** Here is the fun part, the median-cut colormap generator. This is based +** on Paul Heckbert's paper "Color Image Quantization for Frame Buffer +** Display", SIGGRAPH '82 Proceedings, page 297. +*/ + +static void +findBoxBoundaries(tupletable2 const colorfreqtable, + unsigned int const depth, + unsigned int const boxStart, + unsigned int const boxSize, + sample minval[], + sample maxval[]) { +/*---------------------------------------------------------------------------- + Go through the box finding the minimum and maximum of each component - the + boundaries of the box. +-----------------------------------------------------------------------------*/ + unsigned int plane; + unsigned int i; + + for (plane = 0; plane < depth; ++plane) { + minval[plane] = colorfreqtable.table[boxStart]->tuple[plane]; + maxval[plane] = minval[plane]; + } + + for (i = 1; i < boxSize; ++i) { + unsigned int plane; + for (plane = 0; plane < depth; ++plane) { + sample const v = colorfreqtable.table[boxStart + i]->tuple[plane]; + if (v < minval[plane]) minval[plane] = v; + if (v > maxval[plane]) maxval[plane] = v; + } + } +} + + + +static void +findPlaneWithLargestSpreadByNorm(sample const minval[], + sample const maxval[], + unsigned int const depth, + unsigned int * const planeP, + sample * const spreadP) { + + unsigned int planeWithLargest; + sample largestSpreadSoFar; + unsigned int plane; + + for (plane = 0, largestSpreadSoFar = 0; plane < depth; ++plane) { + + sample const spread = maxval[plane]-minval[plane]; + if (spread > largestSpreadSoFar) { + largestSpreadSoFar = spread; + planeWithLargest = plane; + } + } + *planeP = planeWithLargest; + *spreadP = largestSpreadSoFar; +} + + + +static void +findPlaneWithLargestSpreadByLuminosity(sample const minval[], + sample const maxval[], + unsigned int const depth, + unsigned int * const planeP, + sample * const spreadP) { +/*---------------------------------------------------------------------------- + This subroutine presumes that the tuple type is either + BLACKANDWHITE, GRAYSCALE, or RGB (which implies pamP->depth is 1 or 3). + To save time, we don't actually check it. +-----------------------------------------------------------------------------*/ + if (depth == 1){ + *planeP = 0; + *spreadP = 0; + } else { + /* An RGB tuple */ + unsigned int planeWithLargest; + sample largestSpreadSoFar; + unsigned int plane; + + assert(depth >= 3); + + for (plane = 0, largestSpreadSoFar = 0; plane < 3; ++plane) { + double const spread = + pnm_lumin_factor[plane] * (maxval[plane]-minval[plane]); + if (spread > largestSpreadSoFar) { + largestSpreadSoFar = spread; + planeWithLargest = plane; + } + } + *planeP = planeWithLargest; + *spreadP = largestSpreadSoFar; + } +} + + + +static void +computeBoxSpread(const struct Box * const boxP, + tupletable2 const colorfreqtable, + unsigned int const depth, + enum MethodForLargest const methodForLargest, + unsigned int * const planeWithLargestP, + sample * const spreadP + ) { +/*---------------------------------------------------------------------------- + Find the spread in the dimension in which it is greatest. + + Return as *planeWithLargestP the number of that plane and as *spreadP the + spread in that plane. +-----------------------------------------------------------------------------*/ + sample * minval; /* malloc'ed array */ + sample * maxval; /* malloc'ed array */ + + MALLOCARRAY_NOFAIL(minval, depth); + MALLOCARRAY_NOFAIL(maxval, depth); + + findBoxBoundaries(colorfreqtable, depth, boxP->index, boxP->colorCt, + minval, maxval); + + switch (methodForLargest) { + case LARGE_NORM: + findPlaneWithLargestSpreadByNorm(minval, maxval, depth, + planeWithLargestP, spreadP); + break; + case LARGE_LUM: + findPlaneWithLargestSpreadByLuminosity(minval, maxval, depth, + planeWithLargestP, spreadP); + break; + } + free(minval); free(maxval); +} + + + +static unsigned int +freqTotal(tupletable2 const freqtable) { + + unsigned int i; + unsigned int sum; + + for (i = 0, sum = 0; i < freqtable.size; ++i) + sum += freqtable.table[i]->value; + + return sum; +} + + + +static struct BoxVector +newBoxVector(tupletable2 const colorfreqtable, + unsigned int const capacity, + unsigned int const depth, + enum MethodForLargest const methodForLargest) { + + unsigned int const colorCt = colorfreqtable.size; + unsigned int const sum = freqTotal(colorfreqtable); + + struct BoxVector boxVector; + + MALLOCARRAY(boxVector.box, capacity); + + if (!boxVector.box) + pm_error("out of memory allocating box vector table"); + + /* Set up the initial box. */ + boxVector.box[0].index = 0; + boxVector.box[0].colorCt = colorCt; + boxVector.box[0].sum = sum; + + computeBoxSpread(&boxVector.box[0], colorfreqtable, depth, + methodForLargest, + &boxVector.box[0].maxdim, + &boxVector.box[0].spread); + + boxVector.boxCt = 1; + boxVector.capacity = capacity; + + return boxVector; +} + + + +static void +destroyBoxVector(struct BoxVector const boxVector) { + + free(boxVector.box); +} + + + +static void +centerBox(int const boxStart, + int const boxSize, + tupletable2 const colorfreqtable, + unsigned int const depth, + tuple const newTuple) { + + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + int minval, maxval; + unsigned int i; + + minval = maxval = colorfreqtable.table[boxStart]->tuple[plane]; + + for (i = 1; i < boxSize; ++i) { + int const v = colorfreqtable.table[boxStart + i]->tuple[plane]; + minval = MIN( minval, v); + maxval = MAX( maxval, v); + } + newTuple[plane] = (minval + maxval) / 2; + } +} + + + +static tupletable2 +newColorMap(unsigned int const colorCt, + unsigned int const depth) { + + tupletable2 colormap; + unsigned int i; + struct pam pam; + + pam.depth = depth; + + colormap.table = pnm_alloctupletable(&pam, colorCt); + + for (i = 0; i < colorCt; ++i) { + unsigned int plane; + for (plane = 0; plane < depth; ++plane) + colormap.table[i]->tuple[plane] = 0; + } + colormap.size = colorCt; + + return colormap; +} + + + +static void +averageColors(int const boxStart, + int const boxSize, + tupletable2 const colorfreqtable, + unsigned int const depth, + tuple const newTuple) { + + unsigned int plane; + + for (plane = 0; plane < depth; ++plane) { + sample sum; + int i; + + sum = 0; + + for (i = 0; i < boxSize; ++i) + sum += colorfreqtable.table[boxStart+i]->tuple[plane]; + + newTuple[plane] = ROUNDDIV(sum, boxSize); + } +} + + + +static void +averagePixels(int const boxStart, + int const boxSize, + tupletable2 const colorfreqtable, + unsigned int const depth, + tuple const newTuple) { + + unsigned int n; + /* Number of tuples represented by the box */ + unsigned int plane; + unsigned int i; + + /* Count the tuples in question */ + n = 0; /* initial value */ + for (i = 0; i < boxSize; ++i) + n += colorfreqtable.table[boxStart + i]->value; + + + for (plane = 0; plane < depth; ++plane) { + sample sum; + int i; + + sum = 0; + + for (i = 0; i < boxSize; ++i) + sum += colorfreqtable.table[boxStart+i]->tuple[plane] + * colorfreqtable.table[boxStart+i]->value; + + newTuple[plane] = ROUNDDIV(sum, n); + } +} + + + +static tupletable2 +colormapFromBv(unsigned int const colorCt, + struct BoxVector const boxVector, + tupletable2 const colorfreqtable, + unsigned int const depth, + enum MethodForRep const methodForRep) { + /* + ** Ok, we've got enough boxes. Now choose a representative color for + ** each box. There are a number of possible ways to make this choice. + ** One would be to choose the center of the box; this ignores any structure + ** within the boxes. Another method would be to average all the colors in + ** the box - this is the method specified in Heckbert's paper. A third + ** method is to average all the pixels in the box. + */ + tupletable2 colormap; + unsigned int boxIdx; + + colormap = newColorMap(colorCt, depth); + + for (boxIdx = 0; boxIdx < boxVector.boxCt; ++boxIdx) { + switch (methodForRep) { + case REP_CENTER_BOX: + centerBox(boxVector.box[boxIdx].index, + boxVector.box[boxIdx].colorCt, + colorfreqtable, depth, + colormap.table[boxIdx]->tuple); + break; + case REP_AVERAGE_COLORS: + averageColors(boxVector.box[boxIdx].index, + boxVector.box[boxIdx].colorCt, + colorfreqtable, depth, + colormap.table[boxIdx]->tuple); + break; + case REP_AVERAGE_PIXELS: + averagePixels(boxVector.box[boxIdx].index, + boxVector.box[boxIdx].colorCt, + colorfreqtable, depth, + colormap.table[boxIdx]->tuple); + break; + default: + pm_error("Internal error: invalid value of methodForRep: %d", + methodForRep); + } + } + return colormap; +} + + + +static void +splitBox(struct BoxVector * const boxVectorP, + unsigned int const boxIdx, + tupletable2 const colorfreqtable, + unsigned int const depth, + enum MethodForLargest const methodForLargest, + enum MethodForSplit const methodForSplit) { +/*---------------------------------------------------------------------------- + Split Box 'boxIdx' in the box vector 'boxVector' (so that bv contains one + more box than it did as input). Split it so that each new box represents + about half of the pixels in the distribution given by 'colorfreqtable' for + the colors in the original box, but with distinct colors in each of the two + new boxes. + + Assume the box contains at least two colors. +-----------------------------------------------------------------------------*/ + unsigned int const boxStart = boxVectorP->box[boxIdx].index; + unsigned int const boxSize = boxVectorP->box[boxIdx].colorCt; + unsigned int const sum = boxVectorP->box[boxIdx].sum; + + unsigned int medianIndex; + int lowersum; + /* Number of pixels whose value is "less than" the median */ + + + /* Perhaps this sort should go after creating a box, not before splitting. + Because you need the sort to use the REP_CENTER_BOX method of choosing + a color to represent the final boxes + */ + + /* Set the gross global variable 'compareplanePlane' as a + parameter to compareplane(), which is called by qsort(). + */ + compareplanePlane = boxVectorP->box[boxIdx].maxdim; + qsort((char*) &colorfreqtable.table[boxStart], boxSize, + sizeof(colorfreqtable.table[boxStart]), + compareplane); + + { + /* Find the median based on the counts, so that about half the pixels + (not colors, pixels) are in each subdivision. + */ + unsigned int i; + + lowersum = colorfreqtable.table[boxStart]->value; /* initial value */ + for (i = 1; i < boxSize - 1 && lowersum < sum/2; ++i) { + lowersum += colorfreqtable.table[boxStart + i]->value; + } + medianIndex = i; + } + /* Split the box, and sort to bring the biggest boxes to the top. */ + { + struct Box * const oldBoxP = &boxVectorP->box[boxIdx]; + + oldBoxP->colorCt = medianIndex; + oldBoxP->sum = lowersum; + computeBoxSpread(oldBoxP, colorfreqtable, depth, methodForLargest, + &oldBoxP->maxdim, &oldBoxP->spread); + } + { + struct Box * const newBoxP = &boxVectorP->box[boxVectorP->boxCt]; + + newBoxP->index = boxStart + medianIndex; + newBoxP->colorCt = boxSize - medianIndex; + newBoxP->sum = sum - lowersum; + computeBoxSpread(newBoxP, colorfreqtable, depth, methodForLargest, + &newBoxP->maxdim, &newBoxP->spread); + ++boxVectorP->boxCt; + } + + sortBoxes(boxVectorP, methodForSplit); +} + + + +static void +mediancut(tupletable2 const colorfreqtable, + unsigned int const depth, + int const newcolorCt, + enum MethodForLargest const methodForLargest, + enum MethodForRep const methodForRep, + enum MethodForSplit const methodForSplit, + tupletable2 * const colormapP) { +/*---------------------------------------------------------------------------- + Compute a set of only 'newcolorCt' colors that best represent an + image whose pixels are summarized by the histogram + 'colorfreqtable'. Each tuple in that table has depth 'depth'. + colorfreqtable.table[i] tells the number of pixels in the subject image + have a particular color. + + As a side effect, sort 'colorfreqtable'. +-----------------------------------------------------------------------------*/ + struct BoxVector boxVector; + bool multicolorBoxesExist; + /* There is at least one box that contains at least 2 colors; ergo, + there is more splitting we can do. + */ + + boxVector = newBoxVector(colorfreqtable, newcolorCt, depth, + methodForLargest); + + multicolorBoxesExist = (colorfreqtable.size > 1); + + /* Split boxes until we have enough. */ + while (boxVector.boxCt < newcolorCt && multicolorBoxesExist) { + unsigned int boxIdx; + + for (boxIdx = 0; + boxIdx < boxVector.boxCt && boxVector.box[boxIdx].colorCt < 2; + ++boxIdx); + /* Find the first splittable box. */ + + if (boxIdx >= boxVector.boxCt) + multicolorBoxesExist = FALSE; + else + splitBox(&boxVector, boxIdx, colorfreqtable, depth, + methodForLargest, methodForSplit); + } + *colormapP = colormapFromBv(newcolorCt, boxVector, colorfreqtable, + depth, methodForRep); + + destroyBoxVector(boxVector); +} + + + + +static void +validateCompatibleImage(struct pam * const inpamP, + struct pam * const firstPamP, + unsigned int const imageSeq) { + + if (inpamP->depth != firstPamP->depth) + pm_error("Image %u depth (%u) is not the same as Image 0 (%u)", + imageSeq, inpamP->depth, firstPamP->depth); + if (inpamP->maxval != firstPamP->maxval) + pm_error("Image %u maxval (%u) is not the same as Image 0 (%u)", + imageSeq, + (unsigned)inpamP->maxval, (unsigned)firstPamP->maxval); + if (inpamP->format != firstPamP->format) + pm_error("Image %u format (%d) is not the same as Image 0 (%d)", + imageSeq, inpamP->format, firstPamP->format); + if (!streq(inpamP->tuple_type, firstPamP->tuple_type)) + pm_error("Image %u tuple type (%s) is not the same as Image 0 (%s)", + imageSeq, inpamP->tuple_type, firstPamP->tuple_type); +} + + + +static void +addImageColorsToHash(struct pam * const pamP, + tuplehash const tuplehash, + unsigned int * const colorCountP) { + + tuple * tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(pamP); + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + + pnm_readpamrow(pamP, tuplerow); + + for (col = 0; col < pamP->width; ++col) { + int firstOccurrence; + + pnm_addtuplefreqoccurrence(pamP, tuplerow[col], tuplehash, + &firstOccurrence); + + if (firstOccurrence) + ++(*colorCountP); + } + } + pnm_freepamrow(tuplerow); +} + + + +static void +computeHistogram(FILE * const ifP, + int * const formatP, + struct pam * const freqPamP, + tupletable2 * const colorfreqtableP) { +/*---------------------------------------------------------------------------- + Make a histogram of the colors in the image stream in the file '*ifP'. + + Return as *freqPamP a description of the tuple values in the histogram. + Only the fields of *freqPamP that describe individual tuples are + meaningful (depth, maxval, tuple type); + + As a fringe benefit, also return the format of the input file as + *formatP. +----------------------------------------------------------------------------*/ + unsigned int imageSeq; + struct pam firstPam; + tuplehash tuplehash; + unsigned int colorCount; + int eof; + + pm_message("making histogram..."); + + tuplehash = pnm_createtuplehash(); + colorCount = 0; + + eof = FALSE; + + for (imageSeq = 0; !eof; ++imageSeq) { + struct pam inpam; + + pm_message("Scanning image %u", imageSeq); + + pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); + + if (imageSeq == 0) + firstPam = inpam; + else + validateCompatibleImage(&inpam, &firstPam, imageSeq); + + addImageColorsToHash(&inpam, tuplehash, &colorCount); + + pm_message("%u colors so far", colorCount); + + pnm_nextimage(ifP, &eof); + } + colorfreqtableP->table = + pnm_tuplehashtotable(&firstPam, tuplehash, colorCount); + colorfreqtableP->size = colorCount; + + pnm_destroytuplehash(tuplehash); + + pm_message("%u colors found", colorfreqtableP->size); + + freqPamP->size = sizeof(*freqPamP); + freqPamP->len = PAM_STRUCT_SIZE(tuple_type); + freqPamP->maxval = firstPam.maxval; + freqPamP->bytes_per_sample = pnm_bytespersample(freqPamP->maxval); + freqPamP->depth = firstPam.depth; + STRSCPY(freqPamP->tuple_type, firstPam.tuple_type); + + *formatP = firstPam.format; +} + + + +static void +computeColorMapFromInput(FILE * const ifP, + bool const allColors, + int const reqColors, + enum MethodForLargest const methodForLargest, + enum MethodForRep const methodForRep, + enum MethodForSplit const methodForSplit, + int * const formatP, + struct pam * const freqPamP, + tupletable2 * const colormapP) { +/*---------------------------------------------------------------------------- + Produce a colormap containing the best colors to represent the + image stream in file 'ifP'. Figure it out using the median cut + technique. + + The colormap will have 'reqcolors' or fewer colors in it, unless + 'allcolors' is true, in which case it will have all the colors that + are in the input. + + The colormap has the same maxval as the input. + + Put the colormap in newly allocated storage as a tupletable2 + and return its address as *colormapP. Return the number of colors in + it as *colorsP and its maxval as *colormapMaxvalP. + + Return the characteristics of the input file as + *formatP and *freqPamP. (This information is not really + relevant to our colormap mission; just a fringe benefit). +-----------------------------------------------------------------------------*/ + tupletable2 colorfreqtable; + + computeHistogram(ifP, formatP, freqPamP, &colorfreqtable); + + if (allColors) { + *colormapP = colorfreqtable; + } else { + if (colorfreqtable.size <= reqColors) { + pm_message("Image already has few enough colors (<=%d). " + "Keeping same colors.", reqColors); + *colormapP = colorfreqtable; + } else { + pm_message("choosing %d colors...", reqColors); + mediancut(colorfreqtable, freqPamP->depth, + reqColors, methodForLargest, methodForRep, + methodForSplit, colormapP); + pnm_freetupletable2(freqPamP, colorfreqtable); + } + } +} + + + +static void +sortColormap(tupletable2 const colormap, + sample const depth) { +/*---------------------------------------------------------------------------- + Sort the colormap in place, in order of ascending Plane 0 value, + the Plane 1 value, etc. + + Use insertion sort. +-----------------------------------------------------------------------------*/ + int i; + + pm_message("Sorting %u colors...", colormap.size); + + for (i = 0; i < colormap.size; ++i) { + int j; + for (j = i+1; j < colormap.size; ++j) { + unsigned int plane; + bool iIsGreater, iIsLess; + + iIsGreater = FALSE; iIsLess = FALSE; + for (plane = 0; + plane < depth && !iIsGreater && !iIsLess; + ++plane) { + if (colormap.table[i]->tuple[plane] > + colormap.table[j]->tuple[plane]) + iIsGreater = TRUE; + else if (colormap.table[i]->tuple[plane] < + colormap.table[j]->tuple[plane]) + iIsLess = TRUE; + } + if (iIsGreater) { + for (plane = 0; plane < depth; ++plane) { + sample const temp = colormap.table[i]->tuple[plane]; + colormap.table[i]->tuple[plane] = + colormap.table[j]->tuple[plane]; + colormap.table[j]->tuple[plane] = temp; + } + } + } + } +} + + + +static void +colormapToSquare(struct pam * const pamP, + tupletable2 const colormap, + tuple *** const outputRasterP) { + { + unsigned int const intsqrt = (int)sqrt((float)colormap.size); + if (SQR(intsqrt) == colormap.size) + pamP->width = intsqrt; + else + pamP->width = intsqrt + 1; + } + { + unsigned int const intQuotient = colormap.size / pamP->width; + if (pamP->width * intQuotient == colormap.size) + pamP->height = intQuotient; + else + pamP->height = intQuotient + 1; + } + { + tuple ** outputRaster; + unsigned int row; + unsigned int colormapIndex; + + outputRaster = pnm_allocpamarray(pamP); + + colormapIndex = 0; /* initial value */ + + for (row = 0; row < pamP->height; ++row) { + unsigned int col; + for (col = 0; col < pamP->width; ++col) { + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) { + outputRaster[row][col][plane] = + colormap.table[colormapIndex]->tuple[plane]; + } + if (colormapIndex < colormap.size-1) + ++colormapIndex; + } + } + *outputRasterP = outputRaster; + } +} + + + +static void +colormapToSingleRow(struct pam * const pamP, + tupletable2 const colormap, + tuple *** const outputRasterP) { + + tuple ** outputRaster; + unsigned int col; + + pamP->width = colormap.size; + pamP->height = 1; + + outputRaster = pnm_allocpamarray(pamP); + + for (col = 0; col < pamP->width; ++col) { + int plane; + for (plane = 0; plane < pamP->depth; ++plane) + outputRaster[0][col][plane] = colormap.table[col]->tuple[plane]; + } + *outputRasterP = outputRaster; +} + + + +static void +colormapToImage(int const format, + const struct pam * const colormapPamP, + tupletable2 const colormap, + bool const sort, + bool const square, + struct pam * const outpamP, + tuple *** const outputRasterP) { +/*---------------------------------------------------------------------------- + Create a tuple array and pam structure for an image which includes + one pixel of each of the colors in the colormap 'colormap'. + + May rearrange the contents of 'colormap'. +-----------------------------------------------------------------------------*/ + outpamP->size = sizeof(*outpamP); + outpamP->len = PAM_STRUCT_SIZE(tuple_type); + outpamP->format = format, + outpamP->plainformat = FALSE; + outpamP->depth = colormapPamP->depth; + outpamP->maxval = colormapPamP->maxval; + outpamP->bytes_per_sample = pnm_bytespersample(outpamP->maxval); + STRSCPY(outpamP->tuple_type, colormapPamP->tuple_type); + + if (sort) + sortColormap(colormap, outpamP->depth); + + if (square) + colormapToSquare(outpamP, colormap, outputRasterP); + else + colormapToSingleRow(outpamP, colormap, outputRasterP); +} + + + +int +main(int argc, const char * argv[] ) { + + struct CmdlineInfo cmdline; + FILE * ifP; + int format; + struct pam colormapPam; + struct pam outpam; + tuple ** colormapRaster; + tupletable2 colormap; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileNm); + + computeColorMapFromInput(ifP, + cmdline.allcolors, cmdline.newcolors, + cmdline.methodForLargest, + cmdline.methodForRep, + cmdline.methodForSplit, + &format, &colormapPam, &colormap); + + pm_close(ifP); + + colormapToImage(format, &colormapPam, colormap, + cmdline.sort, cmdline.square, &outpam, &colormapRaster); + + if (cmdline.verbose) + pm_message("Generating %u x %u image", outpam.width, outpam.height); + + outpam.file = stdout; + + pnm_writepam(&outpam, colormapRaster); + + pnm_freetupletable2(&colormapPam, colormap); + + pnm_freepamarray(colormapRaster, &outpam); + + pm_close(stdout); + + return 0; +} + + + diff --git a/urt/Runput.c b/urt/Runput.c index 3bc562a..645a376 100644 --- a/urt/Runput.c +++ b/urt/Runput.c @@ -202,10 +202,11 @@ RunSetup(rle_hdr * the_hdr) if ( the_hdr->background != 0 ) { register int i; - register rle_pixel *background = - (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) ); - register int *bg_color; - /* + register rle_pixel *background; + register int *bg_color; + + overflow_add(the_hdr->ncolors,1); + background = (rle_pixel *)malloc( (unsigned)(the_hdr->ncolors + 1) ); /* * If even number of bg color bytes, put out one more to get to * 16 bit boundary. */ @@ -224,7 +225,7 @@ RunSetup(rle_hdr * the_hdr) /* Big-endian machines are harder */ register int i, nmap = (1 << the_hdr->cmaplen) * the_hdr->ncmap; - register char *h_cmap = (char *)malloc( nmap * 2 ); + register char *h_cmap = (char *)malloc2( nmap, 2 ); if ( h_cmap == NULL ) { fprintf( stderr, diff --git a/urt/rle.h b/urt/rle.h index 0071774..6a905ba 100644 --- a/urt/rle.h +++ b/urt/rle.h @@ -152,6 +152,17 @@ rle_hdr /* End of typedef. */ */ extern rle_hdr rle_dflt_hdr; +/* + * Provided by pm library + */ + +extern void overflow_add(int, int); +#define overflow2(a,b) __overflow2(a,b) +extern void __overflow2(int, int); +extern void overflow3(int, int, int); +extern void *malloc2(int, int); +extern void *malloc3(int, int, int); +extern void *realloc2(void *, int, int); /* Declare RLE library routines. */ diff --git a/urt/rle.h.orig b/urt/rle.h.orig new file mode 100644 index 0000000..59d2670 --- /dev/null +++ b/urt/rle.h.orig @@ -0,0 +1,470 @@ +/* + * This software is copyrighted as noted below. It may be freely copied, + * modified, and redistributed, provided that the copyright notice is + * preserved on all copies. + * + * There is no warranty or other guarantee of fitness for this software, + * it is provided solely "as is". Bug reports or fixes may be sent + * to the author, who may or may not act on them as he desires. + * + * You may not include this software in a program or other software product + * without supplying the source, or without informing the end-user that the + * source is available for no extra charge. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + */ +/* + * rle.h - Global declarations for Utah Raster Toolkit RLE programs. + * + * Author: Todd W. Fuqua + * Computer Science Dept. + * University of Utah + * Date: Sun Jul 29 1984 + * Copyright (c) 1984 Todd W. Fuqua + * + * $Id: rle.h,v 3.0.1.5 1992/04/30 14:05:56 spencer Exp $ + */ + +#ifndef RLE_H +#define RLE_H + +#include /* Declare FILE. */ +#include + +enum rle_dispatch { + NO_DISPATCH = -1, + RUN_DISPATCH = 0 +}; + +/* **************************************************************** + * TAG( rle_pixel rle_map ) + * + * Typedef for 8-bit (or less) pixel data. + * + * Typedef for 16-bit color map data. + */ +typedef unsigned char rle_pixel; +typedef unsigned short rle_map; + +/* + * Defines for traditional channel numbers. + */ +#define RLE_RED 0 /* Red channel traditionally here. */ +#define RLE_GREEN 1 /* Green channel traditionally here. */ +#define RLE_BLUE 2 /* Blue channel traditionally here. */ +#define RLE_ALPHA -1 /* Alpha channel here. */ + +/* + * Return values from rle_get_setup. + */ +#define RLE_SUCCESS 0 +#define RLE_NOT_RLE -1 +#define RLE_NO_SPACE -2 +#define RLE_EMPTY -3 +#define RLE_EOF -4 + +/* + * "Magic" value for is_init field. Pi * 2^29. + */ +#define RLE_INIT_MAGIC 0x6487ED51L + +/* + * TAG( rle_hdr ) + * + * Definition of header structure used by RLE routines. + */ + +#ifndef c_plusplus +typedef +#endif + struct rle_hdr { + enum rle_dispatch dispatch; /* Type of file to create. */ + int ncolors; /* Number of color channels. */ + int * bg_color; /* Pointer to bg color vector. */ + int alpha; /* If !0, save alpha channel. */ + int background; /* 0->just save all pixels, */ + /* 1->overlay, 2->clear to bg first. */ + int xmin; /* Lower X bound (left.) */ + int xmax; /* Upper X bound (right.) */ + int ymin; /* Lower Y bound (bottom.) */ + int ymax; /* Upper Y bound (top.) */ + int ncmap; /* Number of color channels in color map. */ + /* Map only saved if != 0. */ + int cmaplen; /* Log2 of color map length. */ + rle_map * cmap; /* Pointer to color map array. */ + const char ** comments; /* Pointer to array of pointers to comments. */ + FILE * rle_file; /* Input or output file. */ + /* + * Bit map of channels to read/save. Indexed by (channel mod 256). + * Alpha channel sets bit 255. + * + * Indexing (0 <= c <= 255): + * bits[c/8] & (1 << (c%8)) + */ +#define RLE_SET_BIT(glob,bit) \ + ((glob).bits[((bit)&0xff)/8] |= (1<<((bit)&0x7))) +#define RLE_CLR_BIT(glob,bit) \ + ((glob).bits[((bit)&0xff)/8] &= ~(1<<((bit)&0x7))) +#define RLE_BIT(glob,bit) \ + ((glob).bits[((bit)&0xff)/8] & (1<<((bit)&0x7))) + char bits[256/8]; + /* Set to magic pattern if following fields are initialized. */ + /* This gives a 2^(-32) chance of missing. */ + long int is_init; + /* Command, file name and image number for error messages. */ + const char *cmd; + const char *file_name; + int img_num; + /* + * Local storage for rle_getrow & rle_putrow. + * rle_getrow has + * scan_y int current Y scanline. + * vert_skip int number of lines to skip. + * rle_putrow has + * nblank int number of blank lines. + * brun short(*)[2] Array of background runs. + * fileptr long Position in output file. + */ + union { + struct { + int scan_y, + vert_skip; + char is_eof, /* Set when EOF or EofOp encountered. */ + is_seek; /* If true, can seek input file. */ + } get; + struct { + int nblank; + short (*brun)[2]; + long fileptr; + } put; + } priv; + } +#ifndef c_plusplus +rle_hdr /* End of typedef. */ +#endif +; + +/* + * TAG( rle_dflt_hdr ) + * + * Global variable with possibly useful default values. + */ +extern rle_hdr rle_dflt_hdr; + + +/* Declare RLE library routines. */ + +/***************************************************************** + * TAG( rle_get_error ) + * + * Print an error message based on the error code returned by + * rle_get_setup. + */ +extern int rle_get_error( int code, + const char *pgmname, + const char *fname ); + +/* From rle_getrow.c */ + +/***************************************************************** + * TAG( rle_debug ) + * + * Turn RLE debugging on or off. + */ +extern void rle_debug( int on_off ); + +int +rle_get_setup(rle_hdr * const the_hdr); + +/***************************************************************** + * TAG( rle_get_setup_ok ) + * + * Call rle_get_setup. If it returns an error code, call + * rle_get_error to print the error message, then exit with the error + * code. + */ +extern void rle_get_setup_ok( rle_hdr *the_hdr, + const char *prog_name, + const char *file_name); + +/***************************************************************** + * TAG( rle_getrow ) + * + * Read a scanline worth of data from an RLE file. + */ +extern int rle_getrow( rle_hdr * the_hdr, + rle_pixel * scanline[] ); + +/* From rle_getskip.c */ + +/***************************************************************** + * TAG( rle_getskip ) + * Skip a scanline, return the number of the next one. + */ +extern unsigned int rle_getskip( rle_hdr *the_hdr ); + +/* From rle_hdr.c. */ + +/***************************************************************** + * TAG( rle_names ) + * + * Load the command and file names into the rle_hdr. + */ +extern void rle_names( rle_hdr *the_hdr, + const char *pgmname, + const char *fname, + int img_num ); + +/***************************************************************** + * TAG( rle_hdr_cp ) + * + * Make a "safe" copy of a rle_hdr structure. + */ +extern rle_hdr * rle_hdr_cp( rle_hdr *from_hdr, + rle_hdr *to_hdr ); + +/***************************************************************** + * TAG( rle_hdr_init ) + * + * Initialize a rle_hdr structure. + */ +extern rle_hdr * rle_hdr_init( rle_hdr *the_hdr ); + +/***************************************************************** + * TAG( rle_hdr_clear ) + * + */ +extern void rle_hdr_clear( rle_hdr *the_hdr ); + +/* From rle_putrow.c. */ + +/***************************************************************** + * TAG( rgb_to_bw ) + * + * Converts RGB data to gray data via the NTSC Y transform. + */ +extern void rgb_to_bw( rle_pixel *red_row, + rle_pixel *green_row, + rle_pixel *blue_row, + rle_pixel *bw_row, + int rowlen ); + +/***************************************************************** + * TAG( rle_puteof ) + * + * Write an End-of-image opcode to the RLE file. + */ +extern void rle_puteof( rle_hdr *the_hdr ); + +/***************************************************************** + * TAG( rle_putrow ) + * + * Write a scanline of data to the RLE file. + */ +extern void rle_putrow( rle_pixel *rows[], int rowlen, rle_hdr *the_hdr ); + +/***************************************************************** + * TAG( rle_put_init ) + * + * Initialize header for output, but don't write it to the file. + */ +extern void rle_put_init( rle_hdr * the_hdr ); + +/***************************************************************** + * TAG( rle_put_setup ) + * + * Write header information to a new RLE image file. + */ +extern void rle_put_setup( rle_hdr * the_hdr ); + +/***************************************************************** + * TAG( rle_skiprow ) + * + * Skip nrow scanlines in the output file. + */ +extern void rle_skiprow( rle_hdr *the_hdr, int nrow ); + +/* From rle_cp.c */ +/***************************************************************** + * TAG( rle_cp ) + * Copy image data from input to output with minimal interpretation. + */ +extern void rle_cp( rle_hdr *in_hdr, rle_hdr *out_hdr ); + +/* From rle_row_alc.c. */ +/***************************************************************** + * TAG( rle_row_alloc ) + * + * Allocate scanline memory for use by rle_getrow. + */ +extern int rle_row_alloc( rle_hdr * the_hdr, + rle_pixel *** scanp ); + +/***************************************************************** + * TAG( rle_row_free ) + * + * Free the above. + */ +extern void rle_row_free( rle_hdr *the_hdr, rle_pixel **scanp ); + +/* From buildmap.c. */ +/* + * buildmap - build a more usable colormap from data in the_hdr struct. + */ +extern rle_pixel **buildmap( rle_hdr *the_hdr, + int minmap, + double orig_gamma, + double new_gamma ); + +/* From rle_getcom.c. */ +/***************************************************************** + * TAG( rle_getcom ) + * + * Get a specific comment from the image comments. + */ +const char * +rle_getcom(const char * const name, + rle_hdr * const the_hdr); + +/* From rle_putcom.c. */ + +/* Delete a specific comment from the image comments. */ +const char * +rle_delcom(const char * const name, + rle_hdr * const the_hdr); + +/* Put (or replace) a comment into the image comments. */ +const char * +rle_putcom(const char * const value, + rle_hdr * const the_hdr); + +/* From dither.c. */ +/***************************************************************** + * TAG( bwdithermap ) + * Create a color map for ordered dithering in grays. + */ +extern void bwdithermap( int levels, double gamma, int bwmap[], + int divN[256], int modN[256], int magic[16][16] ); +/***************************************************************** + * TAG( ditherbw ) + * Dither a gray-scale value. + */ +extern int ditherbw( int x, int y, int val, + int divN[256], int modN[256], int magic[16][16] ); +/***************************************************************** + * TAG( dithergb ) + * Dither a color value. + */ +extern int dithergb( int x, int y, int r, int g, int b, + int divN[256], int modN[256], int magic[16][16] ); +/***************************************************************** + * TAG( dithermap ) + * Create a color map for ordered dithering in color. + */ +extern void dithermap( int levels, double gamma, int rgbmap[][3], + int divN[256], int modN[256], int magic[16][16] ); +/***************************************************************** + * TAG( make_square ) + * Make a 16x16 magic square for ordered dithering. + */ +extern void make_square( double N, int divN[256], int modN[256], + int magic[16][16] ); + +/* From float_to_exp.c. */ +/***************************************************************** + * TAG( float_to_exp ) + * Convert a list of floating point numbers to "exp" format. + */ +extern void float_to_exp( int count, float * floats, rle_pixel * pixels ); + +/* From rle_open_f.c. */ +/***************************************************************** + * TAG( rle_open_f ) + * + * Open an input/output file with default. + */ +FILE * +rle_open_f(const char * prog_name, const char * file_name, + const char * mode); + +/***************************************************************** + * TAG( rle_open_f_noexit ) + * + * Open an input/output file with default. + */ +FILE * +rle_open_f_noexit(const char * const prog_name, + const char * const file_name, + const char * const mode); + +/***************************************************************** + * TAG( rle_close_f ) + * + * Close a file opened by rle_open_f. If the file is stdin or stdout, + * it will not be closed. + */ +extern void +rle_close_f( FILE *fd ); + +/* From colorquant.c. */ +/***************************************************************** + * TAG( colorquant ) + * Compute a colormap for quantizing an image to a limited set of colors. + */ +extern int colorquant( rle_pixel *red, rle_pixel *green, rle_pixel *blue, + unsigned long pixels, rle_pixel *colormap[3], + int colors, int bits, + rle_pixel *rgbmap, int fast, int otherimages ); + +/* From rle_addhist.c. */ + +/* Append history information to the HISTORY comment. */ +void +rle_addhist(char * argv[], + rle_hdr * const in_hdr, + rle_hdr * const out_hdr); + +/* From cmd_name.c. */ +/***************************************************************** + * TAG( cmd_name ) + * Extract command name from argv. + */ +extern char *cmd_name( char **argv ); + +/* From scanargs.c. */ +/***************************************************************** + * TAG( scanargs ) + * Scan command argument list and parse arguments. + */ +extern int scanargs( int argc, + char **argv, + const char *format, + ... ); + +/* From hilbert.c */ +/***************************************************************** + * TAG( hilbert_i2c ) + * Convert an index into a Hilbert curve to a set of coordinates. + */ +extern void hilbert_c2i( int n, int m, int a[], long int *r ); + +/***************************************************************** + * TAG( hilbert_c2i ) + * Convert coordinates of a point on a Hilbert curve to its index. + */ +extern void hilbert_i2c( int n, int m, long int r, int a[] ); + +/* From inv_cmap.c */ +/***************************************************************** + * TAG( inv_cmap ) + * Compute an inverse colormap efficiently. + */ +extern void inv_cmap( int colors, + unsigned char *colormap[3], + int bits, + unsigned long *dist_buf, + unsigned char *rgbmap ); + +#endif /* RLE_H */ diff --git a/urt/rle_addhist.c b/urt/rle_addhist.c index b165175..e09ed94 100644 --- a/urt/rle_addhist.c +++ b/urt/rle_addhist.c @@ -70,13 +70,18 @@ rle_addhist(char * argv[], return; length = 0; - for (i = 0; argv[i]; ++i) + for (i = 0; argv[i]; ++i) { + overflow_add(length, strlen(argv[i])); + overflow_add(length+1, strlen(argv[i])); length += strlen(argv[i]) +1; /* length of each arg plus space. */ + } time(&temp); timedate = ctime(&temp); length += strlen(timedate); /* length of date and time in ASCII. */ - + overflow_add(strlen(padding), 4); + overflow_add(strlen(histoire), strlen(padding) + 4); + overflow_add(length, strlen(histoire) + strlen(padding) + 4); length += strlen(padding) + 3 + strlen(histoire) + 1; /* length of padding, "on " and length of history name plus "="*/ if (in_hdr) /* if we are interested in the old comments... */ @@ -84,8 +89,10 @@ rle_addhist(char * argv[], else old = NULL; - if (old && *old) + if (old && *old) { + overflow_add(length, strlen(old)); length += strlen(old); /* add length if there. */ + } ++length; /*Cater for the null. */ diff --git a/urt/rle_getrow.c b/urt/rle_getrow.c index ae220f5..39010ba 100644 --- a/urt/rle_getrow.c +++ b/urt/rle_getrow.c @@ -164,6 +164,7 @@ rle_get_setup(rle_hdr * const the_hdr) { char * cp; VAXSHORT(comlen, infile); /* get comment length */ + overflow_add(comlen, 1); evenlen = (comlen + 1) & ~1; /* make it even */ if (evenlen) { MALLOCARRAY(comment_buf, evenlen); diff --git a/urt/rle_getrow.c.orig b/urt/rle_getrow.c.orig new file mode 100644 index 0000000..ae220f5 --- /dev/null +++ b/urt/rle_getrow.c.orig @@ -0,0 +1,520 @@ +/* + * This software is copyrighted as noted below. It may be freely copied, + * modified, and redistributed, provided that the copyright notice is + * preserved on all copies. + * + * There is no warranty or other guarantee of fitness for this software, + * it is provided solely "as is". Bug reports or fixes may be sent + * to the author, who may or may not act on them as he desires. + * + * You may not include this software in a program or other software product + * without supplying the source, or without informing the end-user that the + * source is available for no extra charge. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + * + * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire + * to have all "void" functions so declared. + */ +/* + * rle_getrow.c - Read an RLE file in. + * + * Author: Spencer W. Thomas + * Computer Science Dept. + * University of Utah + * Date: Wed Apr 10 1985 + * Copyright (c) 1985 Spencer W. Thomas + * + * $Id: rle_getrow.c,v 3.0.1.5 1992/03/04 19:33:08 spencer Exp spencer $ + */ + +#include +#include + +#include "netpbm/pm.h" +#include "netpbm/mallocvar.h" + +#include "rle.h" +#include "rle_code.h" +#include "vaxshort.h" + +/* Read a two-byte "short" that started in VAX (LITTLE_ENDIAN) order */ +#define VAXSHORT( var, fp )\ + { var = fgetc(fp)&0xFF; var |= (fgetc(fp)) << 8; } + +/* Instruction format -- first byte is opcode, second is datum. */ + +#define OPCODE(inst) (inst[0] & ~LONG) +#define LONGP(inst) (inst[0] & LONG) +#define DATUM(inst) (inst[1] & 0xff) /* Make sure it's unsigned. */ + +static int debug_f; /* If non-zero, print debug info. */ + +int +rle_get_setup(rle_hdr * const the_hdr) { +/*----------------------------------------------------------------------------- + Read the initialization information from an RLE file. + Inputs: + the_hdr: Contains pointer to the input file. + Outputs: + the_hdr: Initialized with information from the input file. + Returns + 0 on success, + -1 if the file is not an RLE file, + -2 if malloc of the color map failed, + -3 if an immediate EOF is hit (empty input file) + -4 if an EOF is encountered reading the setup information. + Assumptions: + infile points to the "magic" number in an RLE file (usually byte 0 + in the file). + Algorithm: + Read in the setup info and fill in the_hdr. +---------------------------------------------------------------------------- */ + struct XtndRsetup setup; + short magic; + FILE * infile = the_hdr->rle_file; + int i; + char * comment_buf; + + /* Clear old stuff out of the header. */ + rle_hdr_clear(the_hdr); + if (the_hdr->is_init != RLE_INIT_MAGIC) + rle_names(the_hdr, "Urt", "some file", 0); + ++the_hdr->img_num; /* Count images. */ + + VAXSHORT(magic, infile); + if (feof(infile)) + return RLE_EMPTY; + if (magic != RLE_MAGIC) + return RLE_NOT_RLE; + fread(&setup, 1, SETUPSIZE, infile); /* assume VAX packing */ + if (feof( infile)) + return RLE_EOF; + + /* Extract information from setup */ + the_hdr->ncolors = setup.h_ncolors; + for (i = 0; i < the_hdr->ncolors; ++i) + RLE_SET_BIT(*the_hdr, i); + + if (!(setup.h_flags & H_NO_BACKGROUND) && setup.h_ncolors > 0) { + rle_pixel * bg_color; + + MALLOCARRAY(the_hdr->bg_color, setup.h_ncolors); + if (!the_hdr->bg_color) + pm_error("Failed to allocation array for %u background colors", + setup.h_ncolors); + MALLOCARRAY(bg_color, 1 + (setup.h_ncolors / 2) * 2); + if (!bg_color) + pm_error("Failed to allocation array for %u background colors", + 1+(setup.h_ncolors / 2) * 2); + fread((char *)bg_color, 1, 1 + (setup.h_ncolors / 2) * 2, infile); + for (i = 0; i < setup.h_ncolors; ++i) + the_hdr->bg_color[i] = bg_color[i]; + free(bg_color); + } else { + getc(infile); /* skip filler byte */ + the_hdr->bg_color = NULL; + } + + if (setup.h_flags & H_NO_BACKGROUND) + the_hdr->background = 0; + else if (setup.h_flags & H_CLEARFIRST) + the_hdr->background = 2; + else + the_hdr->background = 1; + if (setup.h_flags & H_ALPHA) { + the_hdr->alpha = 1; + RLE_SET_BIT( *the_hdr, RLE_ALPHA ); + } else + the_hdr->alpha = 0; + + the_hdr->xmin = vax_gshort(setup.hc_xpos); + the_hdr->ymin = vax_gshort(setup.hc_ypos); + the_hdr->xmax = the_hdr->xmin + vax_gshort(setup.hc_xlen) - 1; + the_hdr->ymax = the_hdr->ymin + vax_gshort(setup.hc_ylen) - 1; + + the_hdr->ncmap = setup.h_ncmap; + the_hdr->cmaplen = setup.h_cmaplen; + if (the_hdr->ncmap > 0) { + int const maplen = the_hdr->ncmap * (1 << the_hdr->cmaplen); + + int i; + char *maptemp; + + MALLOCARRAY(the_hdr->cmap, maplen); + MALLOCARRAY(maptemp, 2 * maplen); + if (the_hdr->cmap == NULL || maptemp == NULL) { + pm_error("Malloc failed for color map of size %d*%d " + "in rle_get_setup, reading '%s'", + the_hdr->ncmap, (1 << the_hdr->cmaplen), + the_hdr->file_name ); + return RLE_NO_SPACE; + } + fread(maptemp, 2, maplen, infile); + for (i = 0; i < maplen; ++i) + the_hdr->cmap[i] = vax_gshort(&maptemp[i * 2]); + free(maptemp); + } + + /* Check for comments */ + if (setup.h_flags & H_COMMENT) { + short comlen, evenlen; + char * cp; + + VAXSHORT(comlen, infile); /* get comment length */ + evenlen = (comlen + 1) & ~1; /* make it even */ + if (evenlen) { + MALLOCARRAY(comment_buf, evenlen); + + if (comment_buf == NULL) { + pm_error("Malloc failed for comment buffer of size %d " + "in rle_get_setup, reading '%s'", + comlen, the_hdr->file_name ); + return RLE_NO_SPACE; + } + fread(comment_buf, 1, evenlen, infile); + /* Count the comments */ + for (i = 0, cp = comment_buf; cp < comment_buf + comlen; ++cp) + if (*cp == '\0') + ++i; + ++i; /* extra for NULL pointer at end */ + /* Get space to put pointers to comments */ + MALLOCARRAY(the_hdr->comments, i); + if (the_hdr->comments == NULL) { + pm_error("Malloc failed for %d comment pointers " + "in rle_get_setup, reading '%s'", + i, the_hdr->file_name ); + return RLE_NO_SPACE; + } + /* Get pointers to the comments */ + *the_hdr->comments = comment_buf; + for (i = 1, cp = comment_buf + 1; + cp < comment_buf + comlen; + ++cp) + if (*(cp - 1) == '\0') + the_hdr->comments[i++] = cp; + the_hdr->comments[i] = NULL; + } else + the_hdr->comments = NULL; + } else + the_hdr->comments = NULL; + + /* Initialize state for rle_getrow */ + the_hdr->priv.get.scan_y = the_hdr->ymin; + the_hdr->priv.get.vert_skip = 0; + the_hdr->priv.get.is_eof = 0; + the_hdr->priv.get.is_seek = ftell(infile) > 0; + debug_f = 0; + + if (!feof(infile)) + return RLE_SUCCESS; /* success! */ + else { + the_hdr->priv.get.is_eof = 1; + return RLE_EOF; + } +} + + + +void +rle_get_setup_ok(rle_hdr * const the_hdr, + const char * const prog_name, + const char * const file_name) { +/*----------------------------------------------------------------------------- + Read the initialization information from an RLE file. + + Inputs: + the_hdr: Contains pointer to the input file. + prog_name: Program name to be printed in the error message. + file_name: File name to be printed in the error message. + If NULL, the string "stdin" is generated. + + Outputs: + the_hdr: Initialized with information from the input file. + If reading the header fails, it prints an error message + and exits with the appropriate status code. + Algorithm: + rle_get_setup does all the work. +---------------------------------------------------------------------------- */ + int code; + + /* Backwards compatibility: if is_init is not properly set, + * initialize the header. + */ + if (the_hdr->is_init != RLE_INIT_MAGIC) { + FILE * const f = the_hdr->rle_file; + rle_hdr_init( the_hdr ); + the_hdr->rle_file = f; + rle_names(the_hdr, prog_name, file_name, 0); + } + + code = rle_get_error(rle_get_setup(the_hdr), + the_hdr->cmd, the_hdr->file_name); + if (code) + exit(code); +} + + + +void +rle_debug( on_off ) + int on_off; +{ +/*----------------------------------------------------------------------------- + Turn RLE debugging on or off. + Inputs: + on_off: if 0, stop debugging, else start. + Outputs: + Sets internal debug flag. + Assumptions: + [None] + Algorithm: + [None] +---------------------------------------------------------------------------- */ + debug_f = on_off; + + /* Set line buffering on stderr. Character buffering is the default, and + * it is SLOOWWW for large amounts of output. + */ + setvbuf(stderr, NULL, _IOLBF, 0); +} + + + +int +rle_getrow(rle_hdr * const the_hdr, + rle_pixel ** const scanline) { +/*----------------------------------------------------------------------------- + Get a scanline from the input file. + Inputs: + the_hdr: Header structure containing information about + the input file. + Outputs: + scanline: an array of pointers to the individual color + scanlines. Scanline is assumed to have + the_hdr->ncolors pointers to arrays of rle_pixel, + each of which is at least the_hdr->xmax+1 long. + Returns the current scanline number. + Assumptions: + rle_get_setup has already been called. + Algorithm: + If a vertical skip is being executed, and clear-to-background is + specified (the_hdr->background is true), just set the + scanlines to the background color. If clear-to-background is + not set, just increment the scanline number and return. + + Otherwise, read input until a vertical skip is encountered, + decoding the instructions into scanline data. + + If ymax is reached (or, somehow, passed), continue reading and + discarding input until end of image. +---------------------------------------------------------------------------- */ + FILE * const infile = the_hdr->rle_file; + + rle_pixel * scanc; + + int scan_x; /* current X position */ + int max_x; /* End of the scanline */ + int channel; /* current color channel */ + int ns; /* Number to skip */ + int nc; + short word, long_data; + char inst[2]; + + scan_x = the_hdr->xmin; /* initial value */ + max_x = the_hdr->xmax; /* initial value */ + channel = 0; /* initial value */ + /* Clear to background if specified */ + if (the_hdr->background != 1) { + if (the_hdr->alpha && RLE_BIT( *the_hdr, -1)) + memset((char *)scanline[-1] + the_hdr->xmin, 0, + the_hdr->xmax - the_hdr->xmin + 1); + for (nc = 0; nc < the_hdr->ncolors; ++nc) { + if (RLE_BIT( *the_hdr, nc)) { + /* Unless bg color given explicitly, use 0. */ + if (the_hdr->background != 2 || the_hdr->bg_color[nc] == 0) + memset((char *)scanline[nc] + the_hdr->xmin, 0, + the_hdr->xmax - the_hdr->xmin + 1); + else + memset((char *)scanline[nc] + the_hdr->xmin, + the_hdr->bg_color[nc], + the_hdr->xmax - the_hdr->xmin + 1); + } + } + } + + /* If skipping, then just return */ + if (the_hdr->priv.get.vert_skip > 0) { + --the_hdr->priv.get.vert_skip; + ++the_hdr->priv.get.scan_y; + if (the_hdr->priv.get.vert_skip > 0) { + if (the_hdr->priv.get.scan_y >= the_hdr->ymax) { + int const y = the_hdr->priv.get.scan_y; + while (rle_getskip(the_hdr) != 32768) + ; + return y; + } else + return the_hdr->priv.get.scan_y; + } + } + + /* If EOF has been encountered, return also */ + if (the_hdr->priv.get.is_eof) + return ++the_hdr->priv.get.scan_y; + + /* Otherwise, read and interpret instructions until a skipLines + instruction is encountered. + */ + if (RLE_BIT(*the_hdr, channel)) + scanc = scanline[channel] + scan_x; + else + scanc = NULL; + for (;;) { + inst[0] = getc(infile); + inst[1] = getc(infile); + if (feof(infile)) { + the_hdr->priv.get.is_eof = 1; + break; /* <--- one of the exits */ + } + + switch(OPCODE(inst)) { + case RSkipLinesOp: + if (LONGP(inst)) { + VAXSHORT(the_hdr->priv.get.vert_skip, infile); + } else + the_hdr->priv.get.vert_skip = DATUM(inst); + if (debug_f) + pm_message("Skip %d Lines (to %d)", + the_hdr->priv.get.vert_skip, + the_hdr->priv.get.scan_y + + the_hdr->priv.get.vert_skip); + + break; /* need to break for() here, too */ + + case RSetColorOp: + channel = DATUM(inst); /* select color channel */ + if (channel == 255) + channel = -1; + scan_x = the_hdr->xmin; + if (RLE_BIT(*the_hdr, channel)) + scanc = scanline[channel]+scan_x; + if (debug_f) + pm_message("Set color to %d (reset x to %d)", + channel, scan_x ); + break; + + case RSkipPixelsOp: + if (LONGP(inst)) { + VAXSHORT(long_data, infile); + scan_x += long_data; + scanc += long_data; + if (debug_f) + pm_message("Skip %d pixels (to %d)", long_data, scan_x); + } else { + scan_x += DATUM(inst); + scanc += DATUM(inst); + if (debug_f) + pm_message("Skip %d pixels (to %d)", DATUM(inst), scan_x); + } + break; + + case RByteDataOp: + if (LONGP(inst)) { + VAXSHORT(nc, infile); + } else + nc = DATUM(inst); + ++nc; + if (debug_f) { + if (RLE_BIT(*the_hdr, channel)) + pm_message("Pixel data %d (to %d):", nc, scan_x + nc); + else + pm_message("Pixel data %d (to %d)", nc, scan_x + nc); + } + if (RLE_BIT(*the_hdr, channel)) { + /* Don't fill past end of scanline! */ + if (scan_x + nc > max_x) { + ns = scan_x + nc - max_x - 1; + nc -= ns; + } else + ns = 0; + fread((char *)scanc, 1, nc, infile); + while (ns-- > 0) + getc(infile); + if (nc & 0x1) + getc(infile); /* throw away odd byte */ + } else { + if (the_hdr->priv.get.is_seek) + fseek(infile, ((nc + 1) / 2) * 2, 1); + else { + int ii; + for (ii = ((nc + 1) / 2) * 2; ii > 0; --ii) + getc(infile); /* discard it */ + } + } + scanc += nc; + scan_x += nc; + if (debug_f && RLE_BIT(*the_hdr, channel)) { + rle_pixel * cp; + for (cp = scanc - nc; nc > 0; --nc) + fprintf(stderr, "%02x", *cp++); + putc('\n', stderr); + } + break; + + case RRunDataOp: + if (LONGP(inst)) { + VAXSHORT(nc, infile); + } else + nc = DATUM(inst); + ++nc; + scan_x += nc; + + VAXSHORT(word, infile); + if (debug_f) + pm_message("Run length %d (to %d), data %02x", + nc, scan_x, word); + if (RLE_BIT(*the_hdr, channel)) { + if (scan_x > max_x) { + ns = scan_x - max_x - 1; + nc -= ns; + } else + ns = 0; + if (nc >= 10) { /* break point for 785, anyway */ + memset((char *)scanc, word, nc); + scanc += nc; + } else { + for (nc--; nc >= 0; --nc, ++scanc) + *scanc = word; + } + } + break; + + case REOFOp: + the_hdr->priv.get.is_eof = 1; + if (debug_f) + pm_message("End of Image"); + break; + + default: + pm_error("rle_getrow: Unrecognized opcode: %d, reading %s", + inst[0], the_hdr->file_name); + } + if (OPCODE(inst) == RSkipLinesOp || OPCODE(inst) == REOFOp) + break; /* <--- the other loop exit */ + } + + /* If at end, skip the rest of a malformed image. */ + if (the_hdr->priv.get.scan_y >= the_hdr->ymax) { + int const y = the_hdr->priv.get.scan_y; + while (rle_getskip(the_hdr) != 32768 ) + ; + return y; + } + + return the_hdr->priv.get.scan_y; +} + + + diff --git a/urt/rle_hdr.c b/urt/rle_hdr.c index 1edb7a3..d306607 100644 --- a/urt/rle_hdr.c +++ b/urt/rle_hdr.c @@ -148,7 +148,7 @@ rle_hdr_cp(rle_hdr * const fromHdrP, if (toHdrP->cmap) { size_t const size = toHdrP->ncmap * (1 << toHdrP->cmaplen) * sizeof(rle_map); - toHdrP->cmap = malloc(size); + toHdrP->cmap = malloc3(toHdrP->ncmap, 1<cmaplen, sizeof(rle_map)); if (!toHdrP->cmap) pm_error("Failed to allocate memory for %u color maps " "of length %u", toHdrP->ncmap, 1 << toHdrP->cmaplen); @@ -164,11 +164,16 @@ rle_hdr_cp(rle_hdr * const fromHdrP, /* Count the comments. */ for (cp = toHdrP->comments, size = 0; *cp; ++cp) + { + overflow_add(size,1); ++size; + } /* Check if there are really any comments. */ if (size > 0) { + overflow_add(size,1); ++size; /* Copy the NULL pointer, too. */ + overflow2(size, sizeof(char *)); size *= sizeof(char *); toHdrP->comments = malloc(size); if (!toHdrP->comments) diff --git a/urt/rle_hdr.c.orig b/urt/rle_hdr.c.orig new file mode 100644 index 0000000..1edb7a3 --- /dev/null +++ b/urt/rle_hdr.c.orig @@ -0,0 +1,286 @@ +/* + * This software is copyrighted as noted below. It may be freely copied, + * modified, and redistributed, provided that the copyright notice is + * preserved on all copies. + * + * There is no warranty or other guarantee of fitness for this software, + * it is provided solely "as is". Bug reports or fixes may be sent + * to the author, who may or may not act on them as he desires. + * + * You may not include this software in a program or other software product + * without supplying the source, or without informing the end-user that the + * source is available for no extra charge. + * + * If you modify this software, you should include a notice giving the + * name of the person performing the modification, the date of modification, + * and the reason for such modification. + */ +/* + * rle_hdr.c - Functions to manipulate rle_hdr structures. + * + * Author: Spencer W. Thomas + * EECS Dept. + * University of Michigan + * Date: Mon May 20 1991 + * Copyright (c) 1991, University of Michigan + */ + +#include + +#include "nstring.h" +#include "mallocvar.h" + +#include "rle_config.h" +#include "rle.h" + + + +void +rle_names(rle_hdr * const hdrP, + const char * const pgmname, + const char * const fname, + int const imgNum) { +/*---------------------------------------------------------------------------- + * Load program and file names into header. + * Inputs: + * hdrP: Header to modify. + * pgmname: The program name. + * fname: The file name. + * imgNum: Number of the image within the file. + * Outputs: + * *hdrP: Modified header. +-----------------------------------------------------------------------------*/ + + /* Algorithm: + If values previously filled in (by testing is_init field), + free them. Make copies of file name and program name, + modifying file name for standard i/o. Set is_init field. + */ + const char * newFname; + const char * newPgmname; + + /* Mark as filled in. */ + hdrP->is_init = RLE_INIT_MAGIC; + + /* Default file name for stdin/stdout. */ + if (!fname || streq(fname, "-") || strlen(fname) == 0) + newFname = "Standard I/O"; + else + newFname = fname; + + if (pgmname) + newPgmname = pgmname; + else + newPgmname = rle_dflt_hdr.cmd; + + /* Fill in with copies of the strings. */ + if (hdrP->cmd != newPgmname) + hdrP->cmd = pm_strdup(newPgmname); + + if (hdrP->file_name != newFname) + hdrP->cmd = pm_strdup(newFname); + + hdrP->img_num = imgNum; +} + + + +/* Used by rle_hdr_cp and rle_hdr_init to avoid recursion loops. */ +static int noRecurse = 0; + + + +rle_hdr * +rle_hdr_cp(rle_hdr * const fromHdrP, + rle_hdr * const toHdrArgP) { +/*---------------------------------------------------------------------------- + * Make a "safe" copy of a rle_hdr structure. + * Inputs: + * *fromHdrP: Header to be copied. + * Outputs: + * *toHdrPd: Copy of from_hdr, with all memory referred to + * by pointers copied. Also returned as function + * value. If NULL, a static header is used. + * Assumptions: + * It is safe to call rle_hdr_init on *toHdrP. +-----------------------------------------------------------------------------*/ + /* Algorithm: + Initialize *toHdrP, copy *fromHdrP to it, then copy the memory + referred to by all non-null pointers. + */ + static rle_hdr dfltHdr; + rle_hdr * toHdrP; + const char * cmd; + const char * file; + unsigned int num; + + /* Save command, file name, and image number if already initialized. */ + if (toHdrArgP && toHdrArgP->is_init == RLE_INIT_MAGIC) { + cmd = toHdrArgP->cmd; + file = toHdrArgP->file_name; + num = toHdrArgP->img_num; + } else { + cmd = file = NULL; + num = 0; + } + + if (!noRecurse) { + ++noRecurse; + rle_hdr_init(toHdrArgP); + --noRecurse; + } + + toHdrP = toHdrArgP ? toHdrArgP : &dfltHdr; + + *toHdrP = *fromHdrP; + + if (toHdrP->bg_color) { + unsigned int i; + + MALLOCARRAY(toHdrP->bg_color, toHdrP->ncolors); + if (!toHdrP->bg_color) + pm_error("Failed to allocate array for %u background colors", + toHdrP->ncolors); + for (i = 0; i < toHdrP->ncolors; ++i) + toHdrP->bg_color[i] = fromHdrP->bg_color[i]; + } + + if (toHdrP->cmap) { + size_t const size = + toHdrP->ncmap * (1 << toHdrP->cmaplen) * sizeof(rle_map); + toHdrP->cmap = malloc(size); + if (!toHdrP->cmap) + pm_error("Failed to allocate memory for %u color maps " + "of length %u", toHdrP->ncmap, 1 << toHdrP->cmaplen); + memcpy(toHdrP->cmap, fromHdrP->cmap, size); + } + + /* Only copy array of pointers, as the original comment memory + * never gets overwritten. + */ + if (toHdrP->comments) { + unsigned int size; + const char ** cp; + + /* Count the comments. */ + for (cp = toHdrP->comments, size = 0; *cp; ++cp) + ++size; + + /* Check if there are really any comments. */ + if (size > 0) { + ++size; /* Copy the NULL pointer, too. */ + size *= sizeof(char *); + toHdrP->comments = malloc(size); + if (!toHdrP->comments) + pm_error("Failed to allocation %u bytes for comments", size); + memcpy(toHdrP->comments, fromHdrP->comments, size); + } else + toHdrP->comments = NULL; /* Blow off empty comment list. */ + } + + /* Restore the names to their original values. */ + toHdrP->cmd = cmd; + toHdrP->file_name = file; + + /* Lines above mean nothing much happens if cmd and file are != NULL. */ + rle_names(toHdrP, toHdrP->cmd, toHdrP->file_name, num); + + return toHdrP; +} + + + +void +rle_hdr_clear(rle_hdr * const hdrP) { +/*---------------------------------------------------------------------------- + * Clear out the allocated memory pieces of a header. + * + * This routine is intended to be used internally by the library, to + * clear a header before putting new data into it. It clears all the + * fields that would be set by reading in a new image header. + * Therefore, it does not clear the program and file names. + * + * Inputs: + * hdrP: To be cleared. + * Outputs: + * *hdrP: After clearing. + * Assumptions: + * If is_init field is RLE_INIT_MAGIC, the header has been + * properly initialized. This will fail every 2^(-32) times, on + * average. +-----------------------------------------------------------------------------*/ + /* Algorithm: + Free memory and set to zero all pointers, except program and + file name. + */ + + /* Try to free memory. Assume if is_init is properly set that this + * header has been previously initialized, therefore it is safe to + * free memory. + */ + if (hdrP && hdrP->is_init == RLE_INIT_MAGIC) { + if (hdrP->bg_color ) + free(hdrP->bg_color); + hdrP->bg_color = NULL; + if (hdrP->cmap ) + free(hdrP->cmap); + hdrP->cmap = NULL; + /* Unfortunately, we don't know how to free the comment memory. */ + if (hdrP->comments) + free(hdrP->comments); + hdrP->comments = NULL; + } +} + + + +rle_hdr * +rle_hdr_init(rle_hdr * const hdrP) { +/*---------------------------------------------------------------------------- + * Initialize a rle_hdr structure. + * Inputs: + * hdrP: Header to be initialized. + * Outputs: + * *hdrP: Initialized header. + * Assumptions: + * If hdrP->is_init is RLE_INIT_MAGIC, the header has been + * previously initialized. + * If the_hdr is a copy of another rle_hdr structure, the copy + * was made with rle_hdr_cp. +-----------------------------------------------------------------------------*/ + /* Algorithm: + Fill in fields of rle_dflt_hdr that could not be set by the loader + If the_hdr is rle_dflt_hdr, do nothing else + Else: + If hdrP is NULL, return a copy of rle_dflt_hdr in static storage + If hdrP->is_init is RLE_INIT_MAGIC, free all memory + pointed to by non-null pointers. + If this is a recursive call to rle_hdr_init, clear *hdrP and + return hdrP. + Else make a copy of rle_dflt_hdr and return its address. Make the + copy in static storage if hdrP is NULL, and in *hdrP otherwise. + */ + rle_hdr * retval; + + rle_dflt_hdr.rle_file = stdout; + + /* The rest of rle_dflt_hdr is set by the loader's data initialization */ + + if (hdrP == &rle_dflt_hdr) + retval = hdrP; + else { + rle_hdr_clear(hdrP); + + /* Call rle_hdr_cp only if not called from there. */ + if (!noRecurse) { + ++noRecurse; + retval = rle_hdr_cp(&rle_dflt_hdr, hdrP); + --noRecurse; + } else + retval = hdrP; + } + return retval; +} + + + diff --git a/urt/rle_hdr.c.rej b/urt/rle_hdr.c.rej new file mode 100644 index 0000000..62f2fb0 --- /dev/null +++ b/urt/rle_hdr.c.rej @@ -0,0 +1,63 @@ +--- urt/rle_hdr.c ++++ urt/rle_hdr.c +@@ -80,7 +80,10 @@ int img_num; + /* Fill in with copies of the strings. */ + if ( the_hdr->cmd != pgmname ) + { +- char *tmp = (char *)malloc( strlen( pgmname ) + 1 ); ++ char *tmp; ++ ++ overflow_add(strlen(pgmname), 1); ++ tmp = malloc( strlen(pgmname) + 1 ); + RLE_CHECK_ALLOC( pgmname, tmp, 0 ); + strcpy( tmp, pgmname ); + the_hdr->cmd = tmp; +@@ -88,8 +91,10 @@ int img_num; + + if ( the_hdr->file_name != fname ) + { +- char *tmp = (char *)malloc( strlen( fname ) + 1 ); +- RLE_CHECK_ALLOC( pgmname, tmp, 0 ); ++ char *tmp; ++ overflow_add(strlen(fname), 1); ++ tmp = malloc( strlen( fname ) + 1 ); ++ RLE_CHECK_ALLOC( pgmname, tmp, 0 ); + strcpy( tmp, fname ); + the_hdr->file_name = tmp; + } +@@ -153,6 +158,7 @@ rle_hdr *from_hdr, *to_hdr; + if ( to_hdr->bg_color ) + { + int size = to_hdr->ncolors * sizeof(int); ++ overflow2(to_hdr->ncolors, sizeof(int)); + to_hdr->bg_color = (int *)malloc( size ); + RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->bg_color, "background color" ); + memcpy( to_hdr->bg_color, from_hdr->bg_color, size ); +@@ -161,7 +167,7 @@ rle_hdr *from_hdr, *to_hdr; + if ( to_hdr->cmap ) + { + int size = to_hdr->ncmap * (1 << to_hdr->cmaplen) * sizeof(rle_map); +- to_hdr->cmap = (rle_map *)malloc( size ); ++ to_hdr->cmap = (rle_map *)malloc3( to_hdr->ncmap, 1<cmaplen, sizeof(rle_map)); + RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->cmap, "color map" ); + memcpy( to_hdr->cmap, from_hdr->cmap, size ); + } +@@ -173,12 +179,17 @@ rle_hdr *from_hdr, *to_hdr; + { + int size = 0; + CONST_DECL char **cp; +- for ( cp=to_hdr->comments; *cp; cp++ ) ++ for ( cp=to_hdr->comments; *cp; cp++ ) ++ { ++ overflow_add(size, 1); + size++; /* Count the comments. */ ++ } + /* Check if there are really any comments. */ + if ( size ) + { ++ overflow_add(size, 1); + size++; /* Copy the NULL pointer, too. */ ++ overflow2(size, sizeof(char *)); + size *= sizeof(char *); + to_hdr->comments = (CONST_DECL char **)malloc( size ); + RLE_CHECK_ALLOC( to_hdr->cmd, to_hdr->comments, "comments" ); diff --git a/urt/rle_open_f.c b/urt/rle_open_f.c index ae8548b..c2ef37d 100644 --- a/urt/rle_open_f.c +++ b/urt/rle_open_f.c @@ -163,65 +163,7 @@ dealWithSubprocess(const char * const file_name, FILE ** const fpP, bool * const noSubprocessP, const char ** const errorP) { - -#ifdef NO_OPEN_PIPES *noSubprocessP = TRUE; -#else - const char *cp; - - reapChildren(catchingChildrenP, pids); - - /* Real file, not stdin or stdout. If name ends in ".Z", - * pipe from/to un/compress (depending on r/w mode). - * - * If it starts with "|", popen that command. - */ - - cp = file_name + strlen(file_name) - 2; - /* Pipe case. */ - if (file_name[0] == '|') { - pid_t thepid; /* PID from my_popen */ - - *noSubprocessP = FALSE; - - *fpP = my_popen(file_name + 1, mode, &thepid); - if (*fpP == NULL) - *errorP = "%s: can't invoke <<%s>> for %s: "; - else { - /* One more child to catch, eventually. */ - if (*catchingChildrenP < MAX_CHILDREN) - pids[(*catchingChildrenP)++] = thepid; - } - } else if (cp > file_name && *cp == '.' && *(cp + 1) == 'Z' ) { - /* Compress case. */ - pid_t thepid; /* PID from my_popen. */ - const char * command; - - *noSubprocessP = FALSE; - - if (*mode == 'w') - pm_asprintf(&command, "compress > %s", file_name); - else if (*mode == 'a') - pm_asprintf(&command, "compress >> %s", file_name); - else - pm_asprintf(&command, "compress -d < %s", file_name); - - *fpP = my_popen(command, mode, &thepid); - - if (*fpP == NULL) - *errorP = "%s: can't invoke 'compress' program, " - "trying to open %s for %s"; - else { - /* One more child to catch, eventually. */ - if (*catchingChildrenP < MAX_CHILDREN) - pids[(*catchingChildrenP)++] = thepid; - } - pm_strfree(command); - } else { - *noSubprocessP = TRUE; - *errorP = NULL; - } -#endif } diff --git a/urt/rle_putcom.c b/urt/rle_putcom.c index ab2eb20..ce83615 100644 --- a/urt/rle_putcom.c +++ b/urt/rle_putcom.c @@ -98,12 +98,14 @@ rle_putcom(const char * const value, const char * v; const char ** old_comments; int i; - for (i = 2, cp = the_hdr->comments; *cp != NULL; ++i, ++cp) + for (i = 2, cp = the_hdr->comments; *cp != NULL; ++i, ++cp) { + overflow_add(i, 1); if (match(value, *cp) != NULL) { v = *cp; *cp = value; return v; } + } /* Not found */ /* Can't realloc because somebody else might be pointing to this * comments block. Of course, if this were true, then the diff --git a/urt/scanargs.c b/urt/scanargs.c index f3af334..5e114bb 100644 --- a/urt/scanargs.c +++ b/urt/scanargs.c @@ -62,9 +62,8 @@ typedef int *ptr; /* * Storage allocation macros */ -#define NEW( type, cnt ) (type *) malloc( (cnt) * sizeof( type ) ) -#define RENEW( type, ptr, cnt ) (type *) realloc( ptr, (cnt) * sizeof( type ) ) - +#define NEW( type, cnt ) (type *) malloc2( (cnt) , sizeof( type ) ) +#define RENEW( type, ptr, cnt ) (type *) realloc2( ptr, (cnt), sizeof( type ) ) static CONST_DECL char * prformat( CONST_DECL char *, int ); static int isnum( CONST_DECL char *, int, int ); static int _do_scanargs( int argc, char **argv, CONST_DECL char *format,