about summary refs log tree commit diff
path: root/converter/ppm/ilbmtoppm.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/ppm/ilbmtoppm.c')
-rw-r--r--converter/ppm/ilbmtoppm.c464
1 files changed, 259 insertions, 205 deletions
diff --git a/converter/ppm/ilbmtoppm.c b/converter/ppm/ilbmtoppm.c
index 5001741a..5ceb70b6 100644
--- a/converter/ppm/ilbmtoppm.c
+++ b/converter/ppm/ilbmtoppm.c
@@ -1,4 +1,4 @@
-/* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
+/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM
 **
 ** Copyright (C) 1989 by Jef Poskanzer.
 **
@@ -43,11 +43,10 @@
 #include <string.h>
 
 #include "pm_c_util.h"
-#include "ppm.h"
-#include "ilbm.h"
 #include "mallocvar.h"
-
-/*#define DEBUG*/
+#include "intcode.h"
+#include "ilbm.h"
+#include "ppm.h"
 
 typedef struct {
     int reg;            /* color register to change */
@@ -764,10 +763,15 @@ multi_free(cmap)
  ****************************************************************************/
 
 static void
-check_cmap(bmhd, cmap)
-    BitMapHeader *bmhd;
-    ColorMap *cmap;
-{
+prepareCmap(const BitMapHeader * const bmhd,
+            ColorMap *           const cmap) {
+/*----------------------------------------------------------------------------
+   This is a really ugly subroutine that 1) analyzes a colormap and its
+   context (returning the analysis in global variables); and 2) modifies that
+   color map, because it's really one type of data structure as input and
+   another as output.
+
+-----------------------------------------------------------------------------*/
     pixval colmaxval = 0;
     int shifted = 1;
     int i, r, g, b;
@@ -990,6 +994,8 @@ std_to_ppm(FILE *         const ifp,
            ColorMap *     const cmap, 
            long           const viewportmodes);
 
+
+
 static void
 ham_to_ppm(FILE *         const ifp, 
            long           const chunksize, 
@@ -1255,7 +1261,7 @@ dcol_to_ppm(FILE *         const ifP,
     unsigned int const greenplanes = dcol->g;
     unsigned int const blueplanes  = dcol->b;
     
-    int col, row, i;
+    int col, row;
     rawtype *Rrow, *Grow, *Brow;
     pixval maxval, redmaxval, greenmaxval, bluemaxval;
     pixval *redtable, *greentable, *bluetable;
@@ -1301,13 +1307,15 @@ dcol_to_ppm(FILE *         const ifP,
     MALLOCARRAY_NOFAIL(greentable, greenmaxval +1);
     MALLOCARRAY_NOFAIL(bluetable,  bluemaxval  +1);
 
-    for( i = 0; i <= redmaxval; i++ )
-        redtable[i] = (i * maxval + redmaxval/2)/redmaxval;
-    for( i = 0; i <= greenmaxval; i++ )
-        greentable[i] = (i * maxval + greenmaxval/2)/greenmaxval;
-    for( i = 0; i <= bluemaxval; i++ )
-        bluetable[i] = (i * maxval + bluemaxval/2)/bluemaxval;
-
+    {
+        unsigned int i;
+        for (i = 0; i <= redmaxval; ++i)
+            redtable[i] = ROUNDDIV(i * maxval, redmaxval);
+        for (i = 0; i <= greenmaxval; ++i)
+            greentable[i] = ROUNDDIV(i * maxval, greenmaxval);
+        for (i = 0; i <= bluemaxval; ++i)
+            bluetable[i] = ROUNDDIV(i * maxval, bluemaxval);
+    }
     if( transpName ) {
         MALLOCVAR_NOFAIL(transpColor);
         *transpColor = ppm_parsecolor(transpName, maxval);
@@ -1343,16 +1351,10 @@ dcol_to_ppm(FILE *         const ifP,
 
 
 static void
-cmap_to_ppm(cmap)
-    ColorMap *cmap;
-{
-    ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL);
-#if 0
-    int i;
-    ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1);
-    for( i = 0; i < cmap->ncolors; i++ )
-        ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1);
-#endif
+cmapToPpm(FILE *     const ofP,
+            ColorMap * const cmapP) {
+
+    ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL);
 }
 
 
@@ -1657,39 +1659,41 @@ PCHG_DecompHuff(src, dest, tree, origsize)
 }
 
 
+
 static void
-PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
-    PCHGHeader *PCHG;
-    PCHGCompHeader *CompHdr;
-    unsigned char *compdata;
-    unsigned long compsize;
-    unsigned char *comptree;
-    unsigned char *data;
-{
-    short *hufftree;
-    unsigned long huffsize, i;
-    unsigned long treesize = CompHdr->CompInfoSize;
+PCHG_Decompress(PCHGHeader *     const PCHG,
+                PCHGCompHeader * const CompHdr,
+                unsigned char *  const compdata,
+                unsigned long    const compsize,
+                unsigned char *  const comptree,
+                unsigned char *  const data) {
 
-    switch( PCHG->Compression ) {
-        case PCHG_COMP_HUFFMAN:
+    switch(PCHG->Compression) {
+    case PCHG_COMP_HUFFMAN: {
+        unsigned long const treesize = CompHdr->CompInfoSize;
+        unsigned long const huffsize = treesize / 2;
+        const bigend16 * const bigendComptree = (const void *)comptree;
 
-#ifdef DEBUG
-            pm_message("PCHG Huffman compression");
-#endif
-            /* turn big-endian 2-byte shorts into native format */
-            huffsize = treesize/2;
-            MALLOCARRAY_NOFAIL(hufftree, huffsize);
-            for( i = 0; i < huffsize; i++ ) {
-                hufftree[i] = (short)BIG_WORD(comptree);
-                comptree += 2;
-            }
+        short * hufftree;
+        unsigned long i;
 
-            /* decompress the change structure data */
-            PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
-                            CompHdr->OriginalDataSize);
+        /* Convert big-endian 2-byte shorts to C shorts */
 
-            free(hufftree);
-            break;
+        MALLOCARRAY(hufftree, huffsize);
+
+        if (!hufftree)
+            pm_error("Couldn't get memory for %lu-byte Huffman tree",
+                     huffsize);
+
+        for (i = 0; i < huffsize; ++i)
+            hufftree[i] = pm_uintFromBigend16(bigendComptree[i]);
+
+        /* decompress the change structure data */
+        PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
+                        CompHdr->OriginalDataSize);
+        
+        free(hufftree);
+    } break;
         default:
             pm_error("unknown PCHG compression type %d", PCHG->Compression);
     }
@@ -1798,94 +1802,119 @@ fail2:
 }
 
 
+
 static void
-PCHG_ConvertBig(PCHG, cmap, mask, datasize)
-    PCHGHeader *PCHG;
-    ColorMap *cmap;
-    unsigned char *mask;
-    unsigned long datasize;
-{
-    unsigned char *data;
+PCHG_ConvertBig(PCHGHeader *    const PCHG,
+                ColorMap *      const cmap,
+                unsigned char * const maskStart,
+                unsigned long   const datasize) {
+
+    unsigned char * data;
     unsigned char thismask;
-    int bits, row, i, changes, masklen, reg;
-    unsigned long totalchanges = 0;
-    int changedlines = PCHG->ChangedLines;
+    int bits;
+    unsigned int row;
+    int changes;
+    int masklen;
+    int reg;
+    unsigned long totalchanges;
+    int changedlines;
+    unsigned long dataRemaining;
+    unsigned char * mask;
+
+    mask = maskStart;  /* initial value */
+    dataRemaining = datasize;  /* initial value */
+    changedlines = PCHG->ChangedLines;  /* initial value */
+    totalchanges = 0;  /* initial value */
 
     masklen = 4 * MaskLongWords(PCHG->LineCount);
-    data = mask + masklen; datasize -= masklen;
+    data = mask + masklen; dataRemaining -= masklen;
 
-    bits = 0;
-    for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
+
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
 
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_init[reg - PCHG->MinReg].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_init[reg - PCHG->MinReg].r = *data++;
                 cmap->mp_init[reg - PCHG->MinReg].b = *data++;  /* yes, RBG */
                 cmap->mp_init[reg - PCHG->MinReg].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
 
-    for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
-        if( bits == 0 ) {
-            if( masklen == 0 ) goto fail2;
+    for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) {
+        if (bits == 0) {
+            if (masklen == 0)
+                pm_error("insufficient data in line mask");
+
             thismask = *mask++;
             --masklen;
             bits = 8;
         }
-        if( thismask & (1<<7) ) {
-            if( datasize < 2 ) goto fail;
-            changes = BIG_WORD(data); data += 2; datasize -= 2;
+        if (thismask & (1<<7)) {
+            unsigned int i;
+
+            if (dataRemaining < 2)
+                pm_error("insufficient data in BigLineChanges structures");
+
+            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
 
             MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1);
-            for( i = 0; i < changes; i++ ) {
-                if( totalchanges >= PCHG->TotalChanges ) goto fail;
-                if( datasize < 6 ) goto fail;
+            for (i = 0; i < changes; ++i) {
+                if (totalchanges >= PCHG->TotalChanges)
+                    pm_error("insufficient data in BigLineChanges structures");
+
+                if (dataRemaining < 6)
+                    pm_error("insufficient data in BigLineChanges structures");
+
                 reg = BIG_WORD(data); data += 2;
                 cmap->mp_change[row][i].reg = reg;
                 ++data; /* skip alpha */
                 cmap->mp_change[row][i].r = *data++;
                 cmap->mp_change[row][i].b = *data++;    /* yes, RBG */
                 cmap->mp_change[row][i].g = *data++;
-                datasize -= 6;
+                dataRemaining -= 6;
                 ++totalchanges;
             }
             cmap->mp_change[row][changes].reg = MP_REG_END;
             --changedlines;
         }
         thismask <<= 1;
-        bits--;
+        --bits;
     }
-    if( totalchanges != PCHG->TotalChanges )
+    if (totalchanges != PCHG->TotalChanges)
         pm_message("warning - got %ld change structures, "
                    "chunk header reports %ld", 
                    totalchanges, PCHG->TotalChanges);
-    return;
-fail:
-    pm_error("insufficient data in BigLineChanges structures");
-fail2:
-    pm_error("insufficient data in line mask");
 }
 
 
+
 static void
 read_pchg(FILE *     const ifp,
           IFF_ID     const iffid,
@@ -1939,7 +1968,7 @@ read_pchg(FILE *     const ifp,
             read_bytes(ifp, treesize, comptree, iffid, &remainingChunksize);
 
             compsize = remainingChunksize;
-            MALLOCARRAY_NOFAIL(compdata, remainingChunksize);
+            MALLOCARRAY_NOFAIL(compdata, compsize);
             read_bytes(ifp, compsize, compdata, iffid, &remainingChunksize);
 
             datasize = CompHdr.OriginalDataSize;
@@ -2033,7 +2062,7 @@ process_body( FILE *          const ifp,
         pm_error("%s chunk without %s chunk", 
                  ID2string(ID_BODY), ID2string(ID_BMHD));
 
-    check_cmap(bmhdP, cmap);
+    prepareCmap(bmhdP, cmap);
 
     pixelrow = ppm_allocrow(bmhdP->w);
     if( maskfile ) {
@@ -2081,21 +2110,21 @@ process_body( FILE *          const ifp,
 
 
 static void 
-process_chunk(FILE *          const ifp,
-              long            const formsize,
-              IFF_ID          const ignorelist[],
-              unsigned int    const ignorecount,
-              int             const fakeviewport,
-              int             const viewportmask,
-              int             const isdeepopt,
-              bool            const cmaponly,
-              bool *          const bodyChunkProcessedP,
-              bool *          const endchunkP,
-              BitMapHeader ** const bmhdP,
-              ColorMap *      const cmap,
-              DirectColor **  const dcolP,
-              int *           const viewportmodesP,
-              long *          const bytesReadP
+processChunk(FILE *          const ifP,
+             long            const formsize,
+             IFF_ID          const ignorelist[],
+             unsigned int    const ignorecount,
+             int             const fakeviewport,
+             int             const viewportmask,
+             int             const isdeepopt,
+             bool            const cmaponly,
+             bool *          const bodyChunkProcessedP,
+             bool *          const endchunkP,
+             BitMapHeader ** const bmhdP,
+             ColorMap *      const cmap,
+             DirectColor **  const dcolP,
+             int *           const viewportmodesP,
+             long *          const bytesReadP
     ) {
 
     IFF_ID iffid;
@@ -2104,129 +2133,168 @@ process_chunk(FILE *          const ifp,
 
     bytesread = 0;
 
-    iffid = get_big_long(ifp, ID_FORM, NULL);
-    chunksize = get_big_long(ifp, iffid, NULL);
+    iffid = get_big_long(ifP, ID_FORM, NULL);
+    chunksize = get_big_long(ifP, iffid, NULL);
     bytesread += 8;
 
     if (debug)
-        pm_message("reading %s chunk: %ld bytes", 
-                   ID2string(iffid), chunksize);
+        pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize);
 
-    if( ignored_iffid(iffid, ignorelist, ignorecount) ) {
+    if (ignored_iffid(iffid, ignorelist, ignorecount)) {
         pm_message("ignoring %s chunk", ID2string(iffid));
-        skip_chunk(ifp, iffid, chunksize);
-    } else if( iffid == ID_END ) {
+        skip_chunk(ifP, iffid, chunksize);
+    } else if (iffid == ID_END) {
         /* END chunks are not officially valid in IFF, but
            suggested as a future expansion for stream-writing,
            see Amiga RKM Devices, 3rd Ed, page 376 
         */
-        if( chunksize != 0 ) {
+        if (chunksize != 0 ) {
             pm_message("warning - non-0 %s chunk", ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
         }
-        if( formsize != 0xffffffff )
+        if (formsize != 0xffffffff)
             pm_message("warning - %s chunk with FORM size 0x%08lx "
                        "(should be 0x%08x)",
                        ID2string(iffid), formsize, 0xffffffff);
         *endchunkP = 1;
-    } else if( *bodyChunkProcessedP ) {
+    } else if (*bodyChunkProcessedP) {
         pm_message("%s chunk found after %s chunk - skipping", 
                    ID2string(iffid), ID2string(ID_BODY));
-        skip_chunk(ifp, iffid, chunksize);
+        skip_chunk(ifP, iffid, chunksize);
     } else
-        switch( iffid ) {
+        switch (iffid) {
         case ID_BMHD:
-            *bmhdP = read_bmhd(ifp, iffid, chunksize);
+            *bmhdP = read_bmhd(ifP, iffid, chunksize);
             break;
         case ID_CMAP:
-            read_cmap(ifp, iffid, chunksize, cmap);
+            read_cmap(ifP, iffid, chunksize, cmap);
             break;
         case ID_CMYK:
-            read_cmyk(ifp, iffid, chunksize, cmap);
+            read_cmyk(ifP, iffid, chunksize, cmap);
             break;
         case ID_CLUT:
-            read_clut(ifp, iffid, chunksize, cmap);
+            read_clut(ifP, iffid, chunksize, cmap);
             break;
         case ID_CAMG:
-            if( chunksize != CAMGChunkSize )
+            if (chunksize != CAMGChunkSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
-            *viewportmodesP = get_big_long(ifp, ID_CAMG, NULL);
+            *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL);
             *viewportmodesP &= viewportmask;      /* -isnotham/-isnotehb */
             break;
         case ID_PCHG:
-            read_pchg(ifp, iffid, chunksize, cmap);
+            read_pchg(ifP, iffid, chunksize, cmap);
             break;
         case ID_CTBL:
         case ID_SHAM:
-            read_4bit_mp(ifp, iffid, chunksize, cmap);
+            read_4bit_mp(ifP, iffid, chunksize, cmap);
             break;
         case ID_DCOL:
-            if( chunksize != DirectColorSize )
+            if (chunksize != DirectColorSize)
                 pm_error("%s chunk size mismatch", ID2string(iffid));
             MALLOCVAR_NOFAIL(*dcolP);
-            (*dcolP)->r = get_byte(ifp, iffid, NULL);
-            (*dcolP)->g = get_byte(ifp, iffid, NULL);
-            (*dcolP)->b = get_byte(ifp, iffid, NULL);
-            (void)get_byte(ifp, iffid, NULL);       /* skip pad byte */
+            (*dcolP)->r = get_byte(ifP, iffid, NULL);
+            (*dcolP)->g = get_byte(ifP, iffid, NULL);
+            (*dcolP)->b = get_byte(ifP, iffid, NULL);
+            get_byte(ifP, iffid, NULL);       /* skip pad byte */
             break;
         case ID_BODY: 
-            if( cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0 )) {
-                skip_chunk(ifp, ID_BODY,  chunksize);
-                return;
-            }
-    
-            process_body(ifp, chunksize, *bmhdP, cmap, 
-                         maskfile, fakeviewport, isdeepopt, *dcolP,
-                         viewportmodesP);
-
-            *bodyChunkProcessedP = TRUE;
+            if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0))
+                skip_chunk(ifP, ID_BODY,  chunksize);
+            else {
+                process_body(ifP, chunksize, *bmhdP, cmap, 
+                             maskfile, fakeviewport, isdeepopt, *dcolP,
+                             viewportmodesP);
 
-            break;
+                *bodyChunkProcessedP = TRUE;
+            } break;
         case ID_GRAB:   case ID_DEST:   case ID_SPRT:   case ID_CRNG:
         case ID_CCRT:   case ID_DYCP:   case ID_DPPV:   case ID_DRNG:
         case ID_EPSF:   case ID_JUNK:   case ID_CNAM:   case ID_PRVW:
         case ID_TINY:   case ID_DPPS:
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         case ID_copy:   case ID_AUTH:   case ID_NAME:   case ID_ANNO:
         case ID_TEXT:   case ID_FVER:
-            if( verbose )
-                display_chunk(ifp, iffid, chunksize);
+            if (verbose)
+                display_chunk(ifP, iffid, chunksize);
             else
-                skip_chunk(ifp, iffid, chunksize);
+                skip_chunk(ifP, iffid, chunksize);
             break;
-        case ID_DPI:
-        {
+        case ID_DPI: {
             int x, y;
 
-            x = get_big_short(ifp, ID_DPI, NULL);
-            y = get_big_short(ifp, ID_DPI, NULL);
-            if( verbose )
+            x = get_big_short(ifP, ID_DPI, NULL);
+            y = get_big_short(ifP, ID_DPI, NULL);
+            if (verbose)
                 pm_message("%s chunk:  dpi_x = %d    dpi_y = %d", 
                            ID2string(ID_DPI), x, y);
-        }
-        break;
+        } break;
         default:
             pm_message("unknown chunk type %s - skipping", 
                        ID2string(iffid));
-            skip_chunk(ifp, iffid, chunksize);
+            skip_chunk(ifP, iffid, chunksize);
             break;
         }
 
     bytesread += chunksize;
 
-    if( ODD(chunksize) ) {
-        (void) get_byte(ifp, iffid, NULL);
+    if (ODD(chunksize)) {
+        get_byte(ifP, iffid, NULL);
         bytesread += 1;
     } 
     *bytesReadP = bytesread;
 }
 
 
+
+static void
+maybeWriteColorMap(FILE *               const ofP,
+                   const BitMapHeader * const bmhdP,
+                   ColorMap *           const cmapP,
+                   bool                 const bodyChunkProcessed,
+                   bool                 const cmaponly) {
+/*----------------------------------------------------------------------------
+   Write to file *ofP the color map *cmapP as a PPM, if appropriate.
+
+   The logic (not just here -- in the program as a whole) for deciding whether
+   to write the image or the colormap is quite twisted.  If I thought anyone
+   was actually using this program, I would take the time to straighten it
+   out.
+
+   What's really sick about this subroutine is that in choosing to write
+   a color map, it has to know that Caller hasn't already written
+   the image.  Huge modularity violation.
+-----------------------------------------------------------------------------*/
+    if (cmaponly) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("You specified -cmaponly, but the ILBM "
+                     "has no colormap");
+    } else if (bmhdP && bmhdP->nPlanes == 0) {
+        if (HAS_COLORMAP(cmapP)) {
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither a color map nor color planes");
+    } else if (!bodyChunkProcessed) {
+        if (HAS_COLORMAP(cmapP)) {
+            pm_message("input is a colormap file");
+            prepareCmap(bmhdP, cmapP);
+            cmapToPpm(ofP, cmapP);
+        } else
+            pm_error("ILBM has neither %s or %s chunk", 
+                     ID2string(ID_BODY), ID2string(ID_CMAP));
+    }
+}
+
+
+
 int
 main(int argc, char *argv[]) {
 
-    FILE *ifp;
+    FILE * ifP;
     int argn;
     short cmaponly = 0, isdeepopt = 0;
     bool endchunk;
@@ -2300,25 +2368,25 @@ main(int argc, char *argv[]) {
     }    
 
     if( argn < argc ) {
-        ifp = pm_openr( argv[argn] );
+        ifP = pm_openr( argv[argn] );
         argn++;
     } else
-        ifp = stdin;
+        ifP = stdin;
 
     if( argn != argc )
         pm_usage(usage);
 
     /* Read in the ILBM file. */
 
-    firstIffid = get_big_long(ifp, ID_FORM, NULL);
-    if( firstIffid != ID_FORM )
+    firstIffid = get_big_long(ifP, ID_FORM, NULL);
+    if (firstIffid != ID_FORM)
         pm_error("input is not a FORM type IFF file");
-    formsize = get_big_long(ifp, ID_FORM, NULL);
-    typeid = get_big_long(ifp, ID_FORM, NULL);
-    if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
-        typeid != ID_PBM )
-        pm_error( "input is not an ILBM, RGBN, RGB8 or PBM "
-                  "type FORM IFF file" );
+    formsize = get_big_long(ifP, ID_FORM, NULL);
+    typeid = get_big_long(ifP, ID_FORM, NULL);
+    if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
+        typeid != ID_PBM)
+        pm_error("input is not an ILBM, RGBN, RGB8 or PBM "
+                 "type FORM IFF file");
     bytesread = 4;  /* FORM and formsize do not count */
 
     cmap = alloc_cmap();
@@ -2326,55 +2394,41 @@ main(int argc, char *argv[]) {
     /* Main loop, parsing the IFF FORM. */
     bodyChunkProcessed = FALSE;
     endchunk = FALSE;
-    while( !endchunk && formsize-bytesread >= 8 ) {
-        long bytes_read_for_chunk;
+    while (!endchunk && formsize-bytesread >= 8) {
+        long bytesReadForChunk;
 
-        process_chunk(ifp, formsize, ignorelist, ignorecount,
-                      fakeviewport, viewportmask,
-                      isdeepopt, cmaponly,
-                      &bodyChunkProcessed,
-                      &endchunk, &bmhdP, cmap, &dcol,
-                      &viewportmodes, &bytes_read_for_chunk);
+        processChunk(ifP, formsize, ignorelist, ignorecount,
+                     fakeviewport, viewportmask,
+                     isdeepopt, cmaponly,
+                     &bodyChunkProcessed,
+                     &endchunk, &bmhdP, cmap, &dcol,
+                     &viewportmodes, &bytesReadForChunk);
 
-        bytesread += bytes_read_for_chunk;
+        bytesread += bytesReadForChunk;
     }
 
-    if( maskfile ) {
+    if (maskfile) {
         pm_close(maskfile);
-        if( !wrotemask )
+        if (!wrotemask)
             remove(maskname);
         pbm_freerow(maskrow);
     }
 
-    if( cmaponly || (bmhdP && bmhdP->nPlanes == 0 )) {
-        if( HAS_COLORMAP(cmap) ) {
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no colormap");
-    } else if( !bodyChunkProcessed ) {
-        if( HAS_COLORMAP(cmap) ) {
-            pm_message("input is a colormap file");
-            check_cmap(bmhdP, cmap);
-            cmap_to_ppm(cmap);
-        } else
-            pm_error("no %s or %s chunk found", 
-                     ID2string(ID_BODY), ID2string(ID_CMAP));
-    }
+    maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly);
 
     {
         unsigned int skipped;
         
-        for( skipped = 0; fgetc(ifp) != EOF; ++skipped )
-            bytesread++;
+        for (skipped = 0; fgetc(ifP) != EOF; ++skipped)
+            ++bytesread;
 
-        if( skipped > 0 )
+        if (skipped > 0)
             pm_message("skipped %u extraneous byte%s after last chunk",
                        skipped, (skipped == 1 ? "" : "s"));
     }
-    pm_close(ifp);
+    pm_close(ifP);
 
-    if( !endchunk && bytesread != formsize ) {
+    if (!endchunk && bytesread != formsize) {
         pm_message("warning - file length/FORM size field mismatch "
                    "(%ld != %ld+8)",
                    bytesread+8 /* FORM+size */, formsize);