Blame converter/ppm/ilbmtoppm.c

Packit 78deda
/* ilbmtoppm.c - read an IFF ILBM file and produce a PPM
Packit 78deda
**
Packit 78deda
** Copyright (C) 1989 by Jef Poskanzer.
Packit 78deda
**
Packit 78deda
** Permission to use, copy, modify, and distribute this software and its
Packit 78deda
** documentation for any purpose and without fee is hereby granted, provided
Packit 78deda
** that the above copyright notice appear in all copies and that both that
Packit 78deda
** copyright notice and this permission notice appear in supporting
Packit 78deda
** documentation.  This software is provided "as is" without express or
Packit 78deda
** implied warranty.
Packit 78deda
**
Packit 78deda
** Modified by Mark Thompson on 10/4/90 to accommodate 24-bit IFF files
Packit 78deda
** as used by ASDG, NewTek, etc.
Packit 78deda
**
Packit 78deda
** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
Packit 78deda
**  20/Jun/93:
Packit 78deda
**  - row-by-row operation
Packit 78deda
**  - better de-interleave algorithm
Packit 78deda
**  - colormap files
Packit 78deda
**  - direct color
Packit 78deda
**  04/Oct/93:
Packit 78deda
**  - multipalette capability (PCHG chunk)
Packit 78deda
**  - options -ignore, -isham, -isehb and -adjustcolors
Packit 78deda
**  22/May/94:
Packit 78deda
**  - minor change: check first for 24 planes, then for HAM
Packit 78deda
**  21/Sep/94:
Packit 78deda
**  - write mask plane to a file if -maskfile option used
Packit 78deda
**  - write colormap file
Packit 78deda
**  - added sliced HAM/dynamic HAM/dynamic Hires multipalette formats (SHAM, CTBL chunk)
Packit 78deda
**  - added color lookup tables (CLUT chunk)
Packit 78deda
**  - major rework of colormap/multipalette handling
Packit 78deda
**  - now uses numeric IFF IDs
Packit 78deda
**  24/Oct/94:
Packit 78deda
**  - transparentColor capability
Packit 78deda
**  - added RGBN/RGB8 image types
Packit 78deda
**  - 24-bit & direct color modified to n-bit deep ILBM
Packit 78deda
**  22/Feb/95:
Packit 78deda
**  - direct color (DCOL) reimplemented
Packit 78deda
**  29/Mar/95
Packit 78deda
**  - added IFF-PBM format
Packit 78deda
*/
Packit 78deda
Packit 78deda
#include <string.h>
Packit 78deda
Packit 78deda
#include "pm_c_util.h"
Packit 78deda
#include "mallocvar.h"
Packit 78deda
#include "intcode.h"
Packit 78deda
#include "ilbm.h"
Packit 78deda
#include "ppm.h"
Packit 78deda
Packit 78deda
typedef struct {
Packit 78deda
    int reg;            /* color register to change */
Packit 78deda
    pixval r, g, b;     /* new colors for register */
Packit 78deda
} PaletteChange;
Packit 78deda
Packit 78deda
typedef struct {
Packit 78deda
    pixel *color;
Packit 78deda
    int    ncolors;
Packit 78deda
    /* lookup tables */
Packit 78deda
    unsigned char *redlut;
Packit 78deda
    unsigned char *greenlut;
Packit 78deda
    unsigned char *bluelut;
Packit 78deda
    unsigned char *monolut;
Packit 78deda
    /* multipalette stuff */
Packit 78deda
    PaletteChange *mp_init;
Packit 78deda
    PaletteChange **mp_change;
Packit 78deda
    int mp_rows;                /* # of rows in change array */
Packit 78deda
    int mp_type;                /* see below, higher types preferred */
Packit 78deda
    int mp_flags;
Packit 78deda
    IFF_ID  mp_id;
Packit 78deda
} ColorMap;
Packit 78deda
Packit 78deda
#define HAS_COLORMAP(cmap)      ((cmap) && (cmap)->color)
Packit 78deda
#define HAS_COLORLUT(cmap)      ((cmap) && ((cmap)->redlut || (cmap)->greenlut || (cmap)->bluelut))
Packit 78deda
#define HAS_MONOLUT(cmap)       ((cmap) && (cmap)->monolut)
Packit 78deda
#define HAS_MULTIPALETTE(cmap)  (HAS_COLORMAP(cmap) && (cmap)->mp_type)
Packit 78deda
#define MP_TYPE_SHAM        1
Packit 78deda
#define MP_TYPE_CTBL        2
Packit 78deda
#define MP_TYPE_PCHG        3
Packit 78deda
#define MP_REG_IGNORE       -1
Packit 78deda
#define MP_REG_END          -2
Packit 78deda
#define MP_FLAGS_SKIPLACED   (1<<0)
Packit 78deda
Packit 78deda
#define FACTOR_4BIT     17      /* scale factor maxval 15 -> maxval 255 */
Packit 78deda
Packit 78deda
static short verbose = 0;
Packit 78deda
static short adjustcolors = 0;
Packit 78deda
static unsigned char *ilbmrow;
Packit 78deda
static pixel *pixelrow;
Packit 78deda
static FILE *maskfile = NULL;
Packit 78deda
static bit *maskrow = NULL;
Packit 78deda
static bool wrotemask;
Packit 78deda
static IFF_ID typeid;       /* ID_ILBM, ID_RGBN, ID_RGB8 */
Packit 78deda
Packit 78deda
static char *transpName = NULL;  /* -transparent option value */
Packit 78deda
Packit 78deda
static bool debug = FALSE;
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static char *
Packit 78deda
ID2string(id)
Packit 78deda
    IFF_ID id;
Packit 78deda
{
Packit 78deda
    static char str[] = "abcd";
Packit 78deda
Packit 78deda
    str[0] = (char)(id >> 24 & 0xff);
Packit 78deda
    str[1] = (char)(id >> 16 & 0xff);
Packit 78deda
    str[2] = (char)(id >>  8 & 0xff);
Packit 78deda
    str[3] = (char)(id >>  0 & 0xff);
Packit 78deda
Packit 78deda
    return str;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Memory allocation
Packit 78deda
 ****************************************************************************/
Packit 78deda
static ColorMap *
Packit 78deda
alloc_cmap(void) {
Packit 78deda
Packit 78deda
    ColorMap * cmap;
Packit 78deda
Packit 78deda
    MALLOCVAR_NOFAIL(cmap);
Packit 78deda
Packit 78deda
    cmap->color     = NULL;
Packit 78deda
    cmap->ncolors   = 0;
Packit 78deda
    cmap->monolut   = NULL;
Packit 78deda
    cmap->redlut    = NULL;
Packit 78deda
    cmap->greenlut  = NULL;
Packit 78deda
    cmap->bluelut   = NULL;
Packit 78deda
    cmap->mp_init   = NULL;
Packit 78deda
    cmap->mp_change = NULL;
Packit 78deda
    cmap->mp_rows   = 0;
Packit 78deda
    cmap->mp_type   = 0;
Packit 78deda
    cmap->mp_flags  = 0;
Packit 78deda
Packit 78deda
    return cmap;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static rawtype *
Packit 78deda
alloc_rawrow(cols)
Packit 78deda
    int cols;
Packit 78deda
{
Packit 78deda
    rawtype *r;
Packit 78deda
    int i;
Packit 78deda
Packit 78deda
    MALLOCARRAY_NOFAIL(r, cols);
Packit 78deda
Packit 78deda
    for( i = 0; i < cols; i++ )
Packit 78deda
        r[i] = 0;
Packit 78deda
Packit 78deda
    return r;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Basic I/O functions
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
static void
Packit 78deda
readerr(f, iffid)
Packit 78deda
    FILE *f;
Packit 78deda
    IFF_ID iffid;
Packit 78deda
{
Packit 78deda
    if( ferror(f) )
Packit 78deda
        pm_error("read error");
Packit 78deda
    else
Packit 78deda
        pm_error("premature EOF in %s chunk", ID2string(iffid));
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_bytes(FILE *          const ifP,
Packit 78deda
           int             const bytes,
Packit 78deda
           unsigned char * const buffer,
Packit 78deda
           IFF_ID          const iffid,
Packit 78deda
           unsigned long * const counterP) {
Packit 78deda
Packit 78deda
    if (counterP) {
Packit 78deda
        if (*counterP < bytes)
Packit 78deda
            pm_error("insufficient data in %s chunk", ID2string(iffid));
Packit 78deda
        *counterP -= bytes;
Packit 78deda
    }
Packit 78deda
    if (fread(buffer, 1, bytes, ifP) != bytes)
Packit 78deda
        readerr(ifP, iffid);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static unsigned char
Packit 78deda
get_byte(ifP, iffid, counter)
Packit 78deda
    FILE* ifP;
Packit 78deda
    IFF_ID iffid;
Packit 78deda
    long *counter;
Packit 78deda
{
Packit 78deda
    int i;
Packit 78deda
Packit 78deda
    if( counter ) {
Packit 78deda
        if( *counter == 0 )
Packit 78deda
            pm_error("insufficient data in %s chunk", ID2string(iffid));
Packit 78deda
        --(*counter);
Packit 78deda
    }
Packit 78deda
    i = getc(ifP);
Packit 78deda
    if( i == EOF )
Packit 78deda
        readerr(ifP, iffid);
Packit 78deda
Packit 78deda
    return (unsigned char) i;
Packit 78deda
}
Packit 78deda
Packit 78deda
static long
Packit 78deda
get_big_long(FILE *          const ifP,
Packit 78deda
             IFF_ID          const iffid,
Packit 78deda
             unsigned long * const counterP) {
Packit 78deda
Packit 78deda
    long l;
Packit 78deda
    
Packit 78deda
    if (counterP) {
Packit 78deda
        if (*counterP < 4)
Packit 78deda
            pm_error("insufficient data in %s chunk", ID2string(iffid));
Packit 78deda
        *counterP -= 4;
Packit 78deda
    }
Packit 78deda
    if (pm_readbiglong(ifP, &l) == -1)
Packit 78deda
        readerr(ifP, iffid);
Packit 78deda
Packit 78deda
    return l;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static short
Packit 78deda
get_big_short(FILE *          const ifP,
Packit 78deda
              IFF_ID          const iffid,
Packit 78deda
              unsigned long * const counterP) {
Packit 78deda
Packit 78deda
    short s;
Packit 78deda
Packit 78deda
    if (counterP) {
Packit 78deda
        if (*counterP < 2)
Packit 78deda
            pm_error("insufficient data in %s chunk", ID2string(iffid));
Packit 78deda
        *counterP -= 2;
Packit 78deda
    }
Packit 78deda
    if (pm_readbigshort(ifP, &s) == -1)
Packit 78deda
        readerr(ifP, iffid);
Packit 78deda
Packit 78deda
    return s;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Chunk reader
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
static void
Packit 78deda
chunk_end(FILE *        const ifP,
Packit 78deda
          IFF_ID        const iffid,
Packit 78deda
          unsigned long const chunksize) {
Packit 78deda
Packit 78deda
    if (chunksize > 0) {
Packit 78deda
        unsigned long remainingChunksize;
Packit 78deda
        pm_message("warning - %ld extraneous byte%s in %s chunk",
Packit 78deda
                    chunksize, (chunksize == 1 ? "" : "s"), ID2string(iffid));
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
        while (remainingChunksize > 0)
Packit 78deda
            get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
skip_chunk(FILE *        const ifP,
Packit 78deda
           IFF_ID        const iffid,
Packit 78deda
           unsigned long const chunksize) {
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
Packit 78deda
    remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
    while (remainingChunksize > 0)
Packit 78deda
        get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
display_chunk(FILE *        const ifP,
Packit 78deda
              IFF_ID        const iffid,
Packit 78deda
              unsigned long const chunksize) {
Packit 78deda
Packit 78deda
    int byte;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
Packit 78deda
    pm_message("contents of %s chunk:", ID2string(iffid));
Packit 78deda
Packit 78deda
    remainingChunksize = chunksize;  /* initial value */
Packit 78deda
    byte = '\0';
Packit 78deda
Packit 78deda
    while (remainingChunksize > 0) {
Packit 78deda
        byte = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        if (fputc(byte, stderr) == EOF)
Packit 78deda
            pm_error("write error");
Packit 78deda
    }
Packit 78deda
    if (byte != '\n')
Packit 78deda
        if (fputc('\n', stderr) == EOF)
Packit 78deda
            pm_error("write error");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_cmap(FILE *     const ifP,
Packit 78deda
          IFF_ID     const iffid,
Packit 78deda
          long       const chunksize,
Packit 78deda
          ColorMap * const cmap) {
Packit 78deda
Packit 78deda
    long colors;
Packit 78deda
Packit 78deda
    colors = chunksize / 3;
Packit 78deda
    if( colors == 0 ) {
Packit 78deda
        pm_error("warning - empty %s colormap", ID2string(iffid));
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else {
Packit 78deda
        unsigned int i;
Packit 78deda
        if( cmap->color )               /* prefer CMAP-chunk over CMYK-chunk */
Packit 78deda
            ppm_freerow(cmap->color);
Packit 78deda
        cmap->color = ppm_allocrow(colors);
Packit 78deda
        cmap->ncolors = colors;
Packit 78deda
        
Packit 78deda
        for( i = 0; i < colors; ++i ) {
Packit 78deda
            int r, g, b;
Packit 78deda
            r = get_byte(ifP, iffid, &chunksize);
Packit 78deda
            g = get_byte(ifP, iffid, &chunksize);
Packit 78deda
            b = get_byte(ifP, iffid, &chunksize);
Packit 78deda
            PPM_ASSIGN(cmap->color[i], r, g, b);
Packit 78deda
        }
Packit 78deda
        chunk_end(ifP, iffid, chunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_cmyk(FILE *     const ifP,
Packit 78deda
          IFF_ID     const iffid,
Packit 78deda
          long       const chunksize,
Packit 78deda
          ColorMap * const cmap) {
Packit 78deda
Packit 78deda
    if( HAS_COLORMAP(cmap) ) {      /* prefer RGB color map */
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else {
Packit 78deda
        long const colors = chunksize/4;
Packit 78deda
        if( colors == 0 ) {
Packit 78deda
            pm_error("warning - empty %s colormap", ID2string(iffid));
Packit 78deda
            skip_chunk(ifP, iffid, chunksize);
Packit 78deda
        } else {
Packit 78deda
            unsigned int i;
Packit 78deda
            cmap->color = ppm_allocrow(colors);
Packit 78deda
            cmap->ncolors = colors;
Packit 78deda
            
Packit 78deda
            for( i = 0; i < colors; ++i ) {
Packit 78deda
                int c, m, y, k;
Packit 78deda
                c = get_byte(ifP, iffid, &chunksize);
Packit 78deda
                m = get_byte(ifP, iffid, &chunksize);
Packit 78deda
                y = get_byte(ifP, iffid, &chunksize);
Packit 78deda
                k = get_byte(ifP, iffid, &chunksize);
Packit 78deda
Packit 78deda
                {
Packit 78deda
                    pixval const red = 
Packit 78deda
                        MAXCOLVAL - MIN(MAXCOLVAL,
Packit 78deda
                                        c*(MAXCOLVAL-k)/MAXCOLVAL+k); 
Packit 78deda
                    pixval const green = 
Packit 78deda
                        MAXCOLVAL - MIN(MAXCOLVAL,
Packit 78deda
                                        m*(MAXCOLVAL-k)/MAXCOLVAL+k);
Packit 78deda
                    pixval const blue = 
Packit 78deda
                        MAXCOLVAL - MIN(MAXCOLVAL,
Packit 78deda
                                        y*(MAXCOLVAL-k)/MAXCOLVAL+k);
Packit 78deda
Packit 78deda
                    PPM_ASSIGN(cmap->color[i], red, green, blue);
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            chunk_end(ifP, iffid, chunksize);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_clut(FILE *        const ifP,
Packit 78deda
          IFF_ID        const iffid,
Packit 78deda
          unsigned long const chunksize,
Packit 78deda
          ColorMap *    const cmap) {
Packit 78deda
Packit 78deda
    if (chunksize != CLUTSize) {
Packit 78deda
        pm_message("invalid size for %s chunk - skipping it", 
Packit 78deda
                   ID2string(iffid));
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else {
Packit 78deda
        long type;
Packit 78deda
        unsigned char * lut;
Packit 78deda
        unsigned long remainingChunksize;
Packit 78deda
        unsigned int i;
Packit 78deda
Packit 78deda
        type = get_big_long(ifP, iffid, &remainingChunksize);
Packit 78deda
        get_big_long(ifP, iffid, &remainingChunksize); /* skip reserved fld */
Packit 78deda
Packit 78deda
        MALLOCARRAY_NOFAIL(lut, 256);
Packit 78deda
        for( i = 0; i < 256; ++i )
Packit 78deda
            lut[i] = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
        switch( type ) {
Packit 78deda
        case CLUT_MONO:
Packit 78deda
            cmap->monolut  = lut;
Packit 78deda
            break;
Packit 78deda
        case CLUT_RED:
Packit 78deda
            cmap->redlut   = lut;
Packit 78deda
            break;
Packit 78deda
        case CLUT_GREEN:
Packit 78deda
            cmap->greenlut = lut;
Packit 78deda
            break;
Packit 78deda
        case CLUT_BLUE:
Packit 78deda
            cmap->bluelut  = lut;
Packit 78deda
            break;
Packit 78deda
        default:
Packit 78deda
            pm_message("warning - %s type %ld not recognized",
Packit 78deda
                       ID2string(iffid), type);
Packit 78deda
            free(lut);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
warnNonsquarePixels(uint8_t const xAspect,
Packit 78deda
                    uint8_t const yAspect) {
Packit 78deda
Packit 78deda
    if (xAspect != yAspect) {
Packit 78deda
        const char * const baseMsg = "warning - non-square pixels";
Packit 78deda
Packit 78deda
        if (pm_have_float_format())
Packit 78deda
            pm_message("%s; to fix do a 'pamscale -%cscale %g'",
Packit 78deda
                       baseMsg,
Packit 78deda
                       xAspect > yAspect ? 'x' : 'y',
Packit 78deda
                       xAspect > yAspect ? 
Packit 78deda
                       (float)xAspect/yAspect : 
Packit 78deda
                       (float)yAspect/xAspect);
Packit 78deda
        else
Packit 78deda
            pm_message("%s", baseMsg);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static BitMapHeader *
Packit 78deda
read_bmhd(FILE *        const ifP,
Packit 78deda
          IFF_ID        const iffid,
Packit 78deda
          unsigned long const chunksize) {
Packit 78deda
Packit 78deda
    BitMapHeader * bmhdP;
Packit 78deda
Packit 78deda
    if (chunksize != BitMapHeaderSize) {
Packit 78deda
        pm_message("invalid size for %s chunk - skipping it", 
Packit 78deda
                   ID2string(iffid));
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
        bmhdP = NULL;
Packit 78deda
    } else {
Packit 78deda
        unsigned long remainingChunksize;
Packit 78deda
Packit 78deda
        MALLOCVAR_NOFAIL(bmhdP);
Packit 78deda
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
        
Packit 78deda
        bmhdP->w = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->h = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->x = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->y = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->nPlanes = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->masking = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->compression = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->flags = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->transparentColor =
Packit 78deda
            get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->xAspect = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->yAspect = get_byte(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->pageWidth  = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        bmhdP->pageHeight = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
        if (verbose) {
Packit 78deda
            if (typeid == ID_ILBM)
Packit 78deda
                pm_message("dimensions: %dx%d, %d planes", 
Packit 78deda
                           bmhdP->w, bmhdP->h, bmhdP->nPlanes);
Packit 78deda
            else
Packit 78deda
                pm_message("dimensions: %dx%d", bmhdP->w, bmhdP->h);
Packit 78deda
Packit 78deda
            if (typeid == ID_ILBM || typeid == ID_PBM) {
Packit 78deda
                pm_message("compression: %s",
Packit 78deda
                           bmhdP->compression <= cmpMAXKNOWN ?
Packit 78deda
                           cmpNAME[bmhdP->compression] : "unknown");
Packit 78deda
Packit 78deda
                switch(bmhdP->masking) {
Packit 78deda
                case mskNone:
Packit 78deda
                    break;
Packit 78deda
                case mskHasMask:
Packit 78deda
                case mskHasTransparentColor:
Packit 78deda
                    if (!maskfile)
Packit 78deda
                        pm_message("use '-maskfile <filename>' "
Packit 78deda
                                   "to generate a PBM mask file from %s", 
Packit 78deda
                                   mskNAME[bmhdP->masking]);
Packit 78deda
                    break;
Packit 78deda
                case mskLasso:
Packit 78deda
                    pm_message("warning - masking type '%s' not recognized", 
Packit 78deda
                               mskNAME[bmhdP->masking]);
Packit 78deda
                    break;
Packit 78deda
                default:
Packit 78deda
                    pm_error("unknown masking type %d", bmhdP->masking);
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            else    /* RGBN/RGB8 */
Packit 78deda
                if (!maskfile)
Packit 78deda
                    pm_message("use '-maskfile <filename>' "
Packit 78deda
                               "to generate a PBM mask file "
Packit 78deda
                               "from genlock bits");
Packit 78deda
        }
Packit 78deda
Packit 78deda
        /* fix aspect ratio */
Packit 78deda
        if (bmhdP->xAspect == 0 || bmhdP->yAspect == 0) {
Packit 78deda
            pm_message("warning - illegal aspect ratio %d:%d, using 1:1", 
Packit 78deda
                       bmhdP->xAspect, bmhdP->yAspect);
Packit 78deda
            bmhdP->xAspect = bmhdP->yAspect = 1;
Packit 78deda
        }
Packit 78deda
Packit 78deda
        warnNonsquarePixels(bmhdP->xAspect, bmhdP->yAspect);
Packit 78deda
    }
Packit 78deda
    return bmhdP;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 ILBM functions
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_ilbm_plane(FILE *          const ifP,
Packit 78deda
                unsigned long * const remainingChunksizeP,
Packit 78deda
                int             const bytes,
Packit 78deda
                int             const compression) {
Packit 78deda
Packit 78deda
    unsigned char *ubp;
Packit 78deda
    int j, byte;
Packit 78deda
    int bytesRemaining;
Packit 78deda
Packit 78deda
    bytesRemaining = bytes;  /* initial value */
Packit 78deda
Packit 78deda
    switch(compression) {
Packit 78deda
        case cmpNone:
Packit 78deda
            read_bytes(ifP, bytesRemaining, ilbmrow,
Packit 78deda
                       ID_BODY, remainingChunksizeP);
Packit 78deda
            break;
Packit 78deda
        case cmpByteRun1:
Packit 78deda
            ubp = ilbmrow;
Packit 78deda
            do {
Packit 78deda
                byte = (int)get_byte(ifP, ID_BODY, remainingChunksizeP);
Packit 78deda
                if( byte <= 127 ) {
Packit 78deda
                    j = byte;
Packit 78deda
                    bytesRemaining -= (j+1);
Packit 78deda
                    if( bytesRemaining < 0 )
Packit 78deda
                        pm_error("error doing ByteRun1 decompression");
Packit 78deda
                    for( ; j >= 0; j-- )
Packit 78deda
                        *ubp++ = get_byte(ifP, ID_BODY, remainingChunksizeP);
Packit 78deda
                }
Packit 78deda
                else
Packit 78deda
                if ( byte != 128 ) {
Packit 78deda
                    j = 256 - byte;
Packit 78deda
                    bytesRemaining -= (j+1);
Packit 78deda
                    if( bytesRemaining < 0 )
Packit 78deda
                        pm_error("error doing ByteRun1 decompression");
Packit 78deda
                    byte = (int)get_byte(ifP, ID_BODY, remainingChunksizeP);
Packit 78deda
                    for( ; j >= 0; j-- )
Packit 78deda
                        *ubp++ = (unsigned char)byte;
Packit 78deda
                }
Packit 78deda
                /* 128 is a NOP */
Packit 78deda
            }
Packit 78deda
            while( bytesRemaining > 0 );
Packit 78deda
            break;
Packit 78deda
        default:
Packit 78deda
            pm_error("unknown compression type %d", compression);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
static const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
Packit 78deda
Packit 78deda
static void
Packit 78deda
decode_row(FILE *          const ifP,
Packit 78deda
           unsigned long * const remainingChunksizeP,
Packit 78deda
           rawtype *       const chunkyrow,
Packit 78deda
           int             const nPlanes,
Packit 78deda
           BitMapHeader *  const bmhdP) {
Packit 78deda
Packit 78deda
    int plane, col, cols, cbit, bytes;
Packit 78deda
    unsigned char *ilp;
Packit 78deda
    rawtype *chp;
Packit 78deda
Packit 78deda
    cols = bmhdP->w;
Packit Service ad4525
    overflow_add(cols, 15);
Packit 78deda
    bytes = RowBytes(cols);
Packit 78deda
    for( plane = 0; plane < nPlanes; plane++ ) {
Packit 78deda
        int mask;
Packit 78deda
Packit 78deda
        mask = 1 << plane;
Packit 78deda
        read_ilbm_plane(ifP, remainingChunksizeP, bytes, bmhdP->compression);
Packit 78deda
Packit 78deda
        ilp = ilbmrow;
Packit 78deda
        chp = chunkyrow;
Packit 78deda
Packit 78deda
        cbit = 7;
Packit 78deda
        for( col = 0; col < cols; col++, cbit--, chp++ ) {
Packit 78deda
            if( cbit < 0 ) {
Packit 78deda
                cbit = 7;
Packit 78deda
                ilp++;
Packit 78deda
            }
Packit 78deda
            if( *ilp & bit_mask[cbit] )
Packit 78deda
                *chp |= mask;
Packit 78deda
            else
Packit 78deda
                *chp &= ~mask;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
decode_mask(FILE *          const ifP,
Packit 78deda
            unsigned long * const remainingChunksizeP,
Packit 78deda
            rawtype *       const chunkyrow,
Packit 78deda
            BitMapHeader *  const bmhdP) {
Packit 78deda
Packit 78deda
    int col, cols, cbit;
Packit 78deda
    unsigned char *ilp;
Packit 78deda
Packit 78deda
    cols = bmhdP->w;
Packit 78deda
    switch (bmhdP->masking) {
Packit 78deda
    case mskNone:
Packit 78deda
        break;
Packit 78deda
    case mskHasMask:        /* mask plane */
Packit 78deda
        read_ilbm_plane(ifP, remainingChunksizeP, RowBytes(cols), 
Packit 78deda
                        bmhdP->compression);
Packit 78deda
        if (maskfile) {
Packit 78deda
            ilp = ilbmrow;
Packit 78deda
            cbit = 7;
Packit 78deda
            for (col = 0; col < cols; ++col, --cbit) {
Packit 78deda
                if (cbit < 0) {
Packit 78deda
                    cbit = 7;
Packit 78deda
                    ++ilp;
Packit 78deda
                }
Packit 78deda
                if (*ilp & bit_mask[cbit])
Packit 78deda
                    maskrow[col] = PBM_BLACK;
Packit 78deda
                else
Packit 78deda
                    maskrow[col] = PBM_WHITE;
Packit 78deda
            }
Packit 78deda
            pbm_writepbmrow(maskfile, maskrow, cols, 0);
Packit 78deda
            wrotemask = true;
Packit 78deda
        }
Packit 78deda
        break;
Packit 78deda
    case mskHasTransparentColor:
Packit 78deda
        if (!chunkyrow)
Packit 78deda
            pm_error("decode_mask(): chunkyrow == NULL - can't happen");
Packit 78deda
        
Packit 78deda
        if (maskfile) {
Packit 78deda
            for (col = 0; col < cols; ++col) {
Packit 78deda
                if (chunkyrow[col] == bmhdP->transparentColor)
Packit 78deda
                    maskrow[col] = PBM_WHITE;
Packit 78deda
                else
Packit 78deda
                    maskrow[col] = PBM_BLACK;
Packit 78deda
            }
Packit 78deda
            pbm_writepbmrow(maskfile, maskrow, cols, 0);
Packit 78deda
                wrotemask = true;
Packit 78deda
        }
Packit 78deda
        break;
Packit 78deda
    case mskLasso:
Packit 78deda
        pm_error("This program does not know how to process Lasso masking");
Packit 78deda
        break;
Packit 78deda
    default:
Packit 78deda
        pm_error("decode_mask(): unknown masking type %d - can't happen", 
Packit 78deda
                 bmhdP->masking);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Multipalette handling
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit Service ad4525
static void *
Packit Service ad4525
xmalloc2(x, y)
Packit Service ad4525
    int x;
Packit Service ad4525
    int y;
Packit Service ad4525
{
Packit Service ad4525
    void *mem;
Packit Service ad4525
Packit Service ad4525
    overflow2(x,y);
Packit Service ad4525
    if( x * y == 0 )
Packit Service ad4525
        return NULL;
Packit Service ad4525
Packit Service ad4525
    mem = malloc2(x,y);
Packit Service ad4525
    if( mem == NULL )
Packit Service ad4525
        pm_error("out of memory allocating %d bytes", x * y);
Packit Service ad4525
    return mem;
Packit Service ad4525
}
Packit Service ad4525
Packit 78deda
Packit 78deda
static void
Packit 78deda
multi_adjust(cmap, row, palchange)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int row;
Packit 78deda
    PaletteChange *palchange;
Packit 78deda
{
Packit 78deda
    int i, reg;
Packit 78deda
Packit 78deda
    for( i = 0; palchange[i].reg != MP_REG_END; i++ ) {
Packit 78deda
        reg = palchange[i].reg;
Packit 78deda
        if( reg >= cmap->ncolors ) {
Packit 78deda
            pm_message("warning - palette change register out of range");
Packit 78deda
            pm_message("    row %d  change structure %d  reg=%d (max %d)", 
Packit 78deda
                       row, i, reg, cmap->ncolors-1);
Packit 78deda
            pm_message("    ignoring it...  "
Packit 78deda
                       "colors might get messed up from here");
Packit 78deda
        }
Packit 78deda
        else
Packit 78deda
        if( reg != MP_REG_IGNORE ) {
Packit 78deda
            PPM_ASSIGN(cmap->color[reg], 
Packit 78deda
                       palchange[i].r, palchange[i].g, palchange[i].b);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
static void
Packit 78deda
multi_init(cmap, viewportmodes)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    long viewportmodes;
Packit 78deda
{
Packit 78deda
    if( cmap->mp_init )
Packit 78deda
        multi_adjust(cmap, -1, cmap->mp_init);
Packit 78deda
    if( !(viewportmodes & vmLACE) )
Packit 78deda
        cmap->mp_flags &= ~(MP_FLAGS_SKIPLACED);
Packit 78deda
}
Packit 78deda
Packit 78deda
static void
Packit 78deda
multi_update(cmap, row)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int row;
Packit 78deda
{
Packit 78deda
    if( cmap->mp_flags & MP_FLAGS_SKIPLACED ) {
Packit 78deda
        if( ODD(row) )
Packit 78deda
            return;
Packit 78deda
        if( row/2 < cmap->mp_rows && cmap->mp_change[row/2] )
Packit 78deda
            multi_adjust(cmap, row, cmap->mp_change[row/2]);
Packit 78deda
    }
Packit 78deda
    else {
Packit 78deda
        if( row < cmap->mp_rows && cmap->mp_change[row] )
Packit 78deda
            multi_adjust(cmap, row, cmap->mp_change[row]);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
static void
Packit 78deda
multi_free(cmap)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
{
Packit 78deda
    int i;
Packit 78deda
Packit 78deda
    if( cmap->mp_init ) {
Packit 78deda
        free(cmap->mp_init);
Packit 78deda
        cmap->mp_init = NULL;
Packit 78deda
    }
Packit 78deda
    if( cmap->mp_change ) {
Packit 78deda
        for( i = 0; i < cmap->mp_rows; i++ ) {
Packit 78deda
            if( cmap->mp_change[i] )
Packit 78deda
                free(cmap->mp_change[i]);
Packit 78deda
        }
Packit 78deda
        free(cmap->mp_change);
Packit 78deda
        cmap->mp_change = NULL;
Packit 78deda
    }
Packit 78deda
    cmap->mp_rows = 0;
Packit 78deda
    cmap->mp_type = 0;
Packit 78deda
    cmap->mp_flags = 0;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Colormap handling
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
analyzeCmapSamples(const ColorMap * const cmapP,
Packit 78deda
                   pixval *         const maxSampleP,
Packit 78deda
                   bool *           const shiftedP) {
Packit 78deda
Packit 78deda
    pixval       maxSample;
Packit 78deda
    bool         shifted;
Packit 78deda
    unsigned int i;
Packit 78deda
        
Packit 78deda
    for (i = 0, maxSample = 0, shifted = true; i < cmapP->ncolors; ++i) {
Packit 78deda
        pixval const r = PPM_GETR(cmapP->color[i]);
Packit 78deda
        pixval const g = PPM_GETG(cmapP->color[i]);
Packit 78deda
        pixval const b = PPM_GETB(cmapP->color[i]);
Packit 78deda
Packit 78deda
        maxSample = MAX(maxSample, MAX(r, MAX(g, b)));
Packit 78deda
Packit 78deda
        if (r & 0x0f || g & 0x0f || b & 0x0f)
Packit 78deda
            shifted = false;
Packit 78deda
    }
Packit 78deda
    *shiftedP   = shifted;
Packit 78deda
    *maxSampleP = maxSample;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
transformCmap(ColorMap * const cmapP) {
Packit 78deda
Packit 78deda
    pixval maxSample;
Packit 78deda
        /* The maximum sample value in *cmapP input */
Packit 78deda
    bool shifted;
Packit 78deda
        /* Samples in the *cmapP input appear to be 4 bit (maxval 15) original
Packit 78deda
           values shifted left 4 places to make 8 bit (maxval 255) samples.
Packit 78deda
        */
Packit 78deda
Packit 78deda
    analyzeCmapSamples(cmapP, &maxSample, &shifted);
Packit 78deda
Packit 78deda
    if (maxSample == 0)
Packit 78deda
        pm_message("warning - black colormap");
Packit 78deda
    else if (shifted || maxSample <= 15) {
Packit 78deda
        if (!adjustcolors) {
Packit 78deda
            pm_message("warning - probably %s4-bit colormap",
Packit 78deda
                       shifted ? "shifted " : "");
Packit 78deda
            pm_message("Use '-adjustcolors' to scale colormap to 8 bits");
Packit 78deda
        } else {
Packit 78deda
            unsigned int i;
Packit 78deda
            pm_message("scaling colormap to 8 bits");
Packit 78deda
            for (i = 0; i < cmapP->ncolors; ++i) {
Packit 78deda
                pixval r, g, b;
Packit 78deda
                r = PPM_GETR(cmapP->color[i]);
Packit 78deda
                g = PPM_GETG(cmapP->color[i]);
Packit 78deda
                b = PPM_GETB(cmapP->color[i]);
Packit 78deda
                if (shifted) {
Packit 78deda
                    r >>= 4;
Packit 78deda
                    g >>= 4;
Packit 78deda
                    b >>= 4;
Packit 78deda
                }
Packit 78deda
                r *= FACTOR_4BIT;
Packit 78deda
                g *= FACTOR_4BIT;
Packit 78deda
                b *= FACTOR_4BIT;
Packit 78deda
                PPM_ASSIGN(cmapP->color[i], r, g, b);
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static pixel *
Packit 78deda
transpColor(const BitMapHeader * const bmhdP,
Packit 78deda
            ColorMap *           const cmapP,
Packit 78deda
            const char *         const transpName,
Packit 78deda
            pixval               const maxval) {
Packit 78deda
Packit 78deda
    pixel * transpColorP;
Packit 78deda
Packit 78deda
    if (bmhdP) {
Packit 78deda
        if (bmhdP->masking == mskHasTransparentColor || 
Packit 78deda
            bmhdP->masking == mskLasso) {
Packit 78deda
            MALLOCVAR_NOFAIL(transpColorP);
Packit 78deda
Packit 78deda
            if (transpName)
Packit 78deda
                *transpColorP = ppm_parsecolor(transpName, maxval);
Packit 78deda
            else {
Packit 78deda
                unsigned short const transpIdx = bmhdP->transparentColor;
Packit 78deda
                if (HAS_COLORMAP(cmapP)) {
Packit 78deda
                    if (transpIdx >= cmapP->ncolors) {
Packit 78deda
                        pm_message("using default transparent color (black)");
Packit 78deda
                        PPM_ASSIGN(*transpColorP, 0, 0, 0);
Packit 78deda
                    } else
Packit 78deda
                        *transpColorP = cmapP->color[transpIdx];
Packit 78deda
                } else {
Packit 78deda
                    /* The color index is just a direct gray level */
Packit 78deda
                    PPM_ASSIGN(*transpColorP, transpIdx, transpIdx, transpIdx);
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
        } else
Packit 78deda
            transpColorP = NULL;
Packit 78deda
    } else
Packit 78deda
        transpColorP = NULL;
Packit 78deda
Packit 78deda
    return transpColorP;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
prepareCmap(const BitMapHeader * const bmhdP,
Packit 78deda
            ColorMap *           const cmapP) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   This is a really ugly subroutine that 1) analyzes a colormap and its
Packit 78deda
   context (returning the analysis in global variables); and 2) modifies that
Packit 78deda
   color map, because it's really one type of data structure as input and
Packit 78deda
   another as output.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    bool bmhdCmapOk;
Packit 78deda
Packit 78deda
    if (bmhdP)
Packit 78deda
        bmhdCmapOk = (bmhdP->flags & BMHD_FLAGS_CMAPOK);
Packit 78deda
    else
Packit 78deda
        bmhdCmapOk = false;
Packit 78deda
Packit 78deda
    if (HAS_COLORMAP(cmapP) && !bmhdCmapOk)
Packit 78deda
        transformCmap(cmapP);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static pixval
Packit 78deda
lookup_red(cmap, oldval)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int oldval;
Packit 78deda
{
Packit 78deda
    if( cmap && cmap->redlut && oldval < 256 )
Packit 78deda
        return cmap->redlut[oldval];
Packit 78deda
    else
Packit 78deda
        return oldval;
Packit 78deda
}
Packit 78deda
Packit 78deda
static pixval
Packit 78deda
lookup_green(cmap, oldval)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int oldval;
Packit 78deda
{
Packit 78deda
    if( cmap && cmap->greenlut && oldval < 256 )
Packit 78deda
        return cmap->greenlut[oldval];
Packit 78deda
    else
Packit 78deda
        return oldval;
Packit 78deda
}
Packit 78deda
Packit 78deda
static pixval
Packit 78deda
lookup_blue(cmap, oldval)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int oldval;
Packit 78deda
{
Packit 78deda
    if( cmap && cmap->bluelut && oldval < 256 )
Packit 78deda
        return cmap->bluelut[oldval];
Packit 78deda
    else
Packit 78deda
        return oldval;
Packit 78deda
}
Packit 78deda
Packit 78deda
static pixval
Packit 78deda
lookup_mono(cmap, oldval)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int oldval;
Packit 78deda
{
Packit 78deda
    if( cmap && cmap->monolut && oldval < 256 )
Packit 78deda
        return cmap->monolut[oldval];
Packit 78deda
    else
Packit 78deda
        return oldval;
Packit 78deda
}
Packit 78deda
Packit 78deda
static ColorMap *
Packit 78deda
ehbcmap(cmap)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
{
Packit 78deda
    pixel *tempcolor = NULL;
Packit 78deda
    int i, col;
Packit 78deda
Packit 78deda
    col = cmap->ncolors;
Packit 78deda
Packit 78deda
    tempcolor = ppm_allocrow(col * 2);
Packit 78deda
    for( i = 0; i < col; i++ ) {
Packit 78deda
        tempcolor[i] = cmap->color[i];
Packit 78deda
        PPM_ASSIGN(tempcolor[col + i],  PPM_GETR(cmap->color[i]) / 2,
Packit 78deda
                                        PPM_GETG(cmap->color[i]) / 2,
Packit 78deda
                                        PPM_GETB(cmap->color[i]) / 2 );
Packit 78deda
    }
Packit 78deda
    ppm_freerow(cmap->color);
Packit 78deda
    cmap->color = tempcolor;
Packit 78deda
    cmap->ncolors *= 2;
Packit 78deda
Packit 78deda
    return cmap;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static pixval
Packit 78deda
lut_maxval(ColorMap * const cmap, 
Packit 78deda
           pixval     const maxval) {
Packit 78deda
Packit 78deda
    pixval retval;
Packit 78deda
    
Packit 78deda
    if (maxval >= 255)
Packit 78deda
        retval = maxval;
Packit 78deda
    else {
Packit 78deda
        if (!HAS_COLORLUT(cmap))
Packit 78deda
            retval = maxval;
Packit 78deda
        else {
Packit 78deda
            unsigned int i;
Packit 78deda
            unsigned char maxlut;
Packit 78deda
            maxlut = maxval;
Packit 78deda
            for( i = 0; i < maxval; i++ ) {
Packit 78deda
                if( cmap->redlut   && cmap->redlut[i]   > maxlut ) 
Packit 78deda
                    maxlut = cmap->redlut[i];
Packit 78deda
                if( cmap->greenlut && cmap->greenlut[i] > maxlut ) 
Packit 78deda
                    maxlut = cmap->greenlut[i];
Packit 78deda
                if( cmap->bluelut  && cmap->bluelut[i]  > maxlut ) 
Packit 78deda
                    maxlut = cmap->bluelut[i];
Packit 78deda
            }
Packit 78deda
            pm_message("warning - "
Packit 78deda
                       "%d-bit index into 8-bit color lookup table, "
Packit 78deda
                       "table maxval=%d", 
Packit 78deda
                       pm_maxvaltobits(maxval), maxlut);
Packit 78deda
            if( maxlut != maxval )
Packit 78deda
                retval = 255;
Packit 78deda
            else
Packit 78deda
                retval = maxval;
Packit 78deda
            pm_message("    assuming image maxval=%d", retval);
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    return retval;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
get_color(cmap, idx, red, green, blue)
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    int idx;
Packit 78deda
    pixval *red, *green, *blue;
Packit 78deda
{
Packit 78deda
    if( HAS_COLORMAP(cmap) ) {
Packit 78deda
        pixval r, g, b;
Packit 78deda
Packit 78deda
        if( idx >= cmap->ncolors )
Packit 78deda
            pm_error("color index out of range: %d (max %d)", 
Packit 78deda
                     idx, cmap->ncolors);
Packit 78deda
        r = PPM_GETR(cmap->color[idx]);
Packit 78deda
        g = PPM_GETG(cmap->color[idx]);
Packit 78deda
        b = PPM_GETB(cmap->color[idx]);
Packit 78deda
Packit 78deda
        *red    = lookup_red(cmap, r);
Packit 78deda
        *green  = lookup_green(cmap, g);
Packit 78deda
        *blue   = lookup_blue(cmap, b);
Packit 78deda
    }
Packit 78deda
    else {
Packit 78deda
        *red = *green = *blue = lookup_mono(cmap, idx);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Conversion functions
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
static void
Packit 78deda
std_to_ppm(FILE *         const ifP, 
Packit 78deda
           long           const chunksize, 
Packit 78deda
           BitMapHeader * const bmhdP, 
Packit 78deda
           ColorMap *     const cmap, 
Packit 78deda
           long           const viewportmodes);
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
ham_to_ppm(FILE *         const ifP, 
Packit 78deda
           long           const chunksize, 
Packit 78deda
           BitMapHeader * const bmhdP, 
Packit 78deda
           ColorMap *     const cmap, 
Packit 78deda
           long           const viewportmodes) {
Packit 78deda
Packit 78deda
    int cols, rows, hambits, hammask, hamshift, hammask2, col, row;
Packit 78deda
    pixval maxval;
Packit 78deda
    rawtype *rawrow;
Packit 78deda
    unsigned char hamlut[256];
Packit 78deda
Packit 78deda
    cols = bmhdP->w;
Packit 78deda
    rows = bmhdP->h;
Packit 78deda
    hambits = bmhdP->nPlanes - 2;
Packit 78deda
    hammask = (1 << hambits) - 1;
Packit 78deda
    hamshift = 8 - hambits;
Packit 78deda
    hammask2 = (1 << hamshift) - 1;
Packit 78deda
Packit 78deda
    if( hambits > 8 || hambits < 1 ) {
Packit 78deda
        int const assumed_viewportmodes = viewportmodes & ~(vmHAM);
Packit 78deda
Packit 78deda
        pm_message("%d-plane HAM?? - interpreting image as a normal ILBM", 
Packit 78deda
                   bmhdP->nPlanes);
Packit 78deda
        std_to_ppm(ifP, chunksize, bmhdP, cmap, assumed_viewportmodes);
Packit 78deda
        return;
Packit 78deda
    } else {
Packit 78deda
        unsigned long remainingChunksize;
Packit 78deda
        pixel * transpColorP;
Packit 78deda
Packit 78deda
        pm_message("input is a %sHAM%d file", 
Packit 78deda
                   HAS_MULTIPALETTE(cmap) ? "multipalette " : "", 
Packit 78deda
                   bmhdP->nPlanes);
Packit 78deda
Packit 78deda
        if( HAS_COLORLUT(cmap) || HAS_MONOLUT(cmap) ) {
Packit 78deda
            pm_message("warning - color lookup tables ignored in HAM");
Packit 78deda
            if( cmap->redlut )      free(cmap->redlut);
Packit 78deda
            if( cmap->greenlut )    free(cmap->greenlut);
Packit 78deda
            if( cmap->bluelut )     free(cmap->bluelut);
Packit 78deda
            if( cmap->monolut )     free(cmap->monolut);
Packit 78deda
            cmap->redlut = cmap->greenlut = cmap->bluelut = 
Packit 78deda
                cmap->monolut = NULL;
Packit 78deda
        }
Packit 78deda
        if( !HAS_COLORMAP(cmap) ) {
Packit 78deda
            pm_message("no colormap - interpreting values as grayscale");
Packit 78deda
            maxval = pm_bitstomaxval(hambits);
Packit 78deda
            for( col = 0; col <= maxval; col++ )
Packit 78deda
                hamlut[col] = col * MAXCOLVAL / maxval;
Packit 78deda
            cmap->monolut = hamlut;
Packit 78deda
        }
Packit 78deda
Packit 78deda
        transpColorP = transpColor(bmhdP, cmap, transpName, MAXCOLVAL);
Packit 78deda
Packit 78deda
        if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
            multi_init(cmap, viewportmodes);
Packit 78deda
Packit 78deda
        rawrow = alloc_rawrow(cols);
Packit 78deda
Packit 78deda
        ppm_writeppminit(stdout, cols, rows, MAXCOLVAL, 0);
Packit 78deda
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
        for (row = 0; row < rows; ++row) {
Packit 78deda
            pixval r, g, b;
Packit 78deda
Packit 78deda
            if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
                multi_update(cmap, row);
Packit 78deda
Packit 78deda
            decode_row(ifP, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP);
Packit 78deda
            decode_mask(ifP, &remainingChunksize, rawrow, bmhdP);
Packit 78deda
Packit 78deda
            r = g = b = 0;
Packit 78deda
            for( col = 0; col < cols; col++ ) {
Packit 78deda
                int idx = rawrow[col] & hammask;
Packit 78deda
Packit 78deda
                if( transpColorP && maskrow && maskrow[col] == PBM_WHITE )
Packit 78deda
                    pixelrow[col] = *transpColorP;
Packit 78deda
                else {
Packit 78deda
                    switch((rawrow[col] >> hambits) & 0x03) {
Packit 78deda
                    case HAMCODE_CMAP:
Packit 78deda
                        get_color(cmap, idx, &r, &g, &b);
Packit 78deda
                        break;
Packit 78deda
                    case HAMCODE_BLUE:
Packit 78deda
                        b = ((b & hammask2) | (idx << hamshift));
Packit 78deda
                        /*b = hamlut[idx];*/
Packit 78deda
                        break;
Packit 78deda
                    case HAMCODE_RED:
Packit 78deda
                        r = ((r & hammask2) | (idx << hamshift));
Packit 78deda
                        /*r = hamlut[idx];*/
Packit 78deda
                        break;
Packit 78deda
                    case HAMCODE_GREEN:
Packit 78deda
                        g = ((g & hammask2) | (idx << hamshift));
Packit 78deda
                        /*g = hamlut[idx];*/
Packit 78deda
                        break;
Packit 78deda
                    default:
Packit 78deda
                        pm_error("ham_to_ppm(): "
Packit 78deda
                                 "impossible HAM code - can't happen");
Packit 78deda
                    }
Packit 78deda
                    PPM_ASSIGN(pixelrow[col], r, g, b);
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0);
Packit 78deda
        }
Packit 78deda
        chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
std_to_ppm(FILE *         const ifP, 
Packit 78deda
           long           const chunksize, 
Packit 78deda
           BitMapHeader * const bmhdP, 
Packit 78deda
           ColorMap *     const cmap, 
Packit 78deda
           long           const viewportmodes) {
Packit 78deda
Packit 78deda
    if (viewportmodes & vmHAM) {
Packit 78deda
        ham_to_ppm(ifP, chunksize, bmhdP, cmap, viewportmodes);
Packit 78deda
    } else {
Packit 78deda
        unsigned int const cols = bmhdP->w;
Packit 78deda
        unsigned int const rows = bmhdP->h;
Packit 78deda
Packit 78deda
        rawtype *rawrow;
Packit 78deda
        unsigned int row, col;
Packit 78deda
        pixval maxval;
Packit 78deda
        unsigned long remainingChunksize;
Packit 78deda
        pixel * transpColorP;
Packit 78deda
Packit 78deda
        pm_message("input is a %d-plane %s%sILBM", bmhdP->nPlanes,
Packit 78deda
                   HAS_MULTIPALETTE(cmap) ? "multipalette " : "",
Packit 78deda
                   viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : ""
Packit 78deda
            );
Packit 78deda
Packit 78deda
        if( bmhdP->nPlanes > MAXPLANES )
Packit 78deda
            pm_error("too many planes (max %d)", MAXPLANES);
Packit 78deda
Packit 78deda
        if( HAS_COLORMAP(cmap) ) {
Packit 78deda
            if( viewportmodes & vmEXTRA_HALFBRITE )
Packit 78deda
                ehbcmap(cmap);  /* Modifies *cmap */
Packit 78deda
            maxval = MAXCOLVAL;
Packit 78deda
        }
Packit 78deda
        else {
Packit 78deda
            pm_message("no colormap - interpreting values as grayscale");
Packit 78deda
            maxval = lut_maxval(cmap, pm_bitstomaxval(bmhdP->nPlanes));
Packit 78deda
            if( maxval > PPM_OVERALLMAXVAL )
Packit 78deda
                pm_error("nPlanes is too large");
Packit 78deda
        }
Packit 78deda
Packit 78deda
        transpColorP = transpColor(bmhdP, cmap, transpName, maxval);
Packit 78deda
Packit 78deda
        rawrow = alloc_rawrow(cols);
Packit 78deda
Packit 78deda
        if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
            multi_init(cmap, viewportmodes);
Packit 78deda
Packit 78deda
        ppm_writeppminit( stdout, cols, rows, maxval, 0 );
Packit 78deda
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
    
Packit 78deda
        for (row = 0; row < rows; ++row) {
Packit 78deda
Packit 78deda
            if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
                multi_update(cmap, row);
Packit 78deda
Packit 78deda
            decode_row(ifP, &remainingChunksize, rawrow, bmhdP->nPlanes, bmhdP);
Packit 78deda
            decode_mask(ifP, &remainingChunksize, rawrow, bmhdP);
Packit 78deda
Packit 78deda
            for( col = 0; col < cols; col++ ) {
Packit 78deda
                pixval r, g, b;
Packit 78deda
                if( transpColorP && maskrow && maskrow[col] == PBM_WHITE )
Packit 78deda
                    pixelrow[col] = *transpColorP;
Packit 78deda
                else {
Packit 78deda
                    get_color(cmap, rawrow[col], &r, &g, &b);
Packit 78deda
                    PPM_ASSIGN(pixelrow[col], r, g, b);
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
Packit 78deda
        }
Packit 78deda
        chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
deep_to_ppm(FILE *         const ifP, 
Packit 78deda
            long           const chunksize, 
Packit 78deda
            BitMapHeader * const bmhdP, 
Packit 78deda
            ColorMap *     const cmap) {
Packit 78deda
Packit 78deda
    unsigned int const cols = bmhdP->w;
Packit 78deda
    unsigned int const rows = bmhdP->h;
Packit 78deda
    unsigned int const planespercolor = bmhdP->nPlanes / 3;
Packit 78deda
Packit 78deda
    unsigned int col, row;
Packit 78deda
    rawtype *Rrow, *Grow, *Brow;
Packit 78deda
    pixval maxval;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
    pixel * transpColorP;
Packit 78deda
Packit 78deda
    pm_message("input is a deep (%d-bit) ILBM", bmhdP->nPlanes);
Packit 78deda
    if( planespercolor > MAXPLANES )
Packit 78deda
        pm_error("too many planes (max %d)", MAXPLANES * 3);
Packit 78deda
Packit 78deda
    if( bmhdP->masking == mskHasTransparentColor || 
Packit 78deda
        bmhdP->masking == mskLasso ) {
Packit 78deda
        pm_message("masking type '%s' in a deep ILBM?? - ignoring it", 
Packit 78deda
                   mskNAME[bmhdP->masking]);
Packit 78deda
        bmhdP->masking = mskNone;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    maxval = lut_maxval(cmap, pm_bitstomaxval(planespercolor));
Packit 78deda
    if( maxval > PPM_OVERALLMAXVAL )
Packit 78deda
        pm_error("nPlanes is too large");
Packit 78deda
Packit 78deda
    transpColorP = transpColor(bmhdP, cmap, transpName, maxval);
Packit 78deda
        
Packit 78deda
    Rrow = alloc_rawrow(cols);
Packit 78deda
    Grow = alloc_rawrow(cols);
Packit 78deda
    Brow = alloc_rawrow(cols);
Packit 78deda
Packit 78deda
    ppm_writeppminit(stdout, cols, rows, maxval, 0);
Packit 78deda
Packit 78deda
    remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
    for( row = 0; row < rows; row++ ) {
Packit 78deda
        decode_row(ifP, &remainingChunksize, Rrow, planespercolor, bmhdP);
Packit 78deda
        decode_row(ifP, &remainingChunksize, Grow, planespercolor, bmhdP);
Packit 78deda
        decode_row(ifP, &remainingChunksize, Brow, planespercolor, bmhdP);
Packit 78deda
        decode_mask(ifP, &remainingChunksize, NULL, bmhdP);
Packit 78deda
Packit 78deda
        for( col = 0; col < cols; col++ ) {
Packit 78deda
            if( transpColorP && maskrow && maskrow[col] == PBM_WHITE )
Packit 78deda
                pixelrow[col] = *transpColorP;
Packit 78deda
            else
Packit 78deda
                PPM_ASSIGN(pixelrow[col],   lookup_red(cmap, Rrow[col]),
Packit 78deda
                                            lookup_green(cmap, Grow[col]),
Packit 78deda
                                            lookup_blue(cmap, Brow[col]) );
Packit 78deda
        }
Packit 78deda
        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
Packit 78deda
    }
Packit 78deda
    chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
dcol_to_ppm(FILE *         const ifP,
Packit 78deda
            long           const chunksize,
Packit 78deda
            BitMapHeader * const bmhdP,
Packit 78deda
            ColorMap *     const cmap,
Packit 78deda
            DirectColor *  const dcol) {
Packit 78deda
Packit 78deda
    unsigned int const cols = bmhdP->w;
Packit 78deda
    unsigned int const rows = bmhdP->h;
Packit 78deda
    unsigned int const redplanes   = dcol->r;
Packit 78deda
    unsigned int const greenplanes = dcol->g;
Packit 78deda
    unsigned int const blueplanes  = dcol->b;
Packit 78deda
    
Packit 78deda
    int col, row;
Packit 78deda
    rawtype *Rrow, *Grow, *Brow;
Packit 78deda
    pixval maxval, redmaxval, greenmaxval, bluemaxval;
Packit 78deda
    pixval *redtable, *greentable, *bluetable;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
    pixel * transpColorP;
Packit 78deda
Packit 78deda
    pm_message("input is a %d:%d:%d direct color ILBM",
Packit 78deda
                redplanes, greenplanes, blueplanes);
Packit 78deda
Packit 78deda
    if( redplanes > MAXPLANES || 
Packit 78deda
        blueplanes > MAXPLANES || 
Packit 78deda
        greenplanes > MAXPLANES )
Packit 78deda
        pm_error("too many planes (max %d per color component)", MAXPLANES);
Packit 78deda
Packit 78deda
    if( bmhdP->nPlanes != (redplanes + greenplanes + blueplanes) )
Packit 78deda
        pm_error("%s/%s plane number mismatch", 
Packit 78deda
                 ID2string(ID_BMHD), ID2string(ID_DCOL));
Packit 78deda
Packit 78deda
    if( bmhdP->masking == mskHasTransparentColor || 
Packit 78deda
        bmhdP->masking == mskLasso ) {
Packit 78deda
        pm_message("masking type '%s' in a direct color ILBM?? - ignoring it",
Packit 78deda
                   mskNAME[bmhdP->masking]);
Packit 78deda
        bmhdP->masking = mskNone;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if( HAS_COLORLUT(cmap) ) {
Packit 78deda
        pm_error("This program does not know how to process a %s chunk "
Packit 78deda
                 "in direct color", ID2string(ID_CLUT));
Packit 78deda
        cmap->redlut = cmap->greenlut = cmap->bluelut = NULL;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    redmaxval   = pm_bitstomaxval(redplanes);
Packit 78deda
    greenmaxval = pm_bitstomaxval(greenplanes);
Packit 78deda
    bluemaxval  = pm_bitstomaxval(blueplanes);
Packit 78deda
    maxval = MAX(redmaxval, MAX(greenmaxval, bluemaxval));
Packit 78deda
Packit 78deda
    if( maxval > PPM_OVERALLMAXVAL )
Packit 78deda
        pm_error("too many planes");
Packit 78deda
Packit 78deda
    if( redmaxval != maxval || greenmaxval != maxval || bluemaxval != maxval )
Packit 78deda
        pm_message("scaling colors to %d bits", pm_maxvaltobits(maxval));
Packit 78deda
    
Packit Service ad4525
    overflow_add(redmaxval, 1);
Packit Service ad4525
    overflow_add(greenmaxval, 1);
Packit Service ad4525
    overflow_add(bluemaxval, 1);
Packit 78deda
    MALLOCARRAY_NOFAIL(redtable,   redmaxval   +1);
Packit 78deda
    MALLOCARRAY_NOFAIL(greentable, greenmaxval +1);
Packit 78deda
    MALLOCARRAY_NOFAIL(bluetable,  bluemaxval  +1);
Packit 78deda
Packit 78deda
    {
Packit 78deda
        unsigned int i;
Packit 78deda
        for (i = 0; i <= redmaxval; ++i)
Packit 78deda
            redtable[i] = ROUNDDIV(i * maxval, redmaxval);
Packit 78deda
        for (i = 0; i <= greenmaxval; ++i)
Packit 78deda
            greentable[i] = ROUNDDIV(i * maxval, greenmaxval);
Packit 78deda
        for (i = 0; i <= bluemaxval; ++i)
Packit 78deda
            bluetable[i] = ROUNDDIV(i * maxval, bluemaxval);
Packit 78deda
    }
Packit 78deda
    transpColorP = transpColor(bmhdP, cmap, transpName, maxval);
Packit 78deda
Packit 78deda
    Rrow = alloc_rawrow(cols);
Packit 78deda
    Grow = alloc_rawrow(cols);
Packit 78deda
    Brow = alloc_rawrow(cols);
Packit 78deda
Packit 78deda
    ppm_writeppminit(stdout, cols, rows, maxval, 0);
Packit 78deda
Packit 78deda
    remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
    for( row = 0; row < rows; row++ ) {
Packit 78deda
        decode_row(ifP, &remainingChunksize, Rrow, redplanes, bmhdP);
Packit 78deda
        decode_row(ifP, &remainingChunksize, Grow, greenplanes, bmhdP);
Packit 78deda
        decode_row(ifP, &remainingChunksize, Brow, blueplanes, bmhdP);
Packit 78deda
        decode_mask(ifP, &remainingChunksize, NULL, bmhdP);
Packit 78deda
Packit 78deda
        for( col = 0; col < cols; col++ ) {
Packit 78deda
            if( transpColorP && maskrow && maskrow[col] == PBM_WHITE )
Packit 78deda
                pixelrow[col] = *transpColorP;
Packit 78deda
            else
Packit 78deda
                PPM_ASSIGN( pixelrow[col],  redtable[Rrow[col]],
Packit 78deda
                                            greentable[Grow[col]],
Packit 78deda
                                            bluetable[Brow[col]]   );
Packit 78deda
        }
Packit 78deda
        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
Packit 78deda
    }
Packit 78deda
    chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
cmapToPpm(FILE *     const ofP,
Packit 78deda
            ColorMap * const cmapP) {
Packit 78deda
Packit 78deda
    ppm_colorrowtomapfile(ofP, cmapP->color, cmapP->ncolors, MAXCOLVAL);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
ipbm_to_ppm(FILE *         const ifP,
Packit 78deda
            long           const chunksize,
Packit 78deda
            BitMapHeader * const bmhdP,
Packit 78deda
            ColorMap *     const cmap,
Packit 78deda
            long           const viewportmodes) {
Packit 78deda
Packit 78deda
    unsigned int const cols = bmhdP->w;
Packit 78deda
    unsigned int const rows = bmhdP->h;
Packit 78deda
Packit 78deda
    int col, row;
Packit 78deda
    pixval maxval;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
    pixel * transpColorP;
Packit 78deda
Packit 78deda
    pm_message("input is a %sPBM ", 
Packit 78deda
               HAS_MULTIPALETTE(cmap) ? "multipalette " : "");
Packit 78deda
Packit 78deda
    if( bmhdP->nPlanes != 8 )
Packit 78deda
        pm_error("invalid number of planes for IFF-PBM: %d (must be 8)", 
Packit 78deda
                 bmhdP->nPlanes);
Packit 78deda
Packit 78deda
    if( bmhdP->masking == mskHasMask )
Packit 78deda
        pm_error("Image has a maskplane, which is invalid in IFF-PBM");
Packit 78deda
Packit 78deda
    if( HAS_COLORMAP(cmap) )
Packit 78deda
        maxval = MAXCOLVAL;
Packit 78deda
    else {
Packit 78deda
        pm_message("no colormap - interpreting values as grayscale");
Packit 78deda
        maxval = lut_maxval(cmap, pm_bitstomaxval(bmhdP->nPlanes));
Packit 78deda
    }
Packit 78deda
Packit 78deda
    transpColorP = transpColor(bmhdP, cmap, transpName, maxval);
Packit 78deda
Packit 78deda
    if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
        multi_init(cmap, viewportmodes);
Packit 78deda
Packit 78deda
    MALLOCARRAY_NOFAIL(ilbmrow, cols);
Packit 78deda
Packit 78deda
    ppm_writeppminit(stdout, cols, rows, maxval, 0);
Packit 78deda
Packit 78deda
    remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
    for( row = 0; row < rows; row++ ) {
Packit 78deda
        if( HAS_MULTIPALETTE(cmap) )
Packit 78deda
            multi_update(cmap, row);
Packit 78deda
        
Packit 78deda
        read_ilbm_plane(ifP, &remainingChunksize, cols, bmhdP->compression);
Packit 78deda
Packit 78deda
        for( col = 0; col < cols; col++ ) {
Packit 78deda
            pixval r, g, b;
Packit 78deda
            if( transpColorP && maskrow && maskrow[col] == PBM_WHITE )
Packit 78deda
                pixelrow[col] = *transpColorP;
Packit 78deda
            else {
Packit 78deda
                get_color(cmap, ilbmrow[col], &r, &g, &b);
Packit 78deda
                PPM_ASSIGN(pixelrow[col], r, g, b);
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
Packit 78deda
    }
Packit 78deda
    chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
rgbn_to_ppm(FILE *         const ifP,
Packit 78deda
            long           const chunksize,
Packit 78deda
            BitMapHeader * const bmhdP,
Packit 78deda
            ColorMap *     const cmap  /* for CLUTs */
Packit 78deda
    ) {
Packit 78deda
Packit 78deda
    unsigned int const rows = bmhdP->h;
Packit 78deda
    unsigned int const cols = bmhdP->w;
Packit 78deda
Packit 78deda
    unsigned int row;
Packit 78deda
    unsigned int count;
Packit 78deda
    pixval maxval;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
    pixel * transpColorP;
Packit 78deda
Packit 78deda
    pm_message("input is a %d-bit RGB image", (typeid == ID_RGB8 ? 8 : 4));
Packit 78deda
Packit 78deda
    if (bmhdP->compression != 4)
Packit 78deda
        pm_error("invalid compression mode for %s: %d (must be 4)", 
Packit 78deda
                 ID2string(typeid), bmhdP->compression);
Packit 78deda
    
Packit 78deda
    switch (typeid) {
Packit 78deda
    case ID_RGBN:
Packit 78deda
        if (bmhdP->nPlanes != 13)
Packit 78deda
            pm_error("invalid number of planes for %s: %d (must be 13)", 
Packit 78deda
                     ID2string(typeid), bmhdP->nPlanes);
Packit 78deda
        maxval = lut_maxval(cmap, 15);
Packit 78deda
        break;
Packit 78deda
    case ID_RGB8:
Packit 78deda
        if (bmhdP->nPlanes != 25)
Packit 78deda
            pm_error("invalid number of planes for %s: %d (must be 25)", 
Packit 78deda
                     ID2string(typeid), bmhdP->nPlanes);
Packit 78deda
        maxval = 255;
Packit 78deda
        break;
Packit 78deda
    default:
Packit 78deda
        pm_error("rgbn_to_ppm(): invalid IFF ID %s - can't happen", 
Packit 78deda
                 ID2string(typeid));
Packit 78deda
    }
Packit 78deda
Packit 78deda
    transpColorP = transpColor(bmhdP, cmap, transpName, maxval);
Packit 78deda
Packit 78deda
    ppm_writeppminit(stdout, cols, rows, maxval, 0);
Packit 78deda
Packit 78deda
    for (row = 0, count = 0, remainingChunksize = chunksize;
Packit 78deda
         row < rows;
Packit 78deda
         ++row) {
Packit 78deda
Packit 78deda
        unsigned int col;
Packit 78deda
Packit 78deda
        for (col = 0; col < cols; ++col) {
Packit 78deda
            unsigned int tries;
Packit 78deda
            unsigned int genlock;
Packit 78deda
            pixval r, g, b;
Packit 78deda
Packit 78deda
            tries = 0;
Packit 78deda
            while (count == 0) {
Packit 78deda
                if (typeid == ID_RGB8) {
Packit 78deda
                    r = lookup_red(cmap,   get_byte(ifP, ID_BODY, 
Packit 78deda
                                                    &remainingChunksize));
Packit 78deda
                    g = lookup_green(cmap, get_byte(ifP, ID_BODY,
Packit 78deda
                                                    &remainingChunksize));
Packit 78deda
                    b = lookup_blue(cmap,  get_byte(ifP, ID_BODY,
Packit 78deda
                                                    &remainingChunksize));
Packit 78deda
                    count = get_byte(ifP, ID_BODY, &remainingChunksize);
Packit 78deda
                    genlock = count & 0x80;
Packit 78deda
                    count &= 0x7f;
Packit 78deda
                } else {
Packit 78deda
                    unsigned int const word =
Packit 78deda
                        get_big_short(ifP, ID_BODY, &remainingChunksize);
Packit 78deda
                    r = lookup_red(cmap, (word & 0xf000) >> 12);
Packit 78deda
                    g = lookup_green(cmap, (word & 0x0f00) >> 8);
Packit 78deda
                    b = lookup_blue(cmap, (word & 0x00f0) >> 4);
Packit 78deda
                    genlock = word & 0x0008;
Packit 78deda
                    count = word & 0x0007;
Packit 78deda
                }
Packit 78deda
                if (!count) {
Packit 78deda
                    count = get_byte(ifP, ID_BODY, &remainingChunksize);
Packit 78deda
                    if (count == 0)
Packit 78deda
                        count =
Packit 78deda
                            get_big_short(ifP, ID_BODY, &remainingChunksize);
Packit 78deda
                    if (count == 0)
Packit 78deda
                        ++tries;
Packit 78deda
                }
Packit 78deda
            }
Packit 78deda
            if (tries > 0) {
Packit 78deda
                pm_message("warning - repeat count 0 at col %u row %u: "
Packit 78deda
                           "skipped %u RGB entr%s",
Packit 78deda
                            col, row, tries, (tries == 1 ? "y" : "ies"));
Packit 78deda
            }
Packit 78deda
            if (maskfile) {
Packit 78deda
                /* genlock bit set -> transparent */
Packit 78deda
                if (genlock)
Packit 78deda
                    maskrow[col] = PBM_WHITE;
Packit 78deda
                else
Packit 78deda
                    maskrow[col] = PBM_BLACK;
Packit 78deda
            }
Packit 78deda
            if (transpColorP && maskrow && maskrow[col] == PBM_WHITE)
Packit 78deda
                pixelrow[col] = *transpColorP;
Packit 78deda
            else
Packit 78deda
                PPM_ASSIGN(pixelrow[col], r, g, b);
Packit 78deda
            --count;
Packit 78deda
        }
Packit 78deda
        ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
Packit 78deda
        if (maskfile) {
Packit 78deda
            pbm_writepbmrow(maskfile, maskrow, cols, 0);
Packit 78deda
            wrotemask = true;
Packit 78deda
        }
Packit 78deda
    }
Packit 78deda
    chunk_end(ifP, ID_BODY, remainingChunksize);
Packit 78deda
}
Packit 78deda
Packit 78deda
/****************************************************************************
Packit 78deda
 Multipalette chunk reader
Packit 78deda
Packit 78deda
    Currently there are three multipalette formats:
Packit 78deda
        SHAM - sliced HAM (obselete)
Packit 78deda
        CTBL - dynamic HAM/Hires (obselete)
Packit 78deda
        PCHG - palette change
Packit 78deda
    There is no official documentation available for SHAM and CTBL, so
Packit 78deda
   this is mostly guesswork from other sources and hexdumps of pictures...
Packit 78deda
Packit 78deda
    CTBL format (dynamic HAM/Hires):
Packit 78deda
        16 bigendian words per row (16 bit: 0000rrrrggggbbbb)
Packit 78deda
    This is simply an entire 4-bit colormap per row.
Packit 78deda
    I have no idea what the DYCP chunk is for.
Packit 78deda
Packit 78deda
    SHAM format (sliced HAM):
Packit 78deda
        1 word  - version info (?) - always 0
Packit 78deda
        16 bigendian words per row (16 bit: 0000rrrrggggbbbb)
Packit 78deda
    If the picture is laced, then there are only rows/2 changes, don't change
Packit 78deda
    palette on odd lines.
Packit 78deda
Packit 78deda
    PCHG format: A detailed description of this format is available
Packit 78deda
    from AmiNet as PCHGLib12.lha.
Packit 78deda
Packit 78deda
 ****************************************************************************/
Packit 78deda
Packit 78deda
/* Turn big-endian 4-byte long and 2-byte short stored at x (unsigned char *)
Packit 78deda
 * into the native format of the CPU
Packit 78deda
 */
Packit 78deda
#define BIG_LONG(x) (   ((unsigned long)((x)[0]) << 24) + \
Packit 78deda
                        ((unsigned long)((x)[1]) << 16) + \
Packit 78deda
                        ((unsigned long)((x)[2]) <<  8) + \
Packit 78deda
                        ((unsigned long)((x)[3]) <<  0) )
Packit 78deda
#define BIG_WORD(x) (   ((unsigned short)((x)[0]) << 8) + \
Packit 78deda
                        ((unsigned short)((x)[1]) << 0) )
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_4bit_mp(FILE *     const ifP,
Packit 78deda
             IFF_ID     const iffid,
Packit 78deda
             long       const chunksize,
Packit 78deda
             ColorMap * const cmap) {
Packit 78deda
Packit 78deda
    int row, rows, i, type;
Packit 78deda
    short data;
Packit 78deda
    unsigned long remainingChunksize;
Packit 78deda
Packit 78deda
    type = (iffid == ID_SHAM ? MP_TYPE_SHAM : MP_TYPE_CTBL);
Packit 78deda
Packit 78deda
    if( cmap->mp_type >= type ) {
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else {
Packit 78deda
        if( cmap->mp_type )
Packit 78deda
            multi_free(cmap);
Packit 78deda
        cmap->mp_type = type;
Packit 78deda
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
        if( type == MP_TYPE_SHAM ) {
Packit 78deda
            cmap->mp_flags = MP_FLAGS_SKIPLACED;
Packit 78deda
            get_big_short(ifP, iffid, &remainingChunksize); /* skip first wd */
Packit 78deda
        }
Packit 78deda
Packit 78deda
        cmap->mp_rows = rows = remainingChunksize/32; /* sizeof(word) * 16 */
Packit 78deda
        MALLOCARRAY_NOFAIL(cmap->mp_change, rows);
Packit 78deda
Packit 78deda
        for( row = 0; row < rows; row++ ) {
Packit 78deda
            MALLOCARRAY_NOFAIL(cmap->mp_change[row], 17);   /* 16 + sentinel */
Packit 78deda
            for( i = 0; i < 16; i++ ) {
Packit 78deda
                data = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
                cmap->mp_change[row][i].reg = i;
Packit 78deda
                cmap->mp_change[row][i].r =
Packit 78deda
                    ((data & 0x0f00) >> 8) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_change[row][i].g =
Packit 78deda
                    ((data & 0x00f0) >> 4) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_change[row][i].b =
Packit 78deda
                    ((data & 0x000f) >> 0) * FACTOR_4BIT;
Packit 78deda
            }
Packit 78deda
            cmap->mp_change[row][16].reg = MP_REG_END;   /* sentinel */
Packit 78deda
        }
Packit 78deda
        chunk_end(ifP, iffid, remainingChunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
PCHG_DecompHuff(src, dest, tree, origsize)
Packit 78deda
    unsigned char *src, *dest;
Packit 78deda
    short *tree;
Packit 78deda
    unsigned long origsize;
Packit 78deda
{
Packit 78deda
    unsigned long i = 0, bits = 0;
Packit 78deda
    unsigned char thisbyte;
Packit 78deda
    short *p;
Packit 78deda
Packit 78deda
    p = tree;
Packit 78deda
    while( i < origsize ) {
Packit 78deda
        if( bits == 0 ) {
Packit 78deda
            thisbyte = *src++;
Packit 78deda
            bits = 8;
Packit 78deda
        }
Packit 78deda
        if( thisbyte & (1 << 7) ) {
Packit 78deda
            if( *p >= 0 ) {
Packit 78deda
                *dest++ = (unsigned char)*p;
Packit 78deda
                i++;
Packit 78deda
                p = tree;
Packit 78deda
            }
Packit 78deda
            else
Packit 78deda
                p += (*p / 2);
Packit 78deda
        }
Packit 78deda
        else {
Packit 78deda
            p--;
Packit 78deda
            if( *p > 0 && (*p & 0x100) ) {
Packit 78deda
                *dest++ = (unsigned char )*p;
Packit 78deda
                i++;
Packit 78deda
                p = tree;
Packit 78deda
            }
Packit 78deda
        }
Packit 78deda
        thisbyte <<= 1;
Packit 78deda
        bits--;
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
PCHG_Decompress(PCHGHeader *     const PCHG,
Packit 78deda
                PCHGCompHeader * const CompHdr,
Packit 78deda
                unsigned char *  const compdata,
Packit 78deda
                unsigned long    const compsize,
Packit 78deda
                unsigned char *  const comptree,
Packit 78deda
                unsigned char *  const data) {
Packit 78deda
Packit 78deda
    switch(PCHG->Compression) {
Packit 78deda
    case PCHG_COMP_HUFFMAN: {
Packit 78deda
        unsigned long const treesize = CompHdr->CompInfoSize;
Packit 78deda
        unsigned long const huffsize = treesize / 2;
Packit 78deda
        const bigend16 * const bigendComptree = (const void *)comptree;
Packit 78deda
Packit 78deda
        short * hufftree;
Packit 78deda
        unsigned long i;
Packit 78deda
Packit 78deda
        /* Convert big-endian 2-byte shorts to C shorts */
Packit 78deda
Packit 78deda
        MALLOCARRAY(hufftree, huffsize);
Packit 78deda
Packit 78deda
        if (!hufftree)
Packit 78deda
            pm_error("Couldn't get memory for %lu-byte Huffman tree",
Packit 78deda
                     huffsize);
Packit 78deda
Packit 78deda
        for (i = 0; i < huffsize; ++i)
Packit 78deda
            hufftree[i] = pm_uintFromBigend16(bigendComptree[i]);
Packit 78deda
Packit 78deda
        /* decompress the change structure data */
Packit 78deda
        PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], 
Packit 78deda
                        CompHdr->OriginalDataSize);
Packit 78deda
        
Packit 78deda
        free(hufftree);
Packit 78deda
    } break;
Packit 78deda
        default:
Packit 78deda
            pm_error("unknown PCHG compression type %d", PCHG->Compression);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
PCHG_ConvertSmall(PCHG, cmap, mask, datasize)
Packit 78deda
    PCHGHeader *PCHG;
Packit 78deda
    ColorMap *cmap;
Packit 78deda
    unsigned char *mask;
Packit 78deda
    unsigned long datasize;
Packit 78deda
{
Packit 78deda
    unsigned char *data;
Packit 78deda
    unsigned char thismask;
Packit 78deda
    int bits, row, i, changes, masklen, reg;
Packit 78deda
    unsigned char ChangeCount16, ChangeCount32;
Packit 78deda
    unsigned short SmallChange;
Packit 78deda
    unsigned long totalchanges = 0;
Packit 78deda
    int changedlines = PCHG->ChangedLines;
Packit 78deda
Packit 78deda
    masklen = 4 * MaskLongWords(PCHG->LineCount);
Packit 78deda
    data = mask + masklen; datasize -= masklen;
Packit 78deda
Packit 78deda
    bits = 0;
Packit 78deda
    for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
Packit 78deda
        if( bits == 0 ) {
Packit 78deda
            if( masklen == 0 ) goto fail2;
Packit 78deda
            thismask = *mask++;
Packit 78deda
            --masklen;
Packit 78deda
            bits = 8;
Packit 78deda
        }
Packit 78deda
        if( thismask & (1<<7) ) {
Packit 78deda
            if( datasize < 2 ) goto fail;
Packit 78deda
            ChangeCount16 = *data++;
Packit 78deda
            ChangeCount32 = *data++;
Packit 78deda
            datasize -= 2;
Packit 78deda
Packit Service ad4525
            overflow_add(ChangeCount16, ChangeCount32);
Packit 78deda
            changes = ChangeCount16 + ChangeCount32;
Packit Service ad4525
            overflow_add(changes, 1);
Packit 78deda
            for( i = 0; i < changes; i++ ) {
Packit 78deda
                if( totalchanges >= PCHG->TotalChanges ) goto fail;
Packit 78deda
                if( datasize < 2 ) goto fail;
Packit 78deda
                SmallChange = BIG_WORD(data); data += 2; datasize -= 2;
Packit 78deda
                reg = ((SmallChange & 0xf000) >> 12) + 
Packit 78deda
                    (i >= ChangeCount16 ? 16 : 0);
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].reg = reg;
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].r = 
Packit 78deda
                    ((SmallChange & 0x0f00) >> 8) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].g = 
Packit 78deda
                    ((SmallChange & 0x00f0) >> 4) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].b = 
Packit 78deda
                    ((SmallChange & 0x000f) >> 0) * FACTOR_4BIT;
Packit 78deda
                ++totalchanges;
Packit 78deda
            }
Packit 78deda
            --changedlines;
Packit 78deda
        }
Packit 78deda
        thismask <<= 1;
Packit 78deda
        bits--;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
Packit 78deda
        if( bits == 0 ) {
Packit 78deda
            if( masklen == 0 ) goto fail2;
Packit 78deda
            thismask = *mask++;
Packit 78deda
            --masklen;
Packit 78deda
            bits = 8;
Packit 78deda
        }
Packit 78deda
        if( thismask & (1<<7) ) {
Packit 78deda
            if( datasize < 2 ) goto fail;
Packit 78deda
            ChangeCount16 = *data++;
Packit 78deda
            ChangeCount32 = *data++;
Packit 78deda
            datasize -= 2;
Packit 78deda
Packit 78deda
            changes = ChangeCount16 + ChangeCount32;
Packit 78deda
            MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1);
Packit 78deda
            for( i = 0; i < changes; i++ ) {
Packit 78deda
                if( totalchanges >= PCHG->TotalChanges ) goto fail;
Packit 78deda
                if( datasize < 2 ) goto fail;
Packit 78deda
                SmallChange = BIG_WORD(data); data += 2; datasize -= 2;
Packit 78deda
                reg = ((SmallChange & 0xf000) >> 12) + 
Packit 78deda
                    (i >= ChangeCount16 ? 16 : 0);
Packit 78deda
                cmap->mp_change[row][i].reg = reg;
Packit 78deda
                cmap->mp_change[row][i].r = 
Packit 78deda
                    ((SmallChange & 0x0f00) >> 8) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_change[row][i].g = 
Packit 78deda
                    ((SmallChange & 0x00f0) >> 4) * FACTOR_4BIT;
Packit 78deda
                cmap->mp_change[row][i].b = 
Packit 78deda
                    ((SmallChange & 0x000f) >> 0) * FACTOR_4BIT;
Packit 78deda
                ++totalchanges;
Packit 78deda
            }
Packit 78deda
            cmap->mp_change[row][changes].reg = MP_REG_END;
Packit 78deda
            --changedlines;
Packit 78deda
        }
Packit 78deda
        thismask <<= 1;
Packit 78deda
        bits--;
Packit 78deda
    }
Packit 78deda
    if( totalchanges != PCHG->TotalChanges )
Packit 78deda
        pm_message("warning - got %ld change structures, "
Packit 78deda
                   "chunk header reports %ld", 
Packit 78deda
                   totalchanges, PCHG->TotalChanges);
Packit 78deda
    return;
Packit 78deda
fail:
Packit 78deda
    pm_error("insufficient data in SmallLineChanges structures");
Packit 78deda
fail2:
Packit 78deda
    pm_error("insufficient data in line mask");
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
PCHG_ConvertBig(PCHGHeader *    const PCHG,
Packit 78deda
                ColorMap *      const cmap,
Packit 78deda
                unsigned char * const maskStart,
Packit 78deda
                unsigned long   const datasize) {
Packit 78deda
Packit 78deda
    unsigned char * data;
Packit 78deda
    unsigned char thismask;
Packit 78deda
    int bits;
Packit 78deda
    unsigned int row;
Packit 78deda
    int changes;
Packit 78deda
    int masklen;
Packit 78deda
    int reg;
Packit 78deda
    unsigned long totalchanges;
Packit 78deda
    int changedlines;
Packit 78deda
    unsigned long dataRemaining;
Packit 78deda
    unsigned char * mask;
Packit 78deda
Packit 78deda
    mask = maskStart;  /* initial value */
Packit 78deda
    dataRemaining = datasize;  /* initial value */
Packit 78deda
    changedlines = PCHG->ChangedLines;  /* initial value */
Packit 78deda
    totalchanges = 0;  /* initial value */
Packit 78deda
Packit 78deda
    masklen = 4 * MaskLongWords(PCHG->LineCount);
Packit 78deda
    data = mask + masklen; dataRemaining -= masklen;
Packit 78deda
Packit 78deda
    for (row = PCHG->StartLine, bits = 0; changedlines && row < 0; ++row) {
Packit 78deda
        if (bits == 0) {
Packit 78deda
            if (masklen == 0)
Packit 78deda
                pm_error("insufficient data in line mask");
Packit 78deda
            thismask = *mask++;
Packit 78deda
            --masklen;
Packit 78deda
            bits = 8;
Packit 78deda
        }
Packit 78deda
        if (thismask & (1<<7)) {
Packit 78deda
            unsigned int i;
Packit 78deda
Packit 78deda
            if (dataRemaining < 2)
Packit 78deda
                pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
Packit 78deda
Packit 78deda
            for (i = 0; i < changes; ++i) {
Packit 78deda
                if (totalchanges >= PCHG->TotalChanges)
Packit 78deda
                    pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
                if (dataRemaining < 6)
Packit 78deda
                    pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
                reg = BIG_WORD(data); data += 2;
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].reg = reg;
Packit 78deda
                ++data; /* skip alpha */
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].r = *data++;
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].b = *data++;  /* yes, RBG */
Packit 78deda
                cmap->mp_init[reg - PCHG->MinReg].g = *data++;
Packit 78deda
                dataRemaining -= 6;
Packit 78deda
                ++totalchanges;
Packit 78deda
            }
Packit 78deda
            --changedlines;
Packit 78deda
        }
Packit 78deda
        thismask <<= 1;
Packit 78deda
        --bits;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    for (row = PCHG->StartLine; changedlines && row < cmap->mp_rows; ++row) {
Packit 78deda
        if (bits == 0) {
Packit 78deda
            if (masklen == 0)
Packit 78deda
                pm_error("insufficient data in line mask");
Packit 78deda
Packit 78deda
            thismask = *mask++;
Packit 78deda
            --masklen;
Packit 78deda
            bits = 8;
Packit 78deda
        }
Packit 78deda
        if (thismask & (1<<7)) {
Packit 78deda
            unsigned int i;
Packit 78deda
Packit 78deda
            if (dataRemaining < 2)
Packit 78deda
                pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
            changes = BIG_WORD(data); data += 2; dataRemaining -= 2;
Packit 78deda
Packit 78deda
            MALLOCARRAY_NOFAIL(cmap->mp_change[row], changes + 1);
Packit 78deda
            for (i = 0; i < changes; ++i) {
Packit 78deda
                if (totalchanges >= PCHG->TotalChanges)
Packit 78deda
                    pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
                if (dataRemaining < 6)
Packit 78deda
                    pm_error("insufficient data in BigLineChanges structures");
Packit 78deda
Packit 78deda
                reg = BIG_WORD(data); data += 2;
Packit 78deda
                cmap->mp_change[row][i].reg = reg;
Packit 78deda
                ++data; /* skip alpha */
Packit 78deda
                cmap->mp_change[row][i].r = *data++;
Packit 78deda
                cmap->mp_change[row][i].b = *data++;    /* yes, RBG */
Packit 78deda
                cmap->mp_change[row][i].g = *data++;
Packit 78deda
                dataRemaining -= 6;
Packit 78deda
                ++totalchanges;
Packit 78deda
            }
Packit 78deda
            cmap->mp_change[row][changes].reg = MP_REG_END;
Packit 78deda
            --changedlines;
Packit 78deda
        }
Packit 78deda
        thismask <<= 1;
Packit 78deda
        --bits;
Packit 78deda
    }
Packit 78deda
    if (totalchanges != PCHG->TotalChanges)
Packit 78deda
        pm_message("warning - got %ld change structures, "
Packit 78deda
                   "chunk header reports %ld", 
Packit 78deda
                   totalchanges, PCHG->TotalChanges);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
read_pchg(FILE *     const ifP,
Packit 78deda
          IFF_ID     const iffid,
Packit 78deda
          long       const chunksize,
Packit 78deda
          ColorMap * const cmap) {
Packit 78deda
Packit 78deda
    if( cmap->mp_type >= MP_TYPE_PCHG ) {
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else {
Packit 78deda
        PCHGHeader      PCHG;
Packit 78deda
        unsigned char   *data;
Packit 78deda
        unsigned long   datasize;
Packit 78deda
        unsigned long   remainingChunksize;
Packit 78deda
        int i;
Packit 78deda
Packit 78deda
        if( cmap->mp_type )
Packit 78deda
            multi_free(cmap);
Packit 78deda
        cmap->mp_type = MP_TYPE_PCHG;
Packit 78deda
Packit 78deda
        remainingChunksize = chunksize;  /* initial value */
Packit 78deda
Packit 78deda
        PCHG.Compression = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.Flags       = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.StartLine   = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.LineCount   = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.ChangedLines= get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.MinReg      = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.MaxReg      = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.MaxChanges  = get_big_short(ifP, iffid, &remainingChunksize);
Packit 78deda
        PCHG.TotalChanges= get_big_long(ifP, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
#ifdef DEBUG
Packit 78deda
        pm_message("PCHG StartLine   : %d", PCHG.StartLine);
Packit 78deda
        pm_message("PCHG LineCount   : %d", PCHG.LineCount);
Packit 78deda
        pm_message("PCHG ChangedLines: %d", PCHG.ChangedLines);
Packit 78deda
        pm_message("PCHG TotalChanges: %d", PCHG.TotalChanges);
Packit 78deda
#endif
Packit 78deda
Packit 78deda
        if( PCHG.Compression != PCHG_COMP_NONE ) {
Packit 78deda
            PCHGCompHeader  CompHdr;
Packit 78deda
            unsigned char *compdata, *comptree;
Packit 78deda
            long treesize, compsize;
Packit 78deda
Packit 78deda
            CompHdr.CompInfoSize     =
Packit 78deda
                get_big_long(ifP, iffid, &remainingChunksize);
Packit 78deda
            CompHdr.OriginalDataSize =
Packit 78deda
                get_big_long(ifP, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
            treesize = CompHdr.CompInfoSize;
Packit 78deda
            MALLOCARRAY_NOFAIL(comptree, treesize);
Packit 78deda
            read_bytes(ifP, treesize, comptree, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
            compsize = remainingChunksize;
Packit 78deda
            MALLOCARRAY_NOFAIL(compdata, compsize);
Packit 78deda
            read_bytes(ifP, compsize, compdata, iffid, &remainingChunksize);
Packit 78deda
Packit 78deda
            datasize = CompHdr.OriginalDataSize;
Packit 78deda
            MALLOCARRAY_NOFAIL(data, datasize);
Packit 78deda
            PCHG_Decompress(&PCHG, &CompHdr, compdata, 
Packit 78deda
                            compsize, comptree, data);
Packit 78deda
Packit 78deda
            free(comptree);
Packit 78deda
            free(compdata);
Packit 78deda
        } else {
Packit 78deda
#ifdef DEBUG
Packit 78deda
            pm_message("uncompressed PCHG");
Packit 78deda
#endif
Packit 78deda
            datasize = remainingChunksize;
Packit 78deda
            MALLOCARRAY_NOFAIL(data, datasize);
Packit 78deda
            read_bytes(ifP, datasize, data, iffid, &remainingChunksize);
Packit 78deda
        }
Packit 78deda
Packit 78deda
        if( PCHG.Flags & PCHGF_USE_ALPHA )
Packit 78deda
            pm_message("warning - ignoring PCHG alpha channel because "
Packit 78deda
                       "this program doesn't know what to do with it");
Packit 78deda
Packit 78deda
        cmap->mp_rows = PCHG.StartLine + PCHG.LineCount;
Packit 78deda
        MALLOCARRAY_NOFAIL(cmap->mp_change, cmap->mp_rows);
Packit 78deda
        for( i = 0; i < cmap->mp_rows; i++ )
Packit 78deda
            cmap->mp_change[i] = NULL;
Packit 78deda
        if( PCHG.StartLine < 0 ) {
Packit 78deda
            int nch;
Packit Service ad4525
            if(PCHG.MaxReg < PCHG.MinReg)
Packit Service ad4525
                pm_error("assert: MinReg > MaxReg");
Packit Service ad4525
            overflow_add(PCHG.MaxReg-PCHG.MinReg, 2);
Packit 78deda
            nch = PCHG.MaxReg - PCHG.MinReg +1;
Packit 78deda
            MALLOCARRAY_NOFAIL(cmap->mp_init, nch + 1);
Packit 78deda
            for( i = 0; i < nch; i++ )
Packit 78deda
                cmap->mp_init[i].reg = MP_REG_IGNORE;
Packit 78deda
            cmap->mp_init[nch].reg = MP_REG_END;
Packit 78deda
        }
Packit 78deda
Packit 78deda
        if( PCHG.Flags & PCHGF_12BIT ) {
Packit 78deda
#ifdef DEBUG
Packit 78deda
            pm_message("SmallLineChanges");
Packit 78deda
#endif
Packit 78deda
            PCHG_ConvertSmall(&PCHG, cmap, data, datasize);
Packit 78deda
        }
Packit 78deda
        else {
Packit 78deda
            if( PCHG.Flags & PCHGF_32BIT ) {
Packit 78deda
#ifdef DEBUG
Packit 78deda
                pm_message("BigLineChanges");
Packit 78deda
#endif
Packit 78deda
                PCHG_ConvertBig(&PCHG, cmap, data, datasize);
Packit 78deda
            }
Packit 78deda
            else
Packit 78deda
                pm_error("unknown palette changes structure "
Packit 78deda
                         "format in %s chunk", 
Packit 78deda
                         ID2string(iffid));
Packit 78deda
        }
Packit 78deda
        free(data);
Packit 78deda
        chunk_end(ifP, iffid, remainingChunksize);
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static bool
Packit 78deda
ignored_iffid(IFF_ID       const iffid,
Packit 78deda
              IFF_ID       const ignorelist[],
Packit 78deda
              unsigned int const ignorecount) {
Packit 78deda
Packit 78deda
    bool ignore;
Packit 78deda
Packit 78deda
    unsigned int i;
Packit 78deda
    ignore = FALSE;  /* initial assumption */
Packit 78deda
    for( i = 0; i < ignorecount && !ignore; i++ ) {
Packit 78deda
        if( iffid == ignorelist[i] )
Packit 78deda
            ignore = TRUE;
Packit 78deda
    }
Packit 78deda
    return ignore;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void 
Packit 78deda
process_body( FILE *          const ifP,
Packit 78deda
              long            const chunksize,
Packit 78deda
              BitMapHeader *  const bmhdP,
Packit 78deda
              ColorMap *      const cmap,
Packit 78deda
              FILE *          const maskfile,
Packit 78deda
              int             const fakeviewport,
Packit 78deda
              int             const isdeepopt,
Packit 78deda
              DirectColor *   const dcol,
Packit 78deda
              int *           const viewportmodesP) {
Packit 78deda
    
Packit 78deda
    if (bmhdP == NULL)
Packit 78deda
        pm_error("%s chunk without %s chunk", 
Packit 78deda
                 ID2string(ID_BODY), ID2string(ID_BMHD));
Packit 78deda
Packit 78deda
    prepareCmap(bmhdP, cmap);
Packit 78deda
Packit 78deda
    pixelrow = ppm_allocrow(bmhdP->w);
Packit 78deda
    if (maskfile) {
Packit 78deda
        maskrow = pbm_allocrow(bmhdP->w);
Packit 78deda
        pbm_writepbminit(maskfile, bmhdP->w, bmhdP->h, 0);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if (typeid == ID_ILBM) {
Packit 78deda
        int isdeep;
Packit 78deda
Packit Service ad4525
        overflow_add(bmhdP->w, 15);
Packit 78deda
        MALLOCARRAY_NOFAIL(ilbmrow, RowBytes(bmhdP->w));
Packit 78deda
        *viewportmodesP |= fakeviewport;      /* -isham/-isehb */
Packit 78deda
Packit 78deda
        if( isdeepopt > 0 && (bmhdP->nPlanes % 3 != 0) ) {
Packit 78deda
            pm_message("cannot interpret %d-plane image as 'deep' "
Packit 78deda
                       "(# of planes must be divisible by 3)", 
Packit 78deda
                       bmhdP->nPlanes);
Packit 78deda
            isdeep = 0;
Packit 78deda
        } else
Packit 78deda
            isdeep = isdeepopt;
Packit 78deda
        
Packit 78deda
        if (isdeep > 0)
Packit 78deda
            deep_to_ppm(ifP, chunksize, bmhdP, cmap);
Packit 78deda
        else if (dcol)
Packit 78deda
            dcol_to_ppm(ifP, chunksize, bmhdP, cmap, dcol);
Packit 78deda
        else if (bmhdP->nPlanes > 8) {
Packit 78deda
            if (bmhdP->nPlanes <= 16 && HAS_COLORMAP(cmap))
Packit 78deda
                std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP);
Packit 78deda
            else if (isdeep >= 0 && (bmhdP->nPlanes % 3 == 0))
Packit 78deda
                deep_to_ppm(ifP, chunksize, bmhdP, cmap);
Packit 78deda
            else if (bmhdP->nPlanes <= 16)
Packit 78deda
                /* will be interpreted as grayscale */
Packit 78deda
                std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP);
Packit 78deda
            else
Packit 78deda
                pm_error("don't know how to interpret %d-plane image", 
Packit 78deda
                         bmhdP->nPlanes);
Packit 78deda
        } else
Packit 78deda
            std_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP);
Packit 78deda
    } else if( typeid == ID_PBM )
Packit 78deda
        ipbm_to_ppm(ifP, chunksize, bmhdP, cmap, *viewportmodesP);
Packit 78deda
    else   /* RGBN or RGB8 */
Packit 78deda
        rgbn_to_ppm(ifP, chunksize, bmhdP, cmap);
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void 
Packit 78deda
processChunk(FILE *          const ifP,
Packit 78deda
             long            const formsize,
Packit 78deda
             IFF_ID          const ignorelist[],
Packit 78deda
             unsigned int    const ignorecount,
Packit 78deda
             int             const fakeviewport,
Packit 78deda
             int             const viewportmask,
Packit 78deda
             int             const isdeepopt,
Packit 78deda
             bool            const cmaponly,
Packit 78deda
             bool *          const bodyChunkProcessedP,
Packit 78deda
             bool *          const endchunkP,
Packit 78deda
             BitMapHeader ** const bmhdP,
Packit 78deda
             ColorMap *      const cmap,
Packit 78deda
             DirectColor **  const dcolP,
Packit 78deda
             int *           const viewportmodesP,
Packit 78deda
             long *          const bytesReadP
Packit 78deda
    ) {
Packit 78deda
Packit 78deda
    IFF_ID iffid;
Packit 78deda
    long chunksize;
Packit 78deda
    long bytesread;
Packit 78deda
Packit 78deda
    bytesread = 0;
Packit 78deda
Packit 78deda
    iffid = get_big_long(ifP, ID_FORM, NULL);
Packit 78deda
    chunksize = get_big_long(ifP, iffid, NULL);
Packit 78deda
    bytesread += 8;
Packit 78deda
Packit 78deda
    if (debug)
Packit 78deda
        pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize);
Packit 78deda
Packit 78deda
    if (ignored_iffid(iffid, ignorelist, ignorecount)) {
Packit 78deda
        pm_message("ignoring %s chunk", ID2string(iffid));
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else if (iffid == ID_END) {
Packit 78deda
        /* END chunks are not officially valid in IFF, but
Packit 78deda
           suggested as a future expansion for stream-writing,
Packit 78deda
           see Amiga RKM Devices, 3rd Ed, page 376 
Packit 78deda
        */
Packit 78deda
        if (chunksize != 0 ) {
Packit 78deda
            pm_message("warning - non-0 %s chunk", ID2string(iffid));
Packit 78deda
            skip_chunk(ifP, iffid, chunksize);
Packit 78deda
        }
Packit 78deda
        if (formsize != 0xffffffff)
Packit 78deda
            pm_message("warning - %s chunk with FORM size 0x%08lx "
Packit 78deda
                       "(should be 0x%08x)",
Packit 78deda
                       ID2string(iffid), formsize, 0xffffffff);
Packit 78deda
        *endchunkP = 1;
Packit 78deda
    } else if (*bodyChunkProcessedP) {
Packit 78deda
        pm_message("%s chunk found after %s chunk - skipping", 
Packit 78deda
                   ID2string(iffid), ID2string(ID_BODY));
Packit 78deda
        skip_chunk(ifP, iffid, chunksize);
Packit 78deda
    } else
Packit 78deda
        switch (iffid) {
Packit 78deda
        case ID_BMHD:
Packit 78deda
            *bmhdP = read_bmhd(ifP, iffid, chunksize);
Packit 78deda
            break;
Packit 78deda
        case ID_CMAP:
Packit 78deda
            read_cmap(ifP, iffid, chunksize, cmap);
Packit 78deda
            break;
Packit 78deda
        case ID_CMYK:
Packit 78deda
            read_cmyk(ifP, iffid, chunksize, cmap);
Packit 78deda
            break;
Packit 78deda
        case ID_CLUT:
Packit 78deda
            read_clut(ifP, iffid, chunksize, cmap);
Packit 78deda
            break;
Packit 78deda
        case ID_CAMG:
Packit 78deda
            if (chunksize != CAMGChunkSize)
Packit 78deda
                pm_error("%s chunk size mismatch", ID2string(iffid));
Packit 78deda
            *viewportmodesP = get_big_long(ifP, ID_CAMG, NULL);
Packit 78deda
            *viewportmodesP &= viewportmask;      /* -isnotham/-isnotehb */
Packit 78deda
            break;
Packit 78deda
        case ID_PCHG:
Packit 78deda
            read_pchg(ifP, iffid, chunksize, cmap);
Packit 78deda
            break;
Packit 78deda
        case ID_CTBL:
Packit 78deda
        case ID_SHAM:
Packit 78deda
            read_4bit_mp(ifP, iffid, chunksize, cmap);
Packit 78deda
            break;
Packit 78deda
        case ID_DCOL:
Packit 78deda
            if (chunksize != DirectColorSize)
Packit 78deda
                pm_error("%s chunk size mismatch", ID2string(iffid));
Packit 78deda
            MALLOCVAR_NOFAIL(*dcolP);
Packit 78deda
            (*dcolP)->r = get_byte(ifP, iffid, NULL);
Packit 78deda
            (*dcolP)->g = get_byte(ifP, iffid, NULL);
Packit 78deda
            (*dcolP)->b = get_byte(ifP, iffid, NULL);
Packit 78deda
            get_byte(ifP, iffid, NULL);       /* skip pad byte */
Packit 78deda
            break;
Packit 78deda
        case ID_BODY: 
Packit 78deda
            if (cmaponly || (*bmhdP && (*bmhdP)->nPlanes == 0))
Packit 78deda
                skip_chunk(ifP, ID_BODY,  chunksize);
Packit 78deda
            else {
Packit 78deda
                process_body(ifP, chunksize, *bmhdP, cmap, 
Packit 78deda
                             maskfile, fakeviewport, isdeepopt, *dcolP,
Packit 78deda
                             viewportmodesP);
Packit 78deda
Packit 78deda
                *bodyChunkProcessedP = TRUE;
Packit 78deda
            } break;
Packit 78deda
        case ID_GRAB:   case ID_DEST:   case ID_SPRT:   case ID_CRNG:
Packit 78deda
        case ID_CCRT:   case ID_DYCP:   case ID_DPPV:   case ID_DRNG:
Packit 78deda
        case ID_EPSF:   case ID_JUNK:   case ID_CNAM:   case ID_PRVW:
Packit 78deda
        case ID_TINY:   case ID_DPPS:
Packit 78deda
            skip_chunk(ifP, iffid, chunksize);
Packit 78deda
            break;
Packit 78deda
        case ID_copy:   case ID_AUTH:   case ID_NAME:   case ID_ANNO:
Packit 78deda
        case ID_TEXT:   case ID_FVER:
Packit 78deda
            if (verbose)
Packit 78deda
                display_chunk(ifP, iffid, chunksize);
Packit 78deda
            else
Packit 78deda
                skip_chunk(ifP, iffid, chunksize);
Packit 78deda
            break;
Packit 78deda
        case ID_DPI: {
Packit 78deda
            int x, y;
Packit 78deda
Packit 78deda
            x = get_big_short(ifP, ID_DPI, NULL);
Packit 78deda
            y = get_big_short(ifP, ID_DPI, NULL);
Packit 78deda
            if (verbose)
Packit 78deda
                pm_message("%s chunk:  dpi_x = %d    dpi_y = %d", 
Packit 78deda
                           ID2string(ID_DPI), x, y);
Packit 78deda
        } break;
Packit 78deda
        default:
Packit 78deda
            pm_message("unknown chunk type %s - skipping", 
Packit 78deda
                       ID2string(iffid));
Packit 78deda
            skip_chunk(ifP, iffid, chunksize);
Packit 78deda
            break;
Packit 78deda
        }
Packit 78deda
Packit 78deda
    bytesread += chunksize;
Packit 78deda
Packit 78deda
    if (ODD(chunksize)) {
Packit 78deda
        get_byte(ifP, iffid, NULL);
Packit 78deda
        bytesread += 1;
Packit 78deda
    } 
Packit 78deda
    *bytesReadP = bytesread;
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
static void
Packit 78deda
maybeWriteColorMap(FILE *               const ofP,
Packit 78deda
                   const BitMapHeader * const bmhdP,
Packit 78deda
                   ColorMap *           const cmapP,
Packit 78deda
                   bool                 const bodyChunkProcessed,
Packit 78deda
                   bool                 const cmaponly) {
Packit 78deda
/*----------------------------------------------------------------------------
Packit 78deda
   Write to file *ofP the color map *cmapP as a PPM, if appropriate.
Packit 78deda
Packit 78deda
   The logic (not just here -- in the program as a whole) for deciding whether
Packit 78deda
   to write the image or the colormap is quite twisted.  If I thought anyone
Packit 78deda
   was actually using this program, I would take the time to straighten it
Packit 78deda
   out.
Packit 78deda
Packit 78deda
   What's really sick about this subroutine is that in choosing to write
Packit 78deda
   a color map, it has to know that Caller hasn't already written
Packit 78deda
   the image.  Huge modularity violation.
Packit 78deda
-----------------------------------------------------------------------------*/
Packit 78deda
    if (cmaponly) {
Packit 78deda
        if (HAS_COLORMAP(cmapP)) {
Packit 78deda
            prepareCmap(bmhdP, cmapP);
Packit 78deda
            cmapToPpm(ofP, cmapP);
Packit 78deda
        } else
Packit 78deda
            pm_error("You specified -cmaponly, but the ILBM "
Packit 78deda
                     "has no colormap");
Packit 78deda
    } else if (bmhdP && bmhdP->nPlanes == 0) {
Packit 78deda
        if (HAS_COLORMAP(cmapP)) {
Packit 78deda
            prepareCmap(bmhdP, cmapP);
Packit 78deda
            cmapToPpm(ofP, cmapP);
Packit 78deda
        } else
Packit 78deda
            pm_error("ILBM has neither a color map nor color planes");
Packit 78deda
    } else if (!bodyChunkProcessed) {
Packit 78deda
        if (HAS_COLORMAP(cmapP)) {
Packit 78deda
            pm_message("input is a colormap file");
Packit 78deda
            prepareCmap(bmhdP, cmapP);
Packit 78deda
            cmapToPpm(ofP, cmapP);
Packit 78deda
        } else
Packit 78deda
            pm_error("ILBM has neither %s or %s chunk", 
Packit 78deda
                     ID2string(ID_BODY), ID2string(ID_CMAP));
Packit 78deda
    }
Packit 78deda
}
Packit 78deda
Packit 78deda
Packit 78deda
Packit 78deda
int
Packit 78deda
main(int argc, char *argv[]) {
Packit 78deda
Packit 78deda
    FILE * ifP;
Packit 78deda
    int argn;
Packit 78deda
    short cmaponly = 0, isdeepopt = 0;
Packit 78deda
    bool endchunk;
Packit 78deda
    bool bodyChunkProcessed;
Packit 78deda
    long formsize, bytesread;
Packit 78deda
    int viewportmodes = 0, fakeviewport = 0, viewportmask;
Packit 78deda
    IFF_ID firstIffid;
Packit 78deda
    BitMapHeader *bmhdP = NULL;
Packit 78deda
    ColorMap * cmap;
Packit 78deda
    DirectColor *dcol = NULL;
Packit 78deda
#define MAX_IGNORE  16
Packit 78deda
    IFF_ID ignorelist[MAX_IGNORE];
Packit 78deda
    int ignorecount = 0;
Packit 78deda
    char *maskname;
Packit 78deda
    const char * const usage =
Packit 78deda
        "[-verbose] [-ignore <chunkID> [-ignore <chunkID>] ...] "
Packit 78deda
        "[-isham|-isehb|-isdeep|-isnotham|-isnotehb|-isnotdeep] "
Packit 78deda
        "[-cmaponly] [-adjustcolors] "
Packit 78deda
        "[-transparent <color>] [-maskfile <filename>] [ilbmfile]";
Packit 78deda
    ppm_init(&argc, argv);
Packit 78deda
Packit 78deda
    viewportmask = 0xffffffff;
Packit 78deda
Packit 78deda
    argn = 1;
Packit 78deda
    while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
Packit 78deda
        if( pm_keymatch(argv[argn], "-verbose", 2) )
Packit 78deda
            verbose = 1;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-noverbose", 4) )
Packit 78deda
            verbose = 0;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isham", 4) )
Packit 78deda
            fakeviewport |= vmHAM;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isehb", 4) )
Packit 78deda
            fakeviewport |= vmEXTRA_HALFBRITE;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isdeep", 4) )
Packit 78deda
            isdeepopt = 1;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isnotham", 7) )
Packit 78deda
            viewportmask &= ~(vmHAM);
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isnotehb", 7) )
Packit 78deda
            viewportmask &= ~(vmEXTRA_HALFBRITE);
Packit 78deda
        else if( pm_keymatch(argv[argn], "-isnotdeep", 7) )
Packit 78deda
            isdeepopt = -1;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-cmaponly", 2) )
Packit 78deda
            cmaponly = 1;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-adjustcolors", 2) )
Packit 78deda
            adjustcolors = 1;
Packit 78deda
        else if( pm_keymatch(argv[argn], "-noadjustcolors", 4) )
Packit 78deda
            adjustcolors = 0;
Packit 78deda
        else  if( pm_keymatch(argv[argn], "-transparent", 2) ) {
Packit 78deda
            if( ++argn >= argc )
Packit 78deda
                pm_usage(usage);
Packit 78deda
            transpName = argv[argn];
Packit 78deda
        } else if( pm_keymatch(argv[argn], "-maskfile", 2) ) {
Packit 78deda
            if( ++argn >= argc )
Packit 78deda
                pm_usage(usage);
Packit 78deda
            maskname = argv[argn];
Packit 78deda
            maskfile = pm_openw(maskname);
Packit 78deda
        } else if( pm_keymatch(argv[argn], "-ignore", 2) ) {
Packit 78deda
            if( ++argn >= argc )
Packit 78deda
                pm_usage(usage);
Packit 78deda
            if( strlen(argv[argn]) != 4 )
Packit 78deda
                pm_error("'-ignore' option needs a 4 byte chunk ID string "
Packit 78deda
                         "as argument");
Packit 78deda
            if( ignorecount >= MAX_IGNORE )
Packit 78deda
                pm_error("max %d chunk IDs to ignore", MAX_IGNORE);
Packit 78deda
            ignorelist[ignorecount++] = 
Packit 78deda
                MAKE_ID(argv[argn][0], argv[argn][1], argv[argn][2], 
Packit 78deda
                        argv[argn][3]);
Packit 78deda
        } else
Packit 78deda
            pm_usage(usage);
Packit 78deda
        ++argn;
Packit 78deda
    }    
Packit 78deda
Packit 78deda
    if( argn < argc ) {
Packit 78deda
        ifP = pm_openr( argv[argn] );
Packit 78deda
        argn++;
Packit 78deda
    } else
Packit 78deda
        ifP = stdin;
Packit 78deda
Packit 78deda
    if( argn != argc )
Packit 78deda
        pm_usage(usage);
Packit 78deda
Packit 78deda
    wrotemask = false;  /* initial value */
Packit 78deda
Packit 78deda
    /* Read in the ILBM file. */
Packit 78deda
Packit 78deda
    firstIffid = get_big_long(ifP, ID_FORM, NULL);
Packit 78deda
    if (firstIffid != ID_FORM)
Packit 78deda
        pm_error("input is not a FORM type IFF file");
Packit 78deda
    formsize = get_big_long(ifP, ID_FORM, NULL);
Packit 78deda
    typeid = get_big_long(ifP, ID_FORM, NULL);
Packit 78deda
    if (typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 && 
Packit 78deda
        typeid != ID_PBM)
Packit 78deda
        pm_error("input is not an ILBM, RGBN, RGB8 or PBM "
Packit 78deda
                 "type FORM IFF file");
Packit 78deda
    bytesread = 4;  /* FORM and formsize do not count */
Packit 78deda
Packit 78deda
    cmap = alloc_cmap();
Packit 78deda
Packit 78deda
    /* Main loop, parsing the IFF FORM. */
Packit 78deda
    bodyChunkProcessed = FALSE;
Packit 78deda
    endchunk = FALSE;
Packit 78deda
    while (!endchunk && formsize-bytesread >= 8) {
Packit 78deda
        long bytesReadForChunk;
Packit 78deda
Packit 78deda
        processChunk(ifP, formsize, ignorelist, ignorecount,
Packit 78deda
                     fakeviewport, viewportmask,
Packit 78deda
                     isdeepopt, cmaponly,
Packit 78deda
                     &bodyChunkProcessed,
Packit 78deda
                     &endchunk, &bmhdP, cmap, &dcol,
Packit 78deda
                     &viewportmodes, &bytesReadForChunk);
Packit 78deda
Packit 78deda
        bytesread += bytesReadForChunk;
Packit 78deda
    }
Packit 78deda
Packit 78deda
    if (maskfile) {
Packit 78deda
        pm_close(maskfile);
Packit 78deda
        if (!wrotemask)
Packit 78deda
            remove(maskname);
Packit 78deda
        pbm_freerow(maskrow);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    maybeWriteColorMap(stdout, bmhdP, cmap, bodyChunkProcessed, cmaponly);
Packit 78deda
Packit 78deda
    {
Packit 78deda
        unsigned int skipped;
Packit 78deda
        
Packit 78deda
        for (skipped = 0; fgetc(ifP) != EOF; ++skipped)
Packit 78deda
            ++bytesread;
Packit 78deda
Packit 78deda
        if (skipped > 0)
Packit 78deda
            pm_message("skipped %u extraneous byte%s after last chunk",
Packit 78deda
                       skipped, (skipped == 1 ? "" : "s"));
Packit 78deda
    }
Packit 78deda
    pm_close(ifP);
Packit 78deda
Packit 78deda
    if (!endchunk && bytesread != formsize) {
Packit 78deda
        pm_message("warning - file length/FORM size field mismatch "
Packit 78deda
                   "(%ld != %ld+8)",
Packit 78deda
                   bytesread+8 /* FORM+size */, formsize);
Packit 78deda
    }
Packit 78deda
Packit 78deda
    return 0;
Packit 78deda
}