diff options
Diffstat (limited to 'converter')
-rwxr-xr-x | converter/other/anytopnm | 2 | ||||
-rw-r--r-- | converter/other/giftopnm.c | 35 | ||||
-rw-r--r-- | converter/other/pngtopam.c | 14 | ||||
-rw-r--r-- | converter/other/pnmtopalm/pnmtopalm.c | 6 | ||||
-rw-r--r-- | converter/other/pnmtops.c | 16 | ||||
-rw-r--r-- | converter/pgm/fstopgm.c | 235 | ||||
-rw-r--r-- | converter/ppm/ilbmtoppm.c | 293 | ||||
-rw-r--r-- | converter/ppm/picttoppm.c | 32 | ||||
-rw-r--r-- | converter/ppm/ppmtoarbtxt.c | 1525 | ||||
-rw-r--r-- | converter/ppm/ppmtobmp.c | 14 |
10 files changed, 1440 insertions, 732 deletions
diff --git a/converter/other/anytopnm b/converter/other/anytopnm index acf88136..f3a00793 100755 --- a/converter/other/anytopnm +++ b/converter/other/anytopnm @@ -379,7 +379,7 @@ case "$2" in ;; gif ) - giftopnm "$file" + giftopnm -image=all "$file" ;; tiff ) diff --git a/converter/other/giftopnm.c b/converter/other/giftopnm.c index 9a543532..9f4bc8a1 100644 --- a/converter/other/giftopnm.c +++ b/converter/other/giftopnm.c @@ -1674,6 +1674,28 @@ readImageData(FILE * const ifP, static void +warnUserNotSquare(unsigned int const aspectRatio) { + + const char * baseMsg = + "warning - input pixels are not square, " + "but we are rendering them as square pixels " + "in the output"; + + if (pm_have_float_format()) { + float const r = ((float)aspectRatio + 15.0 ) / 64.0; + + pm_message("%s. To fix the output, run it through " + "'pamscale -%cscale %g'", + baseMsg, + r < 1.0 ? 'x' : 'y', + r < 1.0 ? 1.0 / r : r ); + } else + pm_message("%s", baseMsg); +} + + + +static void readGifHeader(FILE * const gifFileP, struct gifScreen * const gifScreenP) { /*---------------------------------------------------------------------------- @@ -1734,17 +1756,8 @@ readGifHeader(FILE * const gifFileP, } } - if (gifScreenP->AspectRatio != 0 && gifScreenP->AspectRatio != 49) { - float r; - r = ( (float) gifScreenP->AspectRatio + 15.0 ) / 64.0; - pm_message("warning - input pixels are not square, " - "but we are rendering them as square pixels " - "in the output. " - "To fix the output, run it through " - "'pnmscale -%cscale %g'", - r < 1.0 ? 'x' : 'y', - r < 1.0 ? 1.0 / r : r ); - } + if (gifScreenP->AspectRatio != 0 && gifScreenP->AspectRatio != 49) + warnUserNotSquare(gifScreenP->AspectRatio); } diff --git a/converter/other/pngtopam.c b/converter/other/pngtopam.c index e6e68587..59b29f5f 100644 --- a/converter/other/pngtopam.c +++ b/converter/other/pngtopam.c @@ -1243,10 +1243,16 @@ warnNonsquarePixels(struct pngx * const pngxP, (float)pngx_xPixelsPerMeter(pngxP) / pngx_yPixelsPerMeter(pngxP); if (r != 1.0) { - pm_message ("warning - non-square pixels; " - "to fix do a 'pamscale -%cscale %g'", - r < 1.0 ? 'x' : 'y', - r < 1.0 ? 1.0 / r : r ); + const char * const baseMsg = "warning - non-square pixels"; + + if (pm_have_float_format()) + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + r < 1.0 ? 'x' : 'y', + r < 1.0 ? 1.0 / r : r); + else + pm_message("%s", baseMsg); + *errorLevelP = PNMTOPNG_WARNING_LEVEL; } } diff --git a/converter/other/pnmtopalm/pnmtopalm.c b/converter/other/pnmtopalm/pnmtopalm.c index 67a17e54..7740a3ac 100644 --- a/converter/other/pnmtopalm/pnmtopalm.c +++ b/converter/other/pnmtopalm/pnmtopalm.c @@ -33,8 +33,8 @@ struct cmdline_info { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - const char *inputFilespec; /* Filespecs of input files */ - char *transparent; /* -transparent value. Null if unspec */ + const char * inputFilespec; /* Filespecs of input files */ + const char * transparent; /* -transparent value. Null if unspec */ unsigned int depth; /* -depth value. 0 if unspec */ unsigned int maxdepth; /* -maxdepth value. 0 if unspec */ enum compressionType compression; @@ -289,7 +289,7 @@ formatName(int const format) { static void -findTransparentColor(char * const colorSpec, +findTransparentColor(const char * const colorSpec, pixval const newMaxval, bool const directColor, pixval const maxval, diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index 316b7626..cf6b2873 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -1125,6 +1125,19 @@ validateComputableBoundingBox(float const scols, static void +warnUserRescaling(float const scale) { + + const char * const baseMsg = "warning, image too large for page"; + + if (pm_have_float_format()) + pm_message("%s; rescaling to %g", baseMsg, scale); + else + pm_message("%s; rescaling", baseMsg); +} + + + +static void computeImagePosition(int const dpiX, int const dpiY, int const icols, @@ -1231,8 +1244,7 @@ computeImagePosition(int const dpiX, *srowsP = scale * rows * pixfacY; if (scale != requestedScale) - pm_message("warning, image too large for page, rescaling to %g", - scale ); + warnUserRescaling(scale); /* Before May 2001, Pnmtops enforced a 5% margin around the page. If the image would be too big to leave a 5% margin, Pnmtops would diff --git a/converter/pgm/fstopgm.c b/converter/pgm/fstopgm.c index 2c636f41..1f574604 100644 --- a/converter/pgm/fstopgm.c +++ b/converter/pgm/fstopgm.c @@ -12,127 +12,144 @@ #include <string.h> +#include "pm.h" #include "pgm.h" -static int gethexit ARGS(( FILE* ifp )); + + +static int +gethexit(FILE * const ifP) { + + for ( ; ; ) { + unsigned int const i = getc(ifP); + + if (i == EOF) + pm_error("EOF / read error"); + else { + char const c = (char) i; + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else { + /* Ignore - whitespace. */ + } + } + } +} + + + +static void +warnNonsquarePixels(unsigned int const cols, + unsigned int const xcols, + unsigned int const rows, + unsigned int const xrows) { + + const char * const baseMsg = "warning, non-square pixels"; + + if (pm_have_float_format()) { + float const rowratio = (float) xrows / (float) rows; + float const colratio = (float) xcols / (float) cols; + + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + rowratio > colratio ? 'y' : 'x', + rowratio > colratio ? + rowratio / colratio : colratio / rowratio); + } else + pm_message("%s", baseMsg); +} + + int -main( argc, argv ) -int argc; -char *argv[]; - { - FILE *ifp; - register gray **grays, *gP; - int argn, row; - register int col; - int maxval; - int rows = 0, cols = 0, depth = 0, xrows = 0, xcols = 0, xdepth = 0; +main(int argc, const char ** argv) { + + FILE * ifP; + gray ** grays; + int argn; + int row; + gray maxval; + int rows, cols, depth; + int xrows, xcols, xdepth; #define STRSIZE 1000 - char buf[STRSIZE], firstname[STRSIZE], lastname[STRSIZE], email[STRSIZE]; + pm_proginit(&argc, argv); - pgm_init( &argc, argv ); + rows = 0; + cols = 0; + depth = 0; + + xrows = 0; + xcols = 0; + xdepth = 0; argn = 1; - if ( argn < argc ) - { - ifp = pm_openr( argv[argn] ); - argn++; - } - else - ifp = stdin; + if (argn < argc) { + ifP = pm_openr(argv[argn]); + argn++; + } else + ifP = stdin; - if ( argn != argc ) - pm_usage( "[fsfile]" ); + if (argn != argc) + pm_error("Too many arguments. The only argument is the file name"); /* Read the FaceSaver(tm) header. */ - for ( ; ; ) - { - if ( fgets( buf, STRSIZE, ifp ) == (char *) 0 ) - pm_error( "error reading header" ); - - /* Blank line ends header. */ - if ( strlen( buf ) == 1 ) - break; - - if ( sscanf( buf, "FirstName: %[^\n]", firstname ) == 1 ) - ; - else if ( sscanf( buf, "LastName: %[^\n]", lastname ) == 1 ) - ; - else if ( sscanf( buf, "E-mail: %[^\n]", email ) == 1 ) - ; - else if ( sscanf( buf, "PicData: %d %d %d\n", - &cols, &rows, &depth ) == 3 ) - { - if ( depth != 8 ) - pm_error( - "can't handle 'PicData' depth other than 8" ); - } - else if ( sscanf( buf, "Image: %d %d %d\n", - &xcols, &xrows, &xdepth ) == 3 ) - { - if ( xdepth != 8 ) - pm_error( - "can't handle 'Image' depth other than 8" ); - } - } - if ( cols <= 0 || rows <= 0 ) - pm_error( "invalid header" ); - maxval = pm_bitstomaxval( depth ); - if ( maxval > PGM_OVERALLMAXVAL ) - pm_error( "depth %d is too large. Our maximum is %d", - maxval, PGM_OVERALLMAXVAL); - if ( xcols != 0 && xrows != 0 && ( xcols != cols || xrows != rows ) ) - { - float rowratio, colratio; - - rowratio = (float) xrows / (float) rows; - colratio = (float) xcols / (float) cols; - pm_message( - "warning, non-square pixels; to fix do a 'pamscale -%cscale %g'", - rowratio > colratio ? 'y' : 'x', - rowratio > colratio ? rowratio / colratio : colratio / rowratio ); - } - - /* Now read the hex bits. */ - grays = pgm_allocarray( cols, rows ); - for ( row = rows - 1; row >= 0; row--) - { - for ( col = 0, gP = grays[row]; col < cols; col++, gP++ ) - { - *gP = gethexit( ifp ) << 4; - *gP += gethexit( ifp ); - } - } - pm_close( ifp ); - - /* And write out the graymap. */ - pgm_writepgm( stdout, grays, cols, rows, (gray) maxval, 0 ); - pm_close( stdout ); - - exit( 0 ); + for ( ; ; ) { + char buf[STRSIZE]; + char firstname[STRSIZE]; + char lastname[STRSIZE]; + char email[STRSIZE]; + + char * const rc = fgets(buf, STRSIZE, ifP); + + if (rc == NULL) + pm_error("error reading header"); + + /* Blank line ends header. */ + if (strlen(buf) == 1) + break; + + if (sscanf(buf, "FirstName: %[^\n]", firstname) == 1); + else if (sscanf(buf, "LastName: %[^\n]", lastname) == 1); + else if (sscanf(buf, "E-mail: %[^\n]", email ) == 1); + else if (sscanf(buf, "PicData: %d %d %d\n", + &cols, &rows, &depth ) == 3) { + if (depth != 8) + pm_error("can't handle 'PicData' depth other than 8"); + } else if (sscanf(buf, "Image: %d %d %d\n", + &xcols, &xrows, &xdepth ) == 3) { + if (xdepth != 8) + pm_error("can't handle 'Image' depth other than 8"); + } } - -static int -gethexit( ifp ) -FILE *ifp; - { - register int i; - register char c; - - for ( ; ; ) - { - i = getc( ifp ); - if ( i == EOF ) - pm_error( "EOF / read error" ); - c = (char) i; - if ( c >= '0' && c <= '9' ) - return c - '0'; - else if ( c >= 'A' && c <= 'F' ) - return c - 'A' + 10; - else if ( c >= 'a' && c <= 'f' ) - return c - 'a' + 10; - /* Else ignore - whitespace. */ - } + if (cols <= 0 || rows <= 0) + pm_error("invalid header"); + maxval = pm_bitstomaxval(depth); + if (maxval > PGM_OVERALLMAXVAL) + pm_error("depth %d is too large. Our maximum is %d", + maxval, PGM_OVERALLMAXVAL); + if (xcols != 0 && xrows != 0 && (xcols != cols || xrows != rows)) + warnNonsquarePixels(cols, xcols, rows, xrows); + + /* Read the hex bits. */ + grays = pgm_allocarray(cols, rows); + for (row = rows - 1; row >= 0; --row) { + unsigned int col; + for (col = 0; col < cols; ++col) { + grays[row][col] = gethexit(ifP) << 4; + grays[row][col] += gethexit(ifP); + } } + pm_close(ifP); + + pgm_writepgm(stdout, grays, cols, rows, maxval, 0); + pm_close(stdout); + + return 0; +} + diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c index a898d705..662be0b5 100644 --- a/converter/ppm/ilbmtoppm.c +++ b/converter/ppm/ilbmtoppm.c @@ -89,7 +89,7 @@ static unsigned char *ilbmrow; static pixel *pixelrow; static FILE *maskfile = NULL; static bit *maskrow = NULL; -static short wrotemask = 0; +static bool wrotemask; static IFF_ID typeid; /* ID_ILBM, ID_RGBN, ID_RGB8 */ static char *transpName = NULL; /* -transparent option value */ @@ -191,8 +191,8 @@ read_bytes(FILE * const ifP, static unsigned char -get_byte(ifp, iffid, counter) - FILE* ifp; +get_byte(ifP, iffid, counter) + FILE* ifP; IFF_ID iffid; long *counter; { @@ -203,9 +203,9 @@ get_byte(ifp, iffid, counter) pm_error("insufficient data in %s chunk", ID2string(iffid)); --(*counter); } - i = getc(ifp); + i = getc(ifP); if( i == EOF ) - readerr(ifp, iffid); + readerr(ifP, iffid); return (unsigned char) i; } @@ -310,7 +310,7 @@ display_chunk(FILE * const ifP, static void -read_cmap(FILE * const ifp, +read_cmap(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { @@ -320,7 +320,7 @@ read_cmap(FILE * const ifp, colors = chunksize / 3; if( colors == 0 ) { pm_error("warning - empty %s colormap", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { unsigned int i; if( cmap->color ) /* prefer CMAP-chunk over CMYK-chunk */ @@ -330,30 +330,30 @@ read_cmap(FILE * const ifp, for( i = 0; i < colors; ++i ) { int r, g, b; - r = get_byte(ifp, iffid, &chunksize); - g = get_byte(ifp, iffid, &chunksize); - b = get_byte(ifp, iffid, &chunksize); + r = get_byte(ifP, iffid, &chunksize); + g = get_byte(ifP, iffid, &chunksize); + b = get_byte(ifP, iffid, &chunksize); PPM_ASSIGN(cmap->color[i], r, g, b); } - chunk_end(ifp, iffid, chunksize); + chunk_end(ifP, iffid, chunksize); } } static void -read_cmyk(FILE * const ifp, +read_cmyk(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { if( HAS_COLORMAP(cmap) ) { /* prefer RGB color map */ - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { long const colors = chunksize/4; if( colors == 0 ) { pm_error("warning - empty %s colormap", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { unsigned int i; cmap->color = ppm_allocrow(colors); @@ -361,10 +361,10 @@ read_cmyk(FILE * const ifp, for( i = 0; i < colors; ++i ) { int c, m, y, k; - c = get_byte(ifp, iffid, &chunksize); - m = get_byte(ifp, iffid, &chunksize); - y = get_byte(ifp, iffid, &chunksize); - k = get_byte(ifp, iffid, &chunksize); + c = get_byte(ifP, iffid, &chunksize); + m = get_byte(ifP, iffid, &chunksize); + y = get_byte(ifP, iffid, &chunksize); + k = get_byte(ifP, iffid, &chunksize); { pixval const red = @@ -380,7 +380,7 @@ read_cmyk(FILE * const ifp, PPM_ASSIGN(cmap->color[i], red, green, blue); } } - chunk_end(ifp, iffid, chunksize); + chunk_end(ifP, iffid, chunksize); } } } @@ -388,7 +388,7 @@ read_cmyk(FILE * const ifp, static void -read_clut(FILE * const ifp, +read_clut(FILE * const ifP, IFF_ID const iffid, unsigned long const chunksize, ColorMap * const cmap) { @@ -396,19 +396,19 @@ read_clut(FILE * const ifp, if (chunksize != CLUTSize) { pm_message("invalid size for %s chunk - skipping it", ID2string(iffid)); - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { long type; unsigned char * lut; unsigned long remainingChunksize; unsigned int i; - type = get_big_long(ifp, iffid, &remainingChunksize); - get_big_long(ifp, iffid, &remainingChunksize); /* skip reserved fld */ + type = get_big_long(ifP, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); /* skip reserved fld */ MALLOCARRAY_NOFAIL(lut, 256); for( i = 0; i < 256; ++i ) - lut[i] = get_byte(ifp, iffid, &remainingChunksize); + lut[i] = get_byte(ifP, iffid, &remainingChunksize); switch( type ) { case CLUT_MONO: @@ -433,6 +433,27 @@ read_clut(FILE * const ifp, +static void +warnNonsquarePixels(uint8_t const xAspect, + uint8_t const yAspect) { + + if (xAspect != yAspect) { + const char * const baseMsg = "warning - non-square pixels"; + + if (pm_have_float_format()) + pm_message("%s; to fix do a 'pamscale -%cscale %g'", + baseMsg, + xAspect > yAspect ? 'x' : 'y', + xAspect > yAspect ? + (float)xAspect/yAspect : + (float)yAspect/xAspect); + else + pm_message("%s", baseMsg); + } +} + + + static BitMapHeader * read_bmhd(FILE * const ifP, IFF_ID const iffid, @@ -440,7 +461,7 @@ read_bmhd(FILE * const ifP, BitMapHeader * bmhdP; - if( chunksize != BitMapHeaderSize ) { + if (chunksize != BitMapHeaderSize) { pm_message("invalid size for %s chunk - skipping it", ID2string(iffid)); skip_chunk(ifP, iffid, chunksize); @@ -467,24 +488,24 @@ read_bmhd(FILE * const ifP, bmhdP->pageWidth = get_big_short(ifP, iffid, &remainingChunksize); bmhdP->pageHeight = get_big_short(ifP, iffid, &remainingChunksize); - if( verbose ) { - if( typeid == ID_ILBM ) + if (verbose) { + if (typeid == ID_ILBM) pm_message("dimensions: %dx%d, %d planes", bmhdP->w, bmhdP->h, bmhdP->nPlanes); else pm_message("dimensions: %dx%d", bmhdP->w, bmhdP->h); - if( typeid == ID_ILBM || typeid == ID_PBM ) { + if (typeid == ID_ILBM || typeid == ID_PBM) { pm_message("compression: %s", bmhdP->compression <= cmpMAXKNOWN ? cmpNAME[bmhdP->compression] : "unknown"); - switch( bmhdP->masking ) { + switch(bmhdP->masking) { case mskNone: break; case mskHasMask: case mskHasTransparentColor: - if( !maskfile ) + if (!maskfile) pm_message("use '-maskfile <filename>' " "to generate a PBM mask file from %s", mskNAME[bmhdP->masking]); @@ -498,27 +519,20 @@ read_bmhd(FILE * const ifP, } } else /* RGBN/RGB8 */ - if( !maskfile ) + if (!maskfile) pm_message("use '-maskfile <filename>' " "to generate a PBM mask file " "from genlock bits"); } /* fix aspect ratio */ - if( bmhdP->xAspect == 0 || bmhdP->yAspect == 0 ) { + if (bmhdP->xAspect == 0 || bmhdP->yAspect == 0) { pm_message("warning - illegal aspect ratio %d:%d, using 1:1", bmhdP->xAspect, bmhdP->yAspect); bmhdP->xAspect = bmhdP->yAspect = 1; } - if( bmhdP->xAspect != bmhdP->yAspect ) { - pm_message("warning - non-square pixels; " - "to fix do a 'pnmscale -%cscale %g'", - bmhdP->xAspect > bmhdP->yAspect ? 'x' : 'y', - bmhdP->xAspect > bmhdP->yAspect ? - (float)(bmhdP->xAspect)/bmhdP->yAspect : - (float)(bmhdP->yAspect)/bmhdP->xAspect); - } + warnNonsquarePixels(bmhdP->xAspect, bmhdP->yAspect); } return bmhdP; } @@ -627,42 +641,42 @@ decode_mask(FILE * const ifP, unsigned char *ilp; cols = bmhdP->w; - switch( bmhdP->masking ) { + switch (bmhdP->masking) { case mskNone: break; case mskHasMask: /* mask plane */ read_ilbm_plane(ifP, remainingChunksizeP, RowBytes(cols), bmhdP->compression); - if( maskfile ) { + if (maskfile) { ilp = ilbmrow; cbit = 7; - for( col = 0; col < cols; col++, cbit-- ) { - if( cbit < 0 ) { + for (col = 0; col < cols; ++col, --cbit) { + if (cbit < 0) { cbit = 7; - ilp++; + ++ilp; } - if( *ilp & bit_mask[cbit] ) + if (*ilp & bit_mask[cbit]) maskrow[col] = PBM_BLACK; else maskrow[col] = PBM_WHITE; } pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } break; case mskHasTransparentColor: - if( !chunkyrow ) + if (!chunkyrow) pm_error("decode_mask(): chunkyrow == NULL - can't happen"); - if( maskfile ) { - for( col = 0; col < cols; col++ ) { - if( chunkyrow[col] == bmhdP->transparentColor ) + if (maskfile) { + for (col = 0; col < cols; ++col) { + if (chunkyrow[col] == bmhdP->transparentColor) maskrow[col] = PBM_WHITE; else maskrow[col] = PBM_BLACK; } pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } break; case mskLasso: @@ -1031,7 +1045,7 @@ get_color(cmap, idx, red, green, blue) ****************************************************************************/ static void -std_to_ppm(FILE * const ifp, +std_to_ppm(FILE * const ifP, long const chunksize, BitMapHeader * const bmhdP, ColorMap * const cmap, @@ -1040,7 +1054,7 @@ std_to_ppm(FILE * const ifp, static void -ham_to_ppm(FILE * const ifp, +ham_to_ppm(FILE * const ifP, long const chunksize, BitMapHeader * const bmhdP, ColorMap * const cmap, @@ -1063,7 +1077,7 @@ ham_to_ppm(FILE * const ifp, pm_message("%d-plane HAM?? - interpreting image as a normal ILBM", bmhdP->nPlanes); - std_to_ppm(ifp, chunksize, bmhdP, cmap, assumed_viewportmodes); + std_to_ppm(ifP, chunksize, bmhdP, cmap, assumed_viewportmodes); return; } else { unsigned long remainingChunksize; @@ -1107,8 +1121,8 @@ ham_to_ppm(FILE * const ifp, if( HAS_MULTIPALETTE(cmap) ) multi_update(cmap, row); - decode_row(ifp, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP); - decode_mask(ifp, &remainingChunksize, rawrow, bmhdP); + decode_row(ifP, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP); + decode_mask(ifP, &remainingChunksize, rawrow, bmhdP); r = g = b = 0; for( col = 0; col < cols; col++ ) { @@ -1142,7 +1156,7 @@ ham_to_ppm(FILE * const ifp, } ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0); } - chunk_end(ifp, ID_BODY, remainingChunksize); + chunk_end(ifP, ID_BODY, remainingChunksize); } } @@ -1469,46 +1483,54 @@ rgbn_to_ppm(FILE * const ifP, unsigned int const rows = bmhdP->h; unsigned int const cols = bmhdP->w; - int row, col, count, genlock, tries; - pixval r, g, b, maxval; + unsigned int row; + unsigned int count; + pixval maxval; unsigned long remainingChunksize; pixel * transpColorP; pm_message("input is a %d-bit RGB image", (typeid == ID_RGB8 ? 8 : 4)); - if( bmhdP->compression != 4 ) + if (bmhdP->compression != 4) pm_error("invalid compression mode for %s: %d (must be 4)", ID2string(typeid), bmhdP->compression); - - switch( typeid ) { - case ID_RGBN: - if( bmhdP->nPlanes != 13 ) - pm_error("invalid number of planes for %s: %d (must be 13)", - ID2string(typeid), bmhdP->nPlanes); - maxval = lut_maxval(cmap, 15); - break; - case ID_RGB8: - if( bmhdP->nPlanes != 25 ) - pm_error("invalid number of planes for %s: %d (must be 25)", - ID2string(typeid), bmhdP->nPlanes); - maxval = 255; - break; - default: - pm_error("rgbn_to_ppm(): invalid IFF ID %s - can't happen", - ID2string(typeid)); + + switch (typeid) { + case ID_RGBN: + if (bmhdP->nPlanes != 13) + pm_error("invalid number of planes for %s: %d (must be 13)", + ID2string(typeid), bmhdP->nPlanes); + maxval = lut_maxval(cmap, 15); + break; + case ID_RGB8: + if (bmhdP->nPlanes != 25) + pm_error("invalid number of planes for %s: %d (must be 25)", + ID2string(typeid), bmhdP->nPlanes); + maxval = 255; + break; + default: + pm_error("rgbn_to_ppm(): invalid IFF ID %s - can't happen", + ID2string(typeid)); } transpColorP = transpColor(bmhdP, cmap, transpName, maxval); ppm_writeppminit(stdout, cols, rows, maxval, 0); - remainingChunksize = chunksize; /* initial value */ - count = 0; - for( row = 0; row < rows; row++ ) { - for( col = 0; col < cols; col++ ) { + for (row = 0, count = 0, remainingChunksize = chunksize; + row < rows; + ++row) { + + unsigned int col; + + for (col = 0; col < cols; ++col) { + unsigned int tries; + unsigned int genlock; + pixval r, g, b; + tries = 0; - while( !count ) { - if( typeid == ID_RGB8 ) { + while (count == 0) { + if (typeid == ID_RGB8) { r = lookup_red(cmap, get_byte(ifP, ID_BODY, &remainingChunksize)); g = lookup_green(cmap, get_byte(ifP, ID_BODY, @@ -1518,47 +1540,46 @@ rgbn_to_ppm(FILE * const ifP, count = get_byte(ifP, ID_BODY, &remainingChunksize); genlock = count & 0x80; count &= 0x7f; - } - else { - int word; - word = get_big_short(ifP, ID_BODY, &remainingChunksize); + } else { + unsigned int const word = + get_big_short(ifP, ID_BODY, &remainingChunksize); r = lookup_red(cmap, (word & 0xf000) >> 12); g = lookup_green(cmap, (word & 0x0f00) >> 8); b = lookup_blue(cmap, (word & 0x00f0) >> 4); genlock = word & 0x0008; count = word & 0x0007; } - if( !count ) { + if (!count) { count = get_byte(ifP, ID_BODY, &remainingChunksize); - if( !count ) + if (count == 0) count = get_big_short(ifP, ID_BODY, &remainingChunksize); - if( !count ) - ++tries; + if (count == 0) + ++tries; } } - if( tries ) { - pm_message("warning - repeat count 0 at col %d row %d: " - "skipped %d RGB entr%s", + if (tries > 0) { + pm_message("warning - repeat count 0 at col %u row %u: " + "skipped %u RGB entr%s", col, row, tries, (tries == 1 ? "y" : "ies")); } - if( maskfile ) { + if (maskfile) { /* genlock bit set -> transparent */ - if( genlock ) + if (genlock) maskrow[col] = PBM_WHITE; else maskrow[col] = PBM_BLACK; } - if( transpColorP && maskrow && maskrow[col] == PBM_WHITE ) + if (transpColorP && maskrow && maskrow[col] == PBM_WHITE) pixelrow[col] = *transpColorP; else PPM_ASSIGN(pixelrow[col], r, g, b); --count; } ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0); - if( maskfile ) { + if (maskfile) { pbm_writepbmrow(maskfile, maskrow, cols, 0); - wrotemask = 1; + wrotemask = true; } } chunk_end(ifP, ID_BODY, remainingChunksize); @@ -1947,13 +1968,13 @@ PCHG_ConvertBig(PCHGHeader * const PCHG, static void -read_pchg(FILE * const ifp, +read_pchg(FILE * const ifP, IFF_ID const iffid, long const chunksize, ColorMap * const cmap) { if( cmap->mp_type >= MP_TYPE_PCHG ) { - skip_chunk(ifp, iffid, chunksize); + skip_chunk(ifP, iffid, chunksize); } else { PCHGHeader PCHG; unsigned char *data; @@ -1967,15 +1988,15 @@ read_pchg(FILE * const ifp, remainingChunksize = chunksize; /* initial value */ - PCHG.Compression = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.Flags = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.StartLine = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.LineCount = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.ChangedLines= get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MinReg = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MaxReg = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.MaxChanges = get_big_short(ifp, iffid, &remainingChunksize); - PCHG.TotalChanges= get_big_long(ifp, iffid, &remainingChunksize); + PCHG.Compression = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.Flags = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.StartLine = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.LineCount = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.ChangedLines= get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MinReg = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MaxReg = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.MaxChanges = get_big_short(ifP, iffid, &remainingChunksize); + PCHG.TotalChanges= get_big_long(ifP, iffid, &remainingChunksize); #ifdef DEBUG pm_message("PCHG StartLine : %d", PCHG.StartLine); @@ -1990,17 +2011,17 @@ read_pchg(FILE * const ifp, long treesize, compsize; CompHdr.CompInfoSize = - get_big_long(ifp, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); CompHdr.OriginalDataSize = - get_big_long(ifp, iffid, &remainingChunksize); + get_big_long(ifP, iffid, &remainingChunksize); treesize = CompHdr.CompInfoSize; MALLOCARRAY_NOFAIL(comptree, treesize); - read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize); + read_bytes(ifP, treesize, comptree, iffid, &remainingChunksize); compsize = remainingChunksize; MALLOCARRAY_NOFAIL(compdata, compsize); - read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize); + read_bytes(ifP, compsize, compdata, iffid, &remainingChunksize); datasize = CompHdr.OriginalDataSize; MALLOCARRAY_NOFAIL(data, datasize); @@ -2015,7 +2036,7 @@ read_pchg(FILE * const ifp, #endif datasize = remainingChunksize; MALLOCARRAY_NOFAIL(data, datasize); - read_bytes(ifp, datasize, data, iffid, &remainingChunksize); + read_bytes(ifP, datasize, data, iffid, &remainingChunksize); } if( PCHG.Flags & PCHGF_USE_ALPHA ) @@ -2054,7 +2075,7 @@ read_pchg(FILE * const ifp, ID2string(iffid)); } free(data); - chunk_end(ifp, iffid, remainingChunksize); + chunk_end(ifP, iffid, remainingChunksize); } } @@ -2079,7 +2100,7 @@ ignored_iffid(IFF_ID const iffid, static void -process_body( FILE * const ifp, +process_body( FILE * const ifP, long const chunksize, BitMapHeader * const bmhdP, ColorMap * const cmap, @@ -2089,19 +2110,19 @@ process_body( FILE * const ifp, DirectColor * const dcol, int * const viewportmodesP) { - if( bmhdP == NULL ) + if (bmhdP == NULL) pm_error("%s chunk without %s chunk", ID2string(ID_BODY), ID2string(ID_BMHD)); prepareCmap(bmhdP, cmap); pixelrow = ppm_allocrow(bmhdP->w); - if( maskfile ) { + if (maskfile) { maskrow = pbm_allocrow(bmhdP->w); pbm_writepbminit(maskfile, bmhdP->w, bmhdP->h, 0); } - if( typeid == ID_ILBM ) { + if (typeid == ID_ILBM) { int isdeep; MALLOCARRAY_NOFAIL(ilbmrow, RowBytes(bmhdP->w)); @@ -2115,27 +2136,27 @@ process_body( FILE * const ifp, } else isdeep = isdeepopt; - if( isdeep > 0 ) - deep_to_ppm(ifp, chunksize, bmhdP, cmap); - else if( dcol ) - dcol_to_ppm(ifp, chunksize, bmhdP, cmap, dcol); - else if( bmhdP->nPlanes > 8 ) { - if( bmhdP->nPlanes <= 16 && HAS_COLORMAP(cmap) ) - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); - else if( isdeep >= 0 && (bmhdP->nPlanes % 3 == 0) ) - deep_to_ppm(ifp, chunksize, bmhdP, cmap); - else if( bmhdP->nPlanes <= 16 ) + if (isdeep > 0) + deep_to_ppm(ifP, chunksize, bmhdP, cmap); + else if (dcol) + dcol_to_ppm(ifP, chunksize, bmhdP, cmap, dcol); + else if (bmhdP->nPlanes > 8) { + if (bmhdP->nPlanes <= 16 && HAS_COLORMAP(cmap)) + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); + else if (isdeep >= 0 && (bmhdP->nPlanes % 3 == 0)) + deep_to_ppm(ifP, chunksize, bmhdP, cmap); + else if (bmhdP->nPlanes <= 16) /* will be interpreted as grayscale */ - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); else pm_error("don't know how to interpret %d-plane image", bmhdP->nPlanes); } else - std_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); } else if( typeid == ID_PBM ) - ipbm_to_ppm(ifp, chunksize, bmhdP, cmap, *viewportmodesP); + ipbm_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP); else /* RGBN or RGB8 */ - rgbn_to_ppm(ifp, chunksize, bmhdP, cmap); + rgbn_to_ppm(ifP, chunksize, bmhdP, cmap); } @@ -2407,6 +2428,8 @@ main(int argc, char *argv[]) { if( argn != argc ) pm_usage(usage); + wrotemask = false; /* initial value */ + /* Read in the ILBM file. */ firstIffid = get_big_long(ifP, ID_FORM, NULL); diff --git a/converter/ppm/picttoppm.c b/converter/ppm/picttoppm.c index 43b8d1ef..828d5270 100644 --- a/converter/ppm/picttoppm.c +++ b/converter/ppm/picttoppm.c @@ -1200,7 +1200,7 @@ doDiffSize(struct Rect const clipsrc, unsigned int const dstadd = dstwid - xsize; - FILE * pnmscalePipeP; + FILE * pamscalePipeP; const char * command; FILE * scaled; int cols, rows, format; @@ -1221,19 +1221,19 @@ doDiffSize(struct Rect const clipsrc, pm_close(tempFileP); - pm_asprintf(&command, "pnmscale -xsize %d -ysize %d > %s", + pm_asprintf(&command, "pamscale -xsize %d -ysize %d > %s", rectwidth(&clipdst), rectheight(&clipdst), tempFilename); pm_message("running command '%s'", command); - pnmscalePipeP = popen(command, "w"); - if (pnmscalePipeP == NULL) + pamscalePipeP = popen(command, "w"); + if (pamscalePipeP == NULL) pm_error("cannot execute command '%s' popen() errno = %s (%d)", command, strerror(errno), errno); pm_strfree(command); - fprintf(pnmscalePipeP, "P6\n%d %d\n%d\n", + fprintf(pamscalePipeP, "P6\n%d %d\n%d\n", rectwidth(&clipsrc), rectheight(&clipsrc), PPM_MAXMAXVAL); switch (pixSize) { @@ -1245,9 +1245,9 @@ doDiffSize(struct Rect const clipsrc, for (colNumber = 0; colNumber < xsize; ++colNumber) { unsigned int const colorIndex = row[colNumber]; struct RGBColor * const ct = &color_map[colorIndex]; - fputc(redepth(ct->red, 65535L), pnmscalePipeP); - fputc(redepth(ct->grn, 65535L), pnmscalePipeP); - fputc(redepth(ct->blu, 65535L), pnmscalePipeP); + fputc(redepth(ct->red, 65535L), pamscalePipeP); + fputc(redepth(ct->grn, 65535L), pamscalePipeP); + fputc(redepth(ct->blu, 65535L), pamscalePipeP); } } } @@ -1259,9 +1259,9 @@ doDiffSize(struct Rect const clipsrc, unsigned int colNumber; for (colNumber = 0; colNumber < xsize; ++colNumber) { struct RGBColor const color = decode16(&row[colNumber * 2]); - fputc(redepth(color.red, 32), pnmscalePipeP); - fputc(redepth(color.grn, 32), pnmscalePipeP); - fputc(redepth(color.blu, 32), pnmscalePipeP); + fputc(redepth(color.red, 32), pamscalePipeP); + fputc(redepth(color.grn, 32), pamscalePipeP); + fputc(redepth(color.blu, 32), pamscalePipeP); } } } @@ -1278,17 +1278,17 @@ doDiffSize(struct Rect const clipsrc, unsigned int colNumber; for (colNumber = 0; colNumber < xsize; ++colNumber) { - fputc(redepth(redPlane[colNumber], 256), pnmscalePipeP); - fputc(redepth(grnPlane[colNumber], 256), pnmscalePipeP); - fputc(redepth(bluPlane[colNumber], 256), pnmscalePipeP); + fputc(redepth(redPlane[colNumber], 256), pamscalePipeP); + fputc(redepth(grnPlane[colNumber], 256), pamscalePipeP); + fputc(redepth(bluPlane[colNumber], 256), pamscalePipeP); } } } break; } - if (pclose(pnmscalePipeP)) - pm_error("pnmscale failed. pclose() returned Errno %s (%d)", + if (pclose(pamscalePipeP)) + pm_error("pamscale failed. pclose() returned Errno %s (%d)", strerror(errno), errno); ppm_readppminit(scaled = pm_openr(tempFilename), &cols, &rows, diff --git a/converter/ppm/ppmtoarbtxt.c b/converter/ppm/ppmtoarbtxt.c index df859c84..569f5ea2 100644 --- a/converter/ppm/ppmtoarbtxt.c +++ b/converter/ppm/ppmtoarbtxt.c @@ -1,4 +1,4 @@ -/* ppmtoarbtxt.c - convert portable pixmap to cleartext +/* ppmtoarbtxt.c - convert PPM to a custom text-based format ** ** Renamed from ppmtotxt.c by Bryan Henderson in January 2003. ** @@ -12,51 +12,150 @@ ** implied warranty. */ +#include <assert.h> #include <string.h> +#ifdef __GLIBC__ + #include <printf.h> /* Necessary for parse_printf_format() */ +#endif -#include "ppm.h" #include "mallocvar.h" #include "nstring.h" +#include "shhopt.h" +#include "ppm.h" + +/* HAVE_PARSE_PRINTF_FORMAT means the system library has + parse_printf_format(), declared in <printf.h>. This essentially means + systems with GNU libc. +*/ + +#ifndef HAVE_PARSE_PRINTF_FORMAT + #ifdef PA_FLAG_MASK /* Defined in printf.h */ + #define HAVE_PARSE_PRINTF_FORMAT 1 + #else + #define HAVE_PARSE_PRINTF_FORMAT 0 + #endif +#endif + + + +struct CmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + const char * inputFileName; + const char * bodySklFileName; + const char * hd; + const char * tl; + unsigned int debug; +}; + + + +static void +parseCommandLine(int argc, const char ** argv, + struct CmdlineInfo * const cmdlineP) { +/*---------------------------------------------------------------------------- + Note that many of the strings that this function returns in the + *cmdline_p structure are actually in the supplied argv array. And + sometimes, one of these strings is actually just a suffix of an entry + in argv! +-----------------------------------------------------------------------------*/ + optEntry * option_def; + /* Instructions to OptParseOptions3 on how to parse our options. + */ + optStruct3 opt; + + unsigned int hdSpec, tlSpec; + + unsigned int option_def_index; + + MALLOCARRAY(option_def, 100); + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "hd", OPT_STRING, &cmdlineP->hd, + &hdSpec, 0); + OPTENT3(0, "tl", OPT_STRING, &cmdlineP->tl, + &tlSpec, 0); + OPTENT3(0, "debug", OPT_FLAG, NULL, + &cmdlineP->debug, 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); + free(option_def); + + if (!hdSpec) + cmdlineP->hd = NULL; + + if (!tlSpec) + cmdlineP->tl = NULL; + + if (argc-1 < 1) + pm_error("You must specify the body skeleton file name as an " + "argument"); + else { + cmdlineP->bodySklFileName = strdup(argv[1]); + + if (argc-1 < 2) + cmdlineP->inputFileName = strdup("-"); /* he wants stdin */ + else { + cmdlineP->inputFileName = strdup(argv[2]); + if (argc-1 > 2) + pm_error("Too many arguments. The only possible arguments " + "are the body skeleton file name and input image " + "file name"); + } + } +} + + + typedef enum { /* The types of object we handle */ BDATA, IRED, IGREEN, IBLUE, ILUM, FRED, FGREEN, FBLUE, FLUM, WIDTH, HEIGHT, POSX, POSY -} SKL_OBJ_TYP; +} SkeletonObjectType; typedef enum { OBJTYP_ICOLOR, OBJTYP_FCOLOR, OBJTYP_INT, OBJTYP_BDATA -} SKL_OBJ_CLASS; +} SkeletonObjectClass; /* Maximum size for a format string ("%d" etc.) */ +/* Add one to this size for the terminating '\0'. */ #define MAXFORMAT 16 +typedef union { /* The data we keep for each object */ -typedef union - { - struct BNDAT { char *bdat; /* Binary data (text with newlines etc.) */ - int ndat; - } bin_data; - - struct ICDAT { char icformat[MAXFORMAT]; /* Integer colors */ - int icolmin, icolmax; - } icol_data; - - struct FCDAT { char fcformat[MAXFORMAT]; /* Float colors */ - double fcolmin, fcolmax; - } fcol_data; - - struct IDAT { char iformat[MAXFORMAT]; /* Integer data */ - } i_data; - } SKL_OBJ_DATA; + struct Bndat { + char * bdat; /* Binary data (text with newlines etc.) */ + unsigned int ndat; + } binData; + + struct Icdat { + char icformat[MAXFORMAT+1]; /* Integer colors */ + unsigned int icolmin, icolmax; + } icolData; + + struct Fcdat { + char fcformat[MAXFORMAT+1]; /* Float colors */ + double fcolmin, fcolmax; + } fcolData; + + struct Idat { + char iformat[MAXFORMAT+1]; /* Integer data */ + } iData; +} SkeletonObjectData; /* Each object has a type and some data */ -typedef struct - { - SKL_OBJ_TYP otyp; - SKL_OBJ_DATA odata; - } SKL_OBJ; +typedef struct { + SkeletonObjectType objType; + SkeletonObjectData odata; +} SkeletonObject; + #define MAX_SKL_HEAD_OBJ 64 @@ -66,199 +165,164 @@ typedef struct #define MAX_OBJ_BUF 80 -static void write_txt (fout, nobj, obj, width, height, x, y, red, green, blue) -FILE *fout; -int nobj; -SKL_OBJ *obj[]; -int width, height, x, y; -double red, green, blue; - -{register int count; - -#define WRITE_BNDAT(fd,theobj) \ - {struct BNDAT *bdata = &((theobj)->odata.bin_data); \ - fwrite (bdata->bdat,bdata->ndat,1,fd); } - -#define WRITE_ICOL(fd,theobj,thecol) \ - {struct ICDAT *icdata = &((theobj)->odata.icol_data); \ - fprintf (fd,icdata->icformat,(int)(icdata->icolmin \ - + (icdata->icolmax - icdata->icolmin)*(thecol))); } - -#define WRITE_FCOL(fd,theobj,thecol) \ - {struct FCDAT *fcdata = &((theobj)->odata.fcol_data); \ - fprintf (fd,fcdata->fcformat,(double)(fcdata->fcolmin \ - + (fcdata->fcolmax - fcdata->fcolmin)*(thecol))); } - -#define WRITE_IDAT(fd,theobj,thedat) \ - {struct IDAT *idata = &((theobj)->odata.i_data); \ - fprintf (fd,idata->iformat,thedat); } - - for (count = 0; count < nobj; count++) - { - switch (obj[count]->otyp) - { - case BDATA: - WRITE_BNDAT (fout,obj[count]); - break; - case IRED: - WRITE_ICOL (fout,obj[count],red); - break; - case IGREEN: - WRITE_ICOL (fout,obj[count],green); - break; - case IBLUE: - WRITE_ICOL (fout,obj[count],blue); - break; - case ILUM: - WRITE_ICOL (fout,obj[count],0.299*red+0.587*green+0.114*blue); - break; - case FRED: - WRITE_FCOL (fout,obj[count],red); - break; - case FGREEN: - WRITE_FCOL (fout,obj[count],green); - break; - case FBLUE: - WRITE_FCOL (fout,obj[count],blue); - break; - case FLUM: - WRITE_FCOL (fout,obj[count],0.299*red+0.587*green+0.114*blue); - break; - case WIDTH: - WRITE_IDAT (fout,obj[count],width); - break; - case HEIGHT: - WRITE_IDAT (fout,obj[count],height); - break; - case POSX: - WRITE_IDAT (fout,obj[count],x); - break; - case POSY: - WRITE_IDAT (fout,obj[count],y); - break; - } - } -} +static void +dumpSkeleton(SkeletonObject ** const skeletonPList, + unsigned int const nSkeleton) { -static SKL_OBJ * -save_bin_data(int const ndat, - char * const bdat) { + unsigned int i; - /* Save binary data in Object */ + pm_message("%u objects", nSkeleton); - SKL_OBJ *obj; + for (i = 0; i < nSkeleton; ++i) { + SkeletonObject * const skeletonP = skeletonPList[i]; - obj = (SKL_OBJ *)malloc (sizeof (SKL_OBJ) + ndat); - if (obj != NULL) - { - obj->otyp = BDATA; - obj->odata.bin_data.ndat = ndat; - obj->odata.bin_data.bdat = ((char *)(obj))+sizeof (SKL_OBJ); - memcpy (obj->odata.bin_data.bdat,bdat,ndat); + pm_message(" Object: Type %u", skeletonP->objType); } - return (obj); } -static SKL_OBJ * -save_icol_data(SKL_OBJ_TYP const ctyp, - const char * const format, - int const icolmin, - int const icolmax) { -/* Save integer color data in Object */ - - SKL_OBJ * objP; - - MALLOCVAR(objP); - - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.icol_data.icformat, format); - objP->odata.icol_data.icolmin = icolmin; - objP->odata.icol_data.icolmax = icolmax; - } - return objP; +static void +dumpAllSkeleton(SkeletonObject ** const bodySkeletonPList, + unsigned int const bodyNskl, + SkeletonObject ** const headSkeletonPList, + unsigned int const headNskl, + SkeletonObject ** const tailSkeletonPList, + unsigned int const tailNskl) { + + pm_message("Body skeleton:"); + dumpSkeleton(bodySkeletonPList, bodyNskl); + + pm_message("Head skeleton:"); + dumpSkeleton(headSkeletonPList, headNskl); + + pm_message("Tail skeleton:"); + dumpSkeleton(tailSkeletonPList, tailNskl); } -static SKL_OBJ * -save_fcol_data(SKL_OBJ_TYP const ctyp, - const char * const format, - double const fcolmin, - double const fcolmax) { -/* Save float color data in Object */ - - SKL_OBJ * objP; +static void +writeBndat(FILE * const ofP, + SkeletonObject * const objectP) { - MALLOCVAR(objP); + struct Bndat * const bdataP = &objectP->odata.binData; - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.fcol_data.fcformat, format); - objP->odata.fcol_data.fcolmin = fcolmin; - objP->odata.fcol_data.fcolmax = fcolmax; - } - return objP; + fwrite(bdataP->bdat, bdataP->ndat, 1, ofP); } -static SKL_OBJ * -save_i_data(SKL_OBJ_TYP const ctyp, - const char * const format) { +static void +writeIcol(FILE * const ofP, + SkeletonObject * const objectP, + double const value) { + + struct Icdat * const icdataP = &objectP->odata.icolData; + + fprintf(ofP, icdataP->icformat, + (unsigned int) + (icdataP->icolmin + + (icdataP->icolmax - icdataP->icolmin) * value)); +} -/* Save universal data in Object */ - SKL_OBJ * objP; - MALLOCVAR(objP); - if (objP) { - objP->otyp = ctyp; - strcpy(objP->odata.i_data.iformat, format); - } - return objP; +static void +writeFcol(FILE * const ofP, + SkeletonObject * const objectP, + double const value) { + + struct Fcdat * const fcdataP = &objectP->odata.fcolData; + + fprintf(ofP, fcdataP->fcformat, + (double) + (fcdataP->fcolmin + + (fcdataP->fcolmax - fcdataP->fcolmin) * value)); } -static char const escape = '#'; +static void +writeIdat(FILE * const ofP, + SkeletonObject * const objectP, + unsigned int const value) { + + struct Idat * const idataP = &objectP->odata.iData; + + fprintf(ofP, idataP->iformat, value); +} -static SKL_OBJ_TYP -interpretObjType(const char * const typstr) { +static void +writeText(FILE * const ofP, + unsigned int const nObj, + SkeletonObject ** const obj, + unsigned int const width, + unsigned int const height, + unsigned int const x, + unsigned int const y, + double const red, + double const green, + double const blue) { + + unsigned int i; - SKL_OBJ_TYP otyp; - - /* Check for integer colors */ - if (streq(typstr, "ired") ) otyp = IRED; - else if (streq(typstr, "igreen")) otyp = IGREEN; - else if (streq(typstr, "iblue") ) otyp = IBLUE; - else if (streq(typstr, "ilum") ) otyp = ILUM; - /* Check for real colors */ - else if (streq(typstr, "fred") ) otyp = FRED; - else if (streq(typstr, "fgreen")) otyp = FGREEN; - else if (streq(typstr, "fblue") ) otyp = FBLUE; - else if (streq(typstr, "flum") ) otyp = FLUM; - /* Check for integer data */ - else if (streq(typstr, "width") ) otyp = WIDTH; - else if (streq(typstr, "height")) otyp = HEIGHT; - else if (streq(typstr, "posx") ) otyp = POSX; - else if (streq(typstr, "posy") ) otyp = POSY; - else otyp = BDATA; - - return otyp; + for (i = 0; i < nObj; ++i) { + switch (obj[i]->objType) { + case BDATA: + writeBndat(ofP, obj[i]); + break; + case IRED: + writeIcol(ofP, obj[i], red); + break; + case IGREEN: + writeIcol(ofP, obj[i], green); + break; + case IBLUE: + writeIcol(ofP, obj[i], blue); + break; + case ILUM: + writeIcol(ofP, obj[i], + PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue); + break; + case FRED: + writeFcol(ofP, obj[i], red); + break; + case FGREEN: + writeFcol(ofP, obj[i], green); + break; + case FBLUE: + writeFcol(ofP, obj[i], blue); + break; + case FLUM: + writeFcol(ofP, obj[i], + PPM_LUMINR*red + PPM_LUMING*green + PPM_LUMINB*blue); + break; + case WIDTH: + writeIdat(ofP, obj[i], width); + break; + case HEIGHT: + writeIdat(ofP, obj[i], height); + break; + case POSX: + writeIdat(ofP, obj[i], x); + break; + case POSY: + writeIdat(ofP, obj[i], y); + break; + } + } } -static SKL_OBJ_CLASS -objClass(SKL_OBJ_TYP const otyp) { +static SkeletonObjectClass +objClass(SkeletonObjectType const objType) { - switch (otyp) { + switch (objType) { case IRED: case IGREEN: case IBLUE: @@ -283,298 +347,871 @@ objClass(SKL_OBJ_TYP const otyp) { } +/*---------------------------------------------------------------------------- + Format string validation + + We validate format strings (such as "%f" "%03d") found in the skeleton files + for convenience, even though behavior is documented as undefined when the + user supplies a bogus format string. Certain strings, most notably those + with "%n", are especially risky; they pose a security threat. + + On systems with Glibc, we check with parse_printf_format(). On other + systems we conduct a cursory scan of the characters in the format string, + looking for characters that trigger non-numeric conversions, etc. + + Documentation for parse_printf_format() is usually available in texinfo + format on GNU/Linux systems. As of Dec. 2014 there is no official man page. + + Online documentation is available from: + https:// + www.gnu.org/software/libc/manual/html_node/Parsing-a-Template-String.html +-----------------------------------------------------------------------------*/ +#if HAVE_PARSE_PRINTF_FORMAT static void -addImpostorReplacementSeq(char * const line, - unsigned int const startCursor, - const char * const seqContents, - unsigned int const seqContentsLen, - unsigned int * const newCursorP) { +validateParsePrintfFLag(int const printfConversion, + SkeletonObjectType const ctyp, + const char ** const errorP) { /*---------------------------------------------------------------------------- - Add to line line[], at position 'startCursor', text that looks like a - replacement sequence but doesn't have the proper contents (the - stuff between the parentheses) to be one. For example, + Assuming 'printfConversion' is the value reported by parse_printf_format() + as the type of argument a format string requires, + return an explanation of how it is incompatible with 'ctyp' as + *errorP -- return null string if it is compatible. +-----------------------------------------------------------------------------*/ + /* We first check for "%n", then the type modifiers, and finally the + actual conversion type (char, int, float, double, string or pointer.) + */ + switch (printfConversion & PA_FLAG_MASK) { + case PA_FLAG_PTR: /* This means %n */ + pm_asprintf(errorP, "Contains a %%n conversion specifier"); + break; + + case PA_FLAG_SHORT: + case PA_FLAG_LONG: + case PA_FLAG_LONG_LONG: + /* We omit PA_FLAG_LONG_DOUBLE because it is a synonym for + PA_FLAG_LONG_LONG: listing both causes compilation errors. + */ + pm_asprintf(errorP, "Invalid type modifier"); + break; + + default: + switch (printfConversion & ~PA_FLAG_MASK) { + case PA_CHAR: + pm_message("Warning: char type conversion."); + case PA_INT: + if(objClass(ctyp) == OBJTYP_ICOLOR || + objClass(ctyp) == OBJTYP_INT ) + *errorP = NULL; + else + pm_asprintf(errorP, "Conversion specifier requires a " + "character or integer argument, but it is in " + "a replacement sequence for a different type"); + break; + case PA_DOUBLE: + if(objClass(ctyp) == OBJTYP_FCOLOR) + *errorP = NULL; + else + pm_asprintf(errorP, "Conversion specifier requires a " + "double precision floating point argument, " + "but it is in " + "a replacement sequence for a different type"); + break; + case PA_FLOAT: + case PA_STRING: /* %s */ + case PA_POINTER: /* %p */ + default: + pm_asprintf(errorP, "Conversion specifier requires an argument of " + "a type that this program never provides for " + "any replacement sequence"); + } + } +} +#endif - "#(fread x)" - seqContents[] is the contents; 'seqContentsLen' its length. - Return as *newCursorP where the line[] cursor ends up after adding - the sequence. +static void +validateFormatWithPpf(const char * const format, + SkeletonObjectType const ctyp, + const char ** const errorP) { +/*---------------------------------------------------------------------------- + Validate format string 'format' for use with a skeleton of type 'ctyp', + using the system parse_printf_format() function. + + Return as *errorP an explanation of how it is invalid, or a null string + if it is valid. -----------------------------------------------------------------------------*/ - unsigned int cursor; - unsigned int i; + /* We request parse_printf_format() to report the details of the first + 8 conversions. 8 because the maximum length of format is 16 means it + can have up to 8 conversions: "%d%d%d%d%d%d%d%d". + + Actually this is more than necessary: we are concerned with only the + first conversion and whether there it is the only one. + */ - cursor = startCursor; + int printfConversion[MAXFORMAT/2] = {0, 0, 0, 0, 0, 0, 0, 0}; - line[cursor++] = escape; - line[cursor++] = '('; + size_t const n = + parse_printf_format(format, MAXFORMAT/2, printfConversion); + + switch (n) { + case 0: + pm_asprintf(errorP, "No transformation found"); + break; + + case 1: + validateParsePrintfFLag(printfConversion[0], ctyp, errorP); + break; + + default: + pm_asprintf(errorP, "Has %lu extra transformation%s ", + n-1, n-1 > 1 ? "s" : ""); + break; + } +} - for (i = 0; i < seqContentsLen; ++i) - line[cursor++] = seqContents[i]; - line[cursor++] = ')'; - *newCursorP = cursor; +static void +validateFormatOne(char const typeSpecifier, + bool const isLastInString, + SkeletonObjectType const ctyp, + bool * const validatedP, + const char ** const errorP) { + + switch (typeSpecifier) { + /* Valid character encountered. Skip. */ + /* ' ' (space) is listed here, but should never occur for + we use sscanf() to parse the fields. + */ + case ' ': case '-': case '+': case '\'': case '#': case '.': + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + break; + + case 'c': case 'C': + pm_message("Warning: char type conversion: %%%c.", typeSpecifier); + case 'i': case 'd': case 'u': case 'o': case 'x': case 'X': + if (!isLastInString) + pm_asprintf(errorP, "Extra characters at end"); + else if(objClass(ctyp) != OBJTYP_ICOLOR && + objClass(ctyp) != OBJTYP_INT ) + pm_asprintf(errorP, "Conversion type mismatch"); + else + *validatedP = true; + break; + + case 'f': case 'F': case 'g': case 'G': case 'a': case 'A': + if (!isLastInString) + pm_asprintf(errorP, "Extra characters at end"); + else if(objClass(ctyp) != OBJTYP_FCOLOR) + pm_asprintf(errorP, "Conversion type mismatch"); + else + *validatedP = true; + break; + + case '\0': + pm_asprintf(errorP, "No conversion specified"); + break; + case '%': + pm_asprintf(errorP, "No more than one %% is allowed"); + break; + case '$': + case '*': + pm_asprintf(errorP, "%c is not allowed", typeSpecifier); + break; + case 'h': case 'l': case 'L': case 'q': case 'j': case 'Z': case 't': + pm_asprintf(errorP, "Modifier %c is not allowed in format", + typeSpecifier); + break; + case 's': case 'S': case 'm': case 'p': case 'n': + pm_asprintf(errorP, "Invalid conversion type"); + break; + default: + pm_asprintf(errorP, "Abnormal character"); + break; + } } -static int -read_skeleton(const char * const filename, - unsigned int const maxskl, - unsigned int * const nsklP, - SKL_OBJ ** const skl) { +static void +validateFormatGen(const char * const format, + SkeletonObjectType const ctyp, + const char ** const errorP) { /*---------------------------------------------------------------------------- - Read skeleton file + Validate format string 'format' for use with a skeleton of type 'ctyp', + without using the system parse_printf_format() function. + + The string must begin with "%" and end with the translation type character + ("%d", "%x", "%f", etc.) + + We check only for invalid characters. Invalid constructs, such as + "%00.00.00d" will pass this test. + + Return as *errorP an explanation of how it is invalid, or a null string + if it is valid. -----------------------------------------------------------------------------*/ - FILE * sklfile; - unsigned int slen; - unsigned int objlen; - int chr; - SKL_OBJ_TYP otyp; - char line[MAX_LINE_BUF+MAX_OBJ_BUF+16]; - char objstr[MAX_OBJ_BUF],typstr[MAX_OBJ_BUF]; - unsigned int nskl; - -#define SAVE_BIN(slen,line) \ - { if (slen > 0 && (skl[nskl] = save_bin_data(slen,line)) != NULL) ++nskl; \ - slen = 0; } - - sklfile = pm_openr(filename); - - /* Parse skeleton file */ - nskl = 0; /* initial value */ - - slen = 0; - while ((chr = getc (sklfile)) != EOF) { /* Up to end of skeleton file */ - if (nskl >= maxskl) - return -1; - - if (slen+1 >= MAX_LINE_BUF) { - /* Buffer finished. Save as binary object */ - SAVE_BIN(slen,line); + if (format[0] != '%') + pm_asprintf(errorP, "Does not start with %%"); + else { + unsigned int i; + bool validated; + + for (i = 1, validated = false, *errorP = NULL; + !validated && !*errorP; + ++i) { + + validateFormatOne(format[i], format[i+1] == '\0', ctyp, + &validated, errorP); } + } +} - if (chr != escape) { - /* Not a replacement sequence; just a literal character */ - line[slen++] = chr; - continue; - } - chr = getc(sklfile); - if (chr == EOF) { - /* Not a valid replacement sequence */ - line[slen++] = escape; - break; - } - if (chr != '(') { - /* Not a valid replacement sequence */ - line[slen++] = escape; - line[slen++] = chr; - continue; + +static void +validateFormat(const char * const format, + SkeletonObjectType const ctyp) { + + const char * error; + + if (strlen(format) > MAXFORMAT) + pm_asprintf(&error, "Too long"); + else { +#if HAVE_PARSE_PRINTF_FORMAT + if (true) + validateFormatWithPpf(format, ctyp, &error); + else /* Silence compiler warning about unused function */ + validateFormatGen(format, ctyp, &error); +#else + validateFormatGen(format, ctyp, &error); +#endif + } + + if (error) + pm_error("Invalid format string '%s'. %s", format, error); +} + + + +static SkeletonObject * +newBinDataObj(unsigned int const nDat, + const char * const bdat) { +/*---------------------------------------------------------------------------- + Create a binary data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + objectP = malloc(sizeof(*objectP) + nDat); + + if (!objectP) + pm_error("Failed to allocate memory for binary data object " + "with %u bytes", nDat); + + objectP->objType = BDATA; + objectP->odata.binData.ndat = nDat; + objectP->odata.binData.bdat = ((char *)objectP) + sizeof(SkeletonObject); + memcpy(objectP->odata.binData.bdat, bdat, nDat); + + return objectP; +} + + + +static SkeletonObject * +newIcolDataObj(SkeletonObjectType const ctyp, + const char * const format, + unsigned int const icolmin, + unsigned int const icolmax) { +/*---------------------------------------------------------------------------- + Create integer color data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for an integer color data " + "object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.icolData.icformat, format); + objectP->odata.icolData.icolmin = icolmin; + objectP->odata.icolData.icolmax = icolmax; + + return objectP; +} + + + +static SkeletonObject * +newFcolDataObj(SkeletonObjectType const ctyp, + const char * const format, + double const fcolmin, + double const fcolmax) { +/*---------------------------------------------------------------------------- + Create float color data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for a float color data object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.fcolData.fcformat, format); + objectP->odata.fcolData.fcolmin = fcolmin; + objectP->odata.fcolData.fcolmax = fcolmax; + + return objectP; +} + + + +static SkeletonObject * +newIdataObj(SkeletonObjectType const ctyp, + const char * const format) { +/*---------------------------------------------------------------------------- + Create universal data object. +-----------------------------------------------------------------------------*/ + SkeletonObject * objectP; + + MALLOCVAR(objectP); + + if (!objectP) + pm_error("Failed to allocate memory for a universal data object"); + + objectP->objType = ctyp; + validateFormat(format, ctyp); + strcpy(objectP->odata.iData.iformat, format); + + return objectP; +} + + + +static char const escape = '#'; + + + +static SkeletonObjectType +interpretObjType(const char * const typstr) { + + SkeletonObjectType objType; + + /* handle integer colors */ + if (streq(typstr, "ired") ) objType = IRED; + else if (streq(typstr, "igreen")) objType = IGREEN; + else if (streq(typstr, "iblue") ) objType = IBLUE; + else if (streq(typstr, "ilum") ) objType = ILUM; + /* handle real colors */ + else if (streq(typstr, "fred") ) objType = FRED; + else if (streq(typstr, "fgreen")) objType = FGREEN; + else if (streq(typstr, "fblue") ) objType = FBLUE; + else if (streq(typstr, "flum") ) objType = FLUM; + /* handle integer data */ + else if (streq(typstr, "width") ) objType = WIDTH; + else if (streq(typstr, "height")) objType = HEIGHT; + else if (streq(typstr, "posx") ) objType = POSX; + else if (streq(typstr, "posy") ) objType = POSY; + else objType = BDATA; + + return objType; +} + + + +static SkeletonObject * +newIcSkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + unsigned int icolmin, icolmax; + char formstr[MAX_OBJ_BUF]; + unsigned int nOdata; + + nOdata = sscanf(objstr, "%*s%s%u%u", formstr, &icolmin, &icolmax); + + if (nOdata == 3) + retval = newIcolDataObj(objType, formstr, icolmin, icolmax); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newIcolDataObj(objType, "%u", 0, 255); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newFcSkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + double fcolmin, fcolmax; + char formstr[MAX_OBJ_BUF]; + unsigned int nOdata; + + nOdata = sscanf(objstr, "%*s%s%lf%lf", formstr, + &fcolmin, &fcolmax); + + if (nOdata == 3) + retval = newFcolDataObj(objType, formstr, fcolmin, fcolmax); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newFcolDataObj(objType, "%f", 0.0, 1.0); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newISkelFromReplString(const char * const objstr, + SkeletonObjectType const objType) { + + SkeletonObject * retval; + char formstr[MAX_OBJ_BUF]; + unsigned int const nOdata = sscanf(objstr, "%*s%s", formstr); + + if (nOdata == 1) + retval = newIdataObj(objType, formstr); + else if (nOdata == EOF) { + /* No arguments specified. Use defaults */ + retval = newIdataObj(objType, "%u"); + } else + retval = NULL; + + return retval; +} + + + +static SkeletonObject * +newSkeletonFromReplString(const char * const objstr) { +/*---------------------------------------------------------------------------- + Create a skeleton from the replacement string 'objstr' (the stuff + between the parentheses in #(...) ). + + Return NULL if it isn't a valid replacement string. +-----------------------------------------------------------------------------*/ + /* We use sscanf() to parse the contents of objstr, giving it a format + template with the largest number of fields possible plus one extra to + pick up and check for the existence of invalid trailing characters. We + read and discard fields beyond the first, if any. The appropriate + new**SkelFromReplString() function determines their contents with a + separate call to sscanf(). + */ + + SkeletonObject * retval; + char typstr[MAX_OBJ_BUF]; + SkeletonObjectType objType; + int conversionCt; + char s1[MAX_OBJ_BUF]; /* Dry read. */ + char s2[MAX_OBJ_BUF]; /* Extra tailing characters. */ + float f1, f2; /* Dry read. */ + + typstr[0] = '\0'; /* initial value */ + + conversionCt = sscanf(objstr, "%s%s%f%f%s", typstr, s1, &f1, &f2, s2); + switch (conversionCt) { + case 1: case 2: case 4: + objType = interpretObjType(typstr); + break; + default: + objType = BDATA; + } + + switch (objClass(objType)) { + case OBJTYP_ICOLOR: + retval = newIcSkelFromReplString(objstr, objType); + break; + case OBJTYP_FCOLOR: + retval = newFcSkelFromReplString(objstr, objType); + break; + case OBJTYP_INT: + retval = newISkelFromReplString(objstr, objType); + break; + case OBJTYP_BDATA: + retval = NULL; + } + return retval; +} + + + +static void +readThroughCloseParen(FILE * const ifP, + char * const objstr, + size_t const objstrSize, + bool * const unclosedP) { +/*---------------------------------------------------------------------------- + Read *ifP up through close parenthesis ( ')' ) into 'objstr', which + is of size 'objstrSize'. Make it a NUL-terminated string. + + Return *unclosedP true iff we run out of file or run out of objstr + before we see a close parenthesis. In this case, return the rest of + the file, or as much as fits, in 'objstr', not NUL-terminated. +-----------------------------------------------------------------------------*/ + unsigned int i; + bool eof; + bool gotEscSeq; + + for (i= 0, eof = false, gotEscSeq = false; + i < objstrSize - 1 && !gotEscSeq && !eof; + ++i) { + + int rc; + + rc = getc(ifP); + if (rc == EOF) + eof = true; + else { + char const chr = rc; + if (chr == ')') { + gotEscSeq = true; + objstr[i] = '\0'; + } else + objstr[i] = chr; } - /* Read replacement string up through ')'. Put contents of - parentheses in objstr[]. + } + *unclosedP = !gotEscSeq; +} + + + +typedef struct { + unsigned int capacity; + SkeletonObject ** skeletonPList; + unsigned int nSkeleton; +} SkeletonBuffer; + + + +static void +SkeletonBuffer_init(SkeletonBuffer * const bufferP, + unsigned int const capacity, + SkeletonObject ** const skeletonPList) { + + bufferP->capacity = capacity; + bufferP->skeletonPList = skeletonPList; + bufferP->nSkeleton = 0; +} + + + +static void +SkeletonBuffer_add(SkeletonBuffer * const bufferP, + SkeletonObject * const skeletonP) { + + if (bufferP->nSkeleton >= bufferP->capacity) + pm_error("Too many skeletons. Max = %u", bufferP->capacity); + + bufferP->skeletonPList[bufferP->nSkeleton++] = skeletonP; +} + + + +typedef struct { + + char data[MAX_LINE_BUF + MAX_OBJ_BUF + 16]; + + unsigned int length; + + SkeletonBuffer * skeletonBufferP; + /* The buffer to which we flush. Flushing means turning all the + characters currently in our buffer into a binary skeleton object + here. */ - for (objlen = 0; objlen < sizeof(objstr)-1; ++objlen) { - chr = getc(sklfile); - if (chr == EOF) break; - if (chr == ')') break; - objstr[objlen] = chr; - } - objstr[objlen] = '\0'; - - if (chr != ')') { - /* Not valid replacement sequence */ - unsigned int i; - line[slen++] = escape; - line[slen++] = chr; - for (i = 0; i < objlen; ++i) - line[slen++] = objstr[i]; - if (chr == EOF) - break; - continue; - } - typstr[0] = '\0'; /* Get typ of data */ - sscanf(objstr, "%s", typstr); - - otyp = interpretObjType(typstr); - - switch (objClass(otyp)) { - case OBJTYP_ICOLOR: { - int icolmin, icolmax; - char formstr[MAX_OBJ_BUF]; - int n_odata; - - n_odata = sscanf(objstr, "%*s%s%d%d", formstr, &icolmin, &icolmax); - - if (n_odata == 3) { - SAVE_BIN(slen, line); - skl[nskl] = save_icol_data(otyp, formstr, icolmin, icolmax); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_icol_data(otyp, "%d", 0, 255); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - case OBJTYP_FCOLOR: { - double fcolmin, fcolmax; - char formstr[MAX_OBJ_BUF]; - int n_odata; - - n_odata = sscanf(objstr, "%*s%s%lf%lf", formstr, - &fcolmin, &fcolmax); - - if (n_odata == 3) { - SAVE_BIN(slen, line); - skl[nskl] = save_fcol_data(otyp, formstr, fcolmin, fcolmax); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_fcol_data(otyp, "%f", 0.0, 1.0); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - - case OBJTYP_INT: { - char formstr[MAX_OBJ_BUF]; - int const n_odata = sscanf(objstr, "%*s%s", formstr); - - if (n_odata == 1) { - SAVE_BIN(slen, line); - skl[nskl] = save_i_data(otyp, formstr); - if (skl[nskl] != NULL) - ++nskl; - } else if (n_odata == EOF) { - /* No arguments specified. Use defaults */ - SAVE_BIN(slen, line); - skl[nskl] = save_i_data(otyp, "%d"); - if (skl[nskl] != NULL) - ++nskl; - } else - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); - } break; - case OBJTYP_BDATA: - addImpostorReplacementSeq(line, slen, objstr, objlen, &slen); +} Buffer; + + + +static void +Buffer_init(Buffer * const bufferP, + SkeletonBuffer * const skeletonBufferP) { + + bufferP->skeletonBufferP = skeletonBufferP; + bufferP->length = 0; +} + + + +static void +Buffer_flush(Buffer * const bufferP) { +/*---------------------------------------------------------------------------- + Flush the buffer out to a binary skeleton object. +-----------------------------------------------------------------------------*/ + SkeletonBuffer_add(bufferP->skeletonBufferP, + newBinDataObj(bufferP->length, bufferP->data)); + + bufferP->length = 0; +} + + + +static void +Buffer_add(Buffer * const bufferP, + char const newChar) { + + if (bufferP->length >= MAX_LINE_BUF) + Buffer_flush(bufferP); + + assert(bufferP->length < MAX_LINE_BUF); + + bufferP->data[bufferP->length++] = newChar; +} + + + +static void +Buffer_dropFinalNewline(Buffer * const bufferP) { +/*---------------------------------------------------------------------------- + If the last thing in the buffer is a newline, remove it. +-----------------------------------------------------------------------------*/ + if (bufferP->length >= 1 && bufferP->data[bufferP->length-1] == '\n') { + /* Drop finishing newline character */ + --bufferP->length; + } +} + + + +static void +addImpostorReplacementSeq(Buffer * const bufferP, + const char * const seqContents) { +/*---------------------------------------------------------------------------- + Add to buffer *bufferP something that looks like a replacement sequence but + doesn't have the proper contents (the stuff between the parentheses) to be + one. For example, + + "#(fread x)" + + seqContents[] is the contents, NUL-terminated. +-----------------------------------------------------------------------------*/ + const char * p; + + Buffer_add(bufferP, escape); + Buffer_add(bufferP, '('); + + for (p = &seqContents[0]; *p; ++p) + Buffer_add(bufferP, *p); + + Buffer_add(bufferP, ')'); +} + + + +static void +readSkeletonFile(const char * const filename, + unsigned int const maxskl, + const char ** const errorP, + unsigned int * const nSkeletonP, + SkeletonObject ** const skeletonPList) { +/*---------------------------------------------------------------------------- +-----------------------------------------------------------------------------*/ + FILE * sklfileP; + SkeletonBuffer skeletonBuffer; + /* A buffer for accumulating skeleton objects */ + Buffer buffer; + /* A buffer for accumulating binary (literal; unsubstituted) data, on + its way to becoming a binary skeleton object. + */ + bool eof; + const char * error; + + SkeletonBuffer_init(&skeletonBuffer, maxskl, skeletonPList); + + Buffer_init(&buffer, &skeletonBuffer); + + sklfileP = pm_openr(filename); + + for (eof = false, error = NULL; !eof && !error; ) { + + int rc; + + rc = getc(sklfileP); + + if (rc == EOF) + eof = true; + else { + char const chr = rc; + + if (chr != escape) { + /* Not a replacement sequence; just a literal character */ + Buffer_add(&buffer, chr); + } else { + int rc; + rc = getc(sklfileP); + if (rc == EOF) { + /* Not a replacement sequence, just an escape caharacter + at the end of the file. + */ + Buffer_add(&buffer, escape); + eof = true; + } else { + char const chr = rc; + + if (chr != '(') { + /* Not a replacement sequence, just a lone escape + character + */ + Buffer_add(&buffer, escape); + Buffer_add(&buffer, chr); + } else { + char objstr[MAX_OBJ_BUF]; + bool unclosed; + readThroughCloseParen(sklfileP, + objstr, sizeof(objstr), + &unclosed); + if (unclosed) + pm_asprintf(&error, "Unclosed parentheses " + "in #() escape sequence"); + else { + SkeletonObject * const skeletonP = + newSkeletonFromReplString(objstr); + + if (skeletonP) { + Buffer_flush(&buffer); + SkeletonBuffer_add(&skeletonBuffer, skeletonP); + } else + addImpostorReplacementSeq(&buffer, objstr); + } + } + } + } } - } /* EOF of skeleton file */ + } - if (slen >= 1 && line[slen-1] == '\n') - /* Drop finishing newline character */ - --slen; + if (!error) { + Buffer_dropFinalNewline(&buffer); + Buffer_flush(&buffer); + } + *errorP = error; + *nSkeletonP = skeletonBuffer.nSkeleton; - SAVE_BIN(slen, line); /* Save whatever is left */ + fclose(sklfileP); +} - *nsklP = nskl; - fclose(sklfile); - return 0; + +static void +convertIt(FILE * const ifP, + FILE * const ofP, + SkeletonObject ** const bodySkeletonPList, + unsigned int const bodyNskl, + SkeletonObject ** const headSkeletonPList, + unsigned int const headNskl, + SkeletonObject ** const tailSkeletonPList, + unsigned int const tailNskl) { + + pixel * pixelrow; + pixval maxval; + double dmaxval; + int rows, cols; + int format; + unsigned int row; + + ppm_readppminit(ifP, &cols, &rows, &maxval, &format); + + pixelrow = ppm_allocrow(cols); + + dmaxval = (double)maxval; + + /* Write header */ + writeText(ofP, headNskl, headSkeletonPList, + cols, rows , 0, 0, 0.0, 0.0, 0.0); + + /* Write raster */ + for (row = 0; row < rows; ++row) { + unsigned int col; + + ppm_readppmrow(ifP, pixelrow, cols, maxval, format); + + for (col = 0; col < cols; ++col) { + pixel const thisPixel = pixelrow[col]; + + writeText(ofP, bodyNskl, bodySkeletonPList, + cols, rows, col, row, + PPM_GETR(thisPixel)/dmaxval, + PPM_GETG(thisPixel)/dmaxval, + PPM_GETB(thisPixel)/dmaxval); + } + } + + /* Write trailer */ + writeText(ofP, tailNskl, tailSkeletonPList, + cols, rows, 0, 0, 0.0, 0.0, 0.0); } -int main( argc, argv ) -int argc; -char* argv[]; - -{register int col; - register pixel* xP; - pixel* pixelrow; - pixval maxval,red,green,blue; - double dmaxval; - int argn, rows, cols, format, row; - unsigned int head_nskl,body_nskl,tail_nskl; - SKL_OBJ *head_skl[MAX_SKL_HEAD_OBJ]; - SKL_OBJ *body_skl[MAX_SKL_BODY_OBJ]; - SKL_OBJ *tail_skl[MAX_SKL_TAIL_OBJ]; - FILE *ifp; - const char *usage = "bodyskl [ -hd headskl ] [ -tl tailskl ] [pnmfile]"; - - ppm_init( &argc, argv ); - - argn = 1; - if (argn == argc) - pm_usage( usage ); - /* Read body skeleton file */ - if (read_skeleton (argv[argn],sizeof (body_skl)/sizeof (SKL_OBJ *), - &body_nskl,body_skl) < 0) - pm_usage ( usage ); - ++argn; - - head_nskl = tail_nskl = 0; - - while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') - { - if ( pm_keymatch ( argv[argn], "-hd", 1) && argn+1 < argc ) - { - argn++; /* Read header skeleton */ - if (read_skeleton (argv[argn],sizeof (head_skl)/sizeof (SKL_OBJ *), - &head_nskl,head_skl) < 0) - pm_usage ( usage ); - } - else if ( pm_keymatch ( argv[argn], "-tl", 1) && argn+1 < argc ) - { - argn++; /* Read tail skeleton */ - if (read_skeleton (argv[argn],sizeof (tail_skl)/sizeof (SKL_OBJ *), - &tail_nskl,tail_skl) < 0) - pm_usage ( usage ); - } - else - { - pm_usage ( usage ); - } - argn++; - } - - if ( argn != argc ) - { - ifp = pm_openr( argv[argn] ); - ++argn; - } - else - { - ifp = stdin; - } - - if ( argn != argc ) - pm_usage( usage ); - - ppm_readppminit( ifp, &cols, &rows, &maxval, &format ); - pixelrow = ppm_allocrow( cols ); - dmaxval = (double)maxval; - - if (head_nskl > 0) /* Write header */ - write_txt (stdout,head_nskl,head_skl,cols,rows,0,0,0.0,0.0,0.0); - - for ( row = 0; row < rows; ++row ) - { - ppm_readppmrow( ifp, pixelrow, cols, maxval, format ); - - for ( col = 0, xP = pixelrow; col < cols; ++col, ++xP ) - { - red = PPM_GETR( *xP ); - green = PPM_GETG( *xP ); - blue = PPM_GETB( *xP ); - write_txt (stdout,body_nskl,body_skl,cols,rows,col,row, - red/dmaxval,green/dmaxval,blue/dmaxval); - } - } - - if (tail_nskl > 0) /* Write trailer */ - write_txt (stdout,tail_nskl,tail_skl,cols,rows,0,0,0.0,0.0,0.0); - - pm_close( ifp ); - - exit( 0 ); +int +main(int argc, + const char ** argv) { + + struct CmdlineInfo cmdline; + + unsigned int headNskl, bodyNskl, tailNskl; + SkeletonObject * headSkeletonPList[MAX_SKL_HEAD_OBJ]; + SkeletonObject * bodySkeletonPList[MAX_SKL_BODY_OBJ]; + SkeletonObject * tailSkeletonPList[MAX_SKL_TAIL_OBJ]; + FILE * ifP; + const char * error; + + pm_proginit(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + ifP = pm_openr(cmdline.inputFileName); + + readSkeletonFile(cmdline.bodySklFileName, ARRAY_SIZE(bodySkeletonPList), + &error, &bodyNskl, bodySkeletonPList); + if (error) + pm_error("Invalid body skeleton file '%s'. %s", + cmdline.bodySklFileName, error); + + if (cmdline.hd) { + readSkeletonFile(cmdline.hd, ARRAY_SIZE(headSkeletonPList), + &error, &headNskl, headSkeletonPList); + if (error) + pm_error("Invalid head skeleton file '%s'. %s", + cmdline.hd, error); + } else + headNskl = 0; + + if (cmdline.tl) { + readSkeletonFile(cmdline.tl, ARRAY_SIZE(tailSkeletonPList), + &error, &tailNskl, tailSkeletonPList); + if (error) + pm_error("Invalid tail skeleton file '%s'. %s", + cmdline.tl, error); + } else + tailNskl = 0; + + if (cmdline.debug) + dumpAllSkeleton(bodySkeletonPList, bodyNskl, + headSkeletonPList, headNskl, + tailSkeletonPList, tailNskl); + + convertIt(ifP, stdout, + bodySkeletonPList, bodyNskl, + headSkeletonPList, headNskl, + tailSkeletonPList, tailNskl); + + pm_close(ifP); + + return 0; } + + diff --git a/converter/ppm/ppmtobmp.c b/converter/ppm/ppmtobmp.c index 1fc82ecb..24b1b3e5 100644 --- a/converter/ppm/ppmtobmp.c +++ b/converter/ppm/ppmtobmp.c @@ -63,11 +63,11 @@ freeColorMap(const colorMap * const colorMapP) { -struct cmdlineInfo { +struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. */ - char *input_filename; + const char * inputFilename; int class; /* C_WIN or C_OS2 */ unsigned int bppSpec; unsigned int bpp; @@ -77,7 +77,7 @@ struct cmdlineInfo { static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct CmdlineInfo * const cmdlineP) { /*---------------------------------------------------------------------------- Note that many of the strings that this function returns in the *cmdline_p structure are actually in the supplied argv array. And @@ -131,9 +131,9 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->mapfile = NULL; if (argc - 1 == 0) - cmdlineP->input_filename = strdup("-"); /* he wants stdin */ + cmdlineP->inputFilename = strdup("-"); /* he wants stdin */ else if (argc - 1 == 1) - cmdlineP->input_filename = strdup(argv[1]); + cmdlineP->inputFilename = strdup(argv[1]); else pm_error("Too many arguments. The only argument accepted " "is the input file specificaton"); @@ -915,7 +915,7 @@ int main(int argc, const char ** argv) { - struct cmdlineInfo cmdline; + struct CmdlineInfo cmdline; FILE * ifP; int rows; int cols; @@ -926,7 +926,7 @@ main(int argc, parseCommandLine(argc, argv, &cmdline); - ifP = pm_openr(cmdline.input_filename); + ifP = pm_openr(cmdline.inputFilename); ppm_readppminit(ifP, &cols, &rows, &maxval, &ppmFormat); |