home *** CD-ROM | disk | FTP | other *** search
/ AMIGA PD 1 / AMIGA-PD-1.iso / Programme_zum_Heft / Anwendungen / Kurztests / PBM / ILBMTOPPM.LHA / src / ilbmtoppm.c < prev    next >
C/C++ Source or Header  |  1994-12-16  |  65KB  |  2,083 lines

  1. /* ilbmtoppm.c - read an IFF ILBM file and produce a portable pixmap
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. **
  12. ** Modified by Mark Thompson on 10/4/90 to accomodate 24-bit IFF files
  13. ** as used by ASDG, NewTek, etc.
  14. **
  15. ** Modified by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  16. **  20/Jun/93:
  17. **  - row-by-row operation
  18. **  - better de-interleave algorithm
  19. **  - colormap files
  20. **  - direct color
  21. **  04/Oct/93:
  22. **  - multipalette support (PCHG chunk)
  23. **  - options -ignore, -isham, -isehb and -adjustcolors
  24. **  22/May/94:
  25. **  - minor change: check first for 24 planes, then for HAM
  26. **  21/Sep/94:
  27. **  - write mask plane to a file if -maskfile option used
  28. **  - write colormap file
  29. **  - added sliced HAM/dynamic HAM/dynamic Hires multipalette formats (SHAM, CTBL chunk)
  30. **  - added color lookup tables (CLUT chunk)
  31. **  - major rework of colormap/multipalette handling
  32. **  - now uses numeric IFF IDs
  33. **  24/Oct/94
  34. **  - transparentColor support
  35. **  - added RGBN/RGB8 image types
  36. **  - 24-bit & direct color modified to n-bit deep ILBM
  37. */
  38.  
  39. #include "ppm.h"
  40. #include "pbm.h"
  41. #include "ilbm.h"
  42.  
  43. /* as long as the libcmap2 routines are not part of the "official"
  44.  * libppm we cheat by including the C-source here...
  45.  */
  46. #include "libcmap2.c"
  47. /*#include "ppmcmap2.h"*/
  48.  
  49. /*#define DEBUG*/
  50.  
  51. typedef struct {
  52.     int reg;            /* color register to change */
  53.     pixval r, g, b;     /* new colors for register */
  54. } PaletteChange;
  55. typedef struct {
  56.     pixel *color;
  57.     int    ncolors;
  58.     /* lookup tables */
  59.     unsigned char *redlut;
  60.     unsigned char *greenlut;
  61.     unsigned char *bluelut;
  62.     unsigned char *monolut;
  63.     /* multipalette stuff */
  64.     PaletteChange *mp_init;
  65.     PaletteChange **mp_change;
  66.     int mp_rows;                /* # of rows in change array */
  67.     int mp_type;                /* see below, higher types preferred */
  68.     int mp_flags;
  69.     IFF_ID  mp_id;
  70. } ColorMap;
  71. #define HAS_COLORMAP(cmap)      ((cmap) && (cmap)->color)
  72. #define HAS_COLORLUT(cmap)      ((cmap) && ((cmap)->redlut || (cmap)->greenlut || (cmap)->bluelut))
  73. #define HAS_MONOLUT(cmap)       ((cmap) && (cmap)->monolut)
  74. #define HAS_MULTIPALETTE(cmap)  (HAS_COLORMAP(cmap) && (cmap)->mp_type)
  75. #define MP_TYPE_SHAM        1
  76. #define MP_TYPE_CTBL        2
  77. #define MP_TYPE_PCHG        3
  78. #define MP_REG_IGNORE       -1
  79. #define MP_REG_END          -2
  80. #define MP_FLAGS_SKIPLACED   (1<<0)
  81.  
  82.  
  83. /* prototypes */
  84. static unsigned char get_byte ARGS((FILE* f, IFF_ID iffid, long *counter));
  85. static long get_big_long ARGS((FILE *f, IFF_ID iffid, long *counter));
  86. static short get_big_short ARGS((FILE *f, IFF_ID iffid, long *counter));
  87. static void read_bytes ARGS((FILE *ifp, int bytes, unsigned char *buffer, IFF_ID iffid, long *counter));
  88. static char *ID2string ARGS((IFF_ID iffid));
  89.  
  90. static void chunk_end ARGS((FILE *ifp, IFF_ID iffid, long chunksize));
  91. static void skip_chunk ARGS((FILE *f, IFF_ID iffid, long chunksize));
  92. static void display_chunk ARGS((FILE *ifp, IFF_ID iffid, long chunksize));
  93. static BitMapHeader * read_bmhd ARGS((FILE *f, IFF_ID iffid, long chunksize));
  94. static ColorMap * read_cmap ARGS((FILE *f, IFF_ID iffid, long chunksize, ColorMap *cmap));
  95. static ColorMap * read_cmyk ARGS((FILE *f, IFF_ID iffid, long chunksize, ColorMap *cmap));
  96. static ColorMap * read_clut ARGS((FILE *f, IFF_ID iffid, long chunksize, ColorMap *cmap));
  97. static ColorMap * read_4bit_mp ARGS((FILE *ifp, IFF_ID iffid, long chunksize, ColorMap *cmap));
  98. static ColorMap * read_pchg ARGS((FILE *ifp, IFF_ID iffid, long chunksize, ColorMap *cmap));
  99.  
  100. static void ham_to_ppm ARGS((FILE *ifp, long chunksize, BitMapHeader *bmhd, ColorMap *colormap, long viewportmodes));
  101. static void deep_to_ppm ARGS((FILE *ifp, long chunksize, BitMapHeader *bmhd, ColorMap *cmap));
  102. static void cmap_to_ppm ARGS((ColorMap *colormap));
  103. static void std_to_ppm ARGS((FILE *ifp, long chunksize, BitMapHeader *bmhd, ColorMap *colormap, long viewportmodes));
  104. static void rgbn_to_ppm ARGS((FILE *ifp, long chunksize, BitMapHeader *bmhd, ColorMap *cmap));
  105.  
  106. static ColorMap* ehbcmap ARGS((ColorMap *colormap));
  107. static void read_ilbm_plane ARGS((FILE *ifp, long *chunksizeP, int cols, int compression));
  108. static void decode_row ARGS((FILE *ifp, long *chunksizeP, rawtype *chunkyrow, int planes, BitMapHeader *bmhd));
  109. static void decode_mask ARGS((FILE *ifp, long *chunksizeP, rawtype *chunkyrow, BitMapHeader *bmhd));
  110.  
  111. static void get_color ARGS((ColorMap *cmap, int idx, pixval *r, pixval *g, pixval *b));
  112. static pixval lookup_red ARGS((ColorMap *cmap, int oldval));
  113. static pixval lookup_green ARGS((ColorMap *cmap, int oldval));
  114. static pixval lookup_blue ARGS((ColorMap *cmap, int oldval));
  115. static pixval lookup_mono ARGS((ColorMap *cmap, int oldval));
  116. static pixval lut_maxval ARGS((ColorMap *cmap, pixval maxval));
  117.  
  118. static void multi_init ARGS((ColorMap *cmap, long viewportmodes));
  119. static void multi_update ARGS((ColorMap *cmap, int row));
  120. static void multi_free ARGS((ColorMap *cmap));
  121.  
  122. static rawtype * alloc_rawrow ARGS((int cols));
  123. static ColorMap * alloc_cmap ARGS((void));
  124. static void check_cmap ARGS((BitMapHeader *bmhd, ColorMap *cmap));
  125. static void * xmalloc ARGS((int bytes));
  126. #define MALLOC(n, type)     (type *)xmalloc((n) * sizeof(type))
  127.  
  128. #define FACTOR_4BIT     17      /* scale factor maxval 15 -> maxval 255 */
  129.  
  130. static short verbose = 0;
  131. static short adjustcolors = 0;
  132. static unsigned char *ilbmrow;
  133. static pixel *pixelrow;
  134. static FILE *maskfile = NULL;
  135. static bit *maskrow = NULL;
  136. static short wrotemask = 0;
  137. static IFF_ID typeid;       /* ID_ILBM, ID_RGBN, ID_RGB8 */
  138.  
  139. static pixel *transpColor = NULL;       /* transparent color */
  140. static short transpIndex = -1;
  141. static char *transpName = NULL;
  142.  
  143. int
  144. main(argc, argv)
  145.     int argc;
  146.     char *argv[];
  147. {
  148.     FILE *ifp;
  149.     int argn;
  150.     short body = 0, cmaponly = 0, isdeep = 0, endchunk = 0;
  151.     long formsize, bytesread, chunksize, viewportmodes = 0, fakeviewport = 0, viewportmask;
  152.     IFF_ID iffid;
  153.     BitMapHeader *bmhd = NULL;
  154.     ColorMap *cmap = NULL;
  155. #define MAX_IGNORE  16
  156.     IFF_ID ignorelist[MAX_IGNORE];
  157.     int ignorecount = 0;
  158.     char *maskname;
  159.     char *usage =
  160. "[-verbose] [-ignore <chunkID> [-ignore <chunkID>] ...]\
  161.  [-isham|-isehb|-isdeep|-isnotham|-isnotehb|-isnotdeep]\
  162.  [-cmaponly] [-adjustcolors]\
  163.  [-transparent <color>] [-maskfile <filename>] [ilbmfile]";
  164.  
  165.     ppm_init(&argc, argv);
  166.  
  167.     viewportmask = 0xffffffff;
  168.  
  169.     argn = 1;
  170.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  171.         if( pm_keymatch(argv[argn], "-verbose", 2) )
  172.             verbose = 1;
  173.         else
  174.         if( pm_keymatch(argv[argn], "-noverbose", 4) )
  175.             verbose = 0;
  176.         else
  177.         if( pm_keymatch(argv[argn], "-isham", 4) )
  178.             fakeviewport |= vmHAM;
  179.         else
  180.         if( pm_keymatch(argv[argn], "-isehb", 4) )
  181.             fakeviewport |= vmEXTRA_HALFBRITE;
  182.         else
  183.         if( pm_keymatch(argv[argn], "-isdeep", 4) )
  184.             isdeep = 1;
  185.         else
  186.         if( pm_keymatch(argv[argn], "-isnotham", 7) )
  187.             viewportmask &= ~(vmHAM);
  188.         else
  189.         if( pm_keymatch(argv[argn], "-isnotehb", 7) )
  190.             viewportmask &= ~(vmEXTRA_HALFBRITE);
  191.         else
  192.         if( pm_keymatch(argv[argn], "-isnotdeep", 7) )
  193.             isdeep = -1;
  194.         else
  195.         if( pm_keymatch(argv[argn], "-cmaponly", 2) )
  196.             cmaponly = 1;
  197.         else
  198.         if( pm_keymatch(argv[argn], "-adjustcolors", 2) )
  199.             adjustcolors = 1;
  200.         else
  201.         if( pm_keymatch(argv[argn], "-noadjustcolors", 4) )
  202.             adjustcolors = 0;
  203.         else
  204.         if( pm_keymatch(argv[argn], "-transparent", 2) ) {
  205.             if( ++argn >= argc )
  206.                 pm_usage(usage);
  207.             transpName = argv[argn];
  208.         }
  209.         else
  210.         if( pm_keymatch(argv[argn], "-maskfile", 2) ) {
  211.             if( ++argn >= argc )
  212.                 pm_usage(usage);
  213.             maskname = argv[argn];
  214.             maskfile = pm_openw(maskname);
  215.         }
  216.         else
  217.         if( pm_keymatch(argv[argn], "-ignore", 2) ) {
  218.             if( ++argn >= argc )
  219.                 pm_usage(usage);
  220.             if( strlen(argv[argn]) != 4 )
  221.                 pm_error("\"-ignore\" option needs a 4 byte chunk ID string as argument");
  222.             if( ignorecount >= MAX_IGNORE )
  223.                 pm_error("max %d chunk IDs to ignore", MAX_IGNORE);
  224.             ignorelist[ignorecount++] = MAKE_ID(argv[argn][0], argv[argn][1], argv[argn][2], argv[argn][3]);
  225.         }
  226.         else
  227.             pm_usage(usage);
  228.         ++argn;
  229.     }
  230.  
  231.     if( argn < argc ) {
  232.         ifp = pm_openr( argv[argn] );
  233.         argn++;
  234.     }
  235.     else
  236.         ifp = stdin;
  237.  
  238.     if( argn != argc )
  239.         pm_usage(usage);
  240.  
  241.     /* Read in the ILBM file. */
  242.     iffid = get_big_long(ifp, ID_FORM, NULL);
  243.     if( iffid != ID_FORM )
  244.         pm_error("input is not a FORM type IFF file");
  245.     formsize = get_big_long(ifp, ID_FORM, NULL);
  246.     typeid = get_big_long(ifp, ID_FORM, NULL);
  247.     if( typeid != ID_ILBM && typeid != ID_RGBN && typeid != ID_RGB8 )
  248.         pm_error( "input is not an ILBM, RGBN or RGB8 type FORM IFF file" );
  249.     bytesread = 4;  /* FORM and formsize do not count */
  250.  
  251.     /* Main loop, parsing the IFF FORM. */
  252.     while( !endchunk && formsize-bytesread >= 8 ) {
  253.         short i, ignore = 0;
  254.  
  255.         iffid = get_big_long(ifp, ID_FORM, NULL);
  256.         chunksize = get_big_long(ifp, iffid, NULL);
  257.         bytesread += 8;
  258.  
  259.         for( i = 0; i < ignorecount && !ignore; i++ ) {
  260.             if( iffid == ignorelist[i] )
  261.                 ignore = 1;
  262.         }
  263.  
  264. #ifdef DEBUG
  265.             pm_message("reading %s chunk: %ld bytes", ID2string(iffid), chunksize);
  266. #endif
  267.         if( ignore ) {
  268.             ignore = 0;
  269.             pm_message("ignoring %s chunk", ID2string(iffid));
  270.             skip_chunk(ifp, iffid, chunksize);
  271.         }
  272.         else
  273.         if( iffid == ID_END ) {
  274.             /* END chunks are not officially supported in IFF, but
  275.                 suggested as a future expansion for stream-writing,
  276.                 see Amiga RKM Devices, 3rd Ed, page 376 */
  277.             if( chunksize != 0 ) {
  278.                 pm_message("warning - non-0 %s chunk", ID2string(iffid));
  279.                 skip_chunk(ifp, iffid, chunksize);
  280.             }
  281.             if( formsize != 0xffffffff )
  282.                 pm_message("warning - %s chunk with FORM size 0x%08lx (should be 0x%08lx)",
  283.                             ID2string(iffid), formsize, 0xffffffff);
  284.             endchunk = 1;
  285.         }
  286.         else
  287.         if( body != 0 ) {
  288.             pm_message("%s chunk found after %s chunk - skipping", ID2string(iffid), ID2string(ID_BODY));
  289.             skip_chunk(ifp, iffid, chunksize);
  290.         }
  291.         else
  292.         switch( iffid ) {
  293.             case ID_BMHD:
  294.                 bmhd = read_bmhd(ifp, iffid, chunksize);
  295.                 if( bmhd->nPlanes == 0 )
  296.                     cmaponly = 1;
  297.                 break;
  298.             case ID_CMAP:
  299.                 cmap = read_cmap(ifp, iffid, chunksize, cmap);
  300.                 break;
  301.             case ID_CMYK:
  302.                 cmap = read_cmyk(ifp, iffid, chunksize, cmap);
  303.                 break;
  304.             case ID_CLUT:
  305.                 cmap = read_clut(ifp, iffid, chunksize, cmap);
  306.                 break;
  307.             case ID_CAMG:
  308.                 if( chunksize != CAMGChunkSize )
  309.                     pm_error("%s chunk size mismatch", ID2string(iffid));
  310.                 viewportmodes = get_big_long(ifp, ID_CAMG, NULL);
  311.                 viewportmodes &= viewportmask;      /* -isnotham/-isnotehb */
  312.                 break;
  313.             case ID_PCHG:
  314.                 cmap = read_pchg(ifp, iffid, chunksize, cmap);
  315.                 break;
  316.             case ID_CTBL:
  317.             case ID_SHAM:
  318.                 cmap = read_4bit_mp(ifp, iffid, chunksize, cmap);
  319.                 break;
  320.             case ID_BODY:
  321.                 body = 1;
  322.  
  323.                 if( bmhd == NULL )
  324.                     pm_error("%s chunk without %s chunk", ID2string(ID_BODY), ID2string(ID_BMHD));
  325.  
  326.                 if( cmaponly ) {
  327.                     skip_chunk(ifp, iffid,  chunksize);
  328.                     break;
  329.                 }
  330.  
  331.                 check_cmap(bmhd, cmap);
  332.  
  333.                 pixelrow = ppm_allocrow(bmhd->w);
  334.                 if( maskfile ) {
  335.                     maskrow = pbm_allocrow(bmhd->w);
  336.                     pbm_writepbminit(maskfile, bmhd->w, bmhd->h, 0);
  337.                 }
  338.  
  339.                 if( typeid == ID_ILBM ) {
  340.                     ilbmrow = MALLOC(RowBytes(bmhd->w), unsigned char);
  341.                     viewportmodes |= fakeviewport;      /* -isham/-isehb */
  342.  
  343.                     if( isdeep > 0 && (bmhd->nPlanes % 3 != 0) ) {
  344.                         pm_message("cannot interpret %d-plane image as \'deep\' (# of planes must be divisible by 3)", bmhd->nPlanes);
  345.                         isdeep = 0;
  346.                     }
  347.  
  348.                     if( isdeep > 0 )
  349.                         deep_to_ppm(ifp, chunksize, bmhd, cmap);
  350.                     else
  351.                     if( bmhd->nPlanes > 8 ) {
  352.                         if( bmhd->nPlanes <= 16 && HAS_COLORMAP(cmap) )
  353.                             std_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes);
  354.                         else
  355.                         if( isdeep >= 0 && (bmhd->nPlanes % 3 == 0) )
  356.                             deep_to_ppm(ifp, chunksize, bmhd, cmap);
  357.                         else
  358.                         if( bmhd->nPlanes <= 16 )   /* will be interpreted as grayscale */
  359.                             std_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes);
  360.                         else
  361.                             pm_error("don\'t know how to interpret %d-plane image", bmhd->nPlanes);
  362.                     }
  363.                     else
  364.                         std_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes);
  365.                 }
  366.                 else {  /* RGBN or RGB8 */
  367.                     rgbn_to_ppm(ifp, chunksize, bmhd, cmap);
  368.                 }
  369.                 break;
  370.             case ID_GRAB:   case ID_DEST:   case ID_SPRT:   case ID_CRNG:
  371.             case ID_CCRT:   case ID_DYCP:   case ID_DPPV:   case ID_DRNG:
  372.             case ID_EPSF:   case ID_JUNK:   case ID_CNAM:   case ID_PRVW:
  373.                 skip_chunk(ifp, iffid, chunksize);
  374.                 break;
  375.             case ID_copy:   case ID_AUTH:   case ID_NAME:   case ID_ANNO:
  376.             case ID_TEXT:   case ID_FVER:
  377.                 if( verbose )
  378.                     display_chunk(ifp, iffid, chunksize);
  379.                 else
  380.                     skip_chunk(ifp, iffid, chunksize);
  381.                 break;
  382.             case ID_DPI:
  383.                 {
  384.                     int x, y;
  385.  
  386.                     x = get_big_short(ifp, ID_DPI, NULL);
  387.                     y = get_big_short(ifp, ID_DPI, NULL);
  388.                     if( verbose )
  389.                         pm_message("%s chunk:  dpi_x = %d    dpi_y = %d", ID2string(ID_DPI), x, y);
  390.                 }
  391.                 break;
  392.             default:
  393.                 pm_message("unknown chunk type %s - skipping", ID2string(iffid));
  394.                 skip_chunk(ifp, iffid, chunksize);
  395.                 break;
  396.         }
  397.  
  398.         bytesread += chunksize;
  399.         if( odd(chunksize) ) {
  400.             (void) get_byte(ifp, iffid, NULL);
  401.             ++bytesread;
  402.         }
  403.     }
  404.  
  405.     if( maskfile ) {
  406.         pm_close(maskfile);
  407.         if( !wrotemask )
  408.             remove(maskname);
  409.         pbm_freerow(maskrow);
  410.     }
  411.  
  412.     if( cmaponly ) {
  413.         if( HAS_COLORMAP(cmap) ) {
  414.             check_cmap(bmhd, cmap);
  415.             cmap_to_ppm(cmap);
  416.         }
  417.         else
  418.             pm_error("no colormap");
  419.     }
  420.     else
  421.     if( body == 0 ) {
  422.         if( HAS_COLORMAP(cmap) ) {
  423.             pm_message("input is a colormap file");
  424.             check_cmap(bmhd, cmap);
  425.             cmap_to_ppm(cmap);
  426.         }
  427.         else
  428.             pm_error("no %s or %s chunk found", ID2string(ID_BODY), ID2string(ID_CMAP));
  429.     }
  430.  
  431.     for(chunksize = 0; fgetc(ifp) != EOF; chunksize++ )
  432.         bytesread++;
  433.     pm_close(ifp);
  434.  
  435.     if( chunksize )
  436.         pm_message("skipped %ld extraneous byte%s after last chunk",
  437.                     chunksize, (chunksize == 1 ? "" : "s"));
  438.  
  439.     if( !endchunk && bytesread != formsize ) {
  440.         pm_message("warning - file length/FORM size field mismatch (%ld != %ld+8)",
  441.                     bytesread+8 /* FORM+size */, formsize);
  442.     }
  443.  
  444.     exit(0);
  445. }
  446.  
  447.  
  448. /****************************************************************************
  449.  Chunk reader
  450.  ****************************************************************************/
  451.  
  452. static void
  453. chunk_end(ifp, iffid, chunksize)
  454.     FILE *ifp;
  455.     IFF_ID iffid;
  456.     long chunksize;
  457. {
  458.     if( chunksize ) {
  459.         pm_message("warning - %ld extraneous byte%s in %s chunk",
  460.                     chunksize, (chunksize == 1 ? "" : "s"), ID2string(iffid));
  461.         while( chunksize )
  462.             (void) get_byte(ifp, iffid, &chunksize);
  463.     }
  464. }
  465.  
  466.  
  467. static void
  468. skip_chunk(ifp, iffid, chunksize)
  469.     FILE *ifp;
  470.     IFF_ID iffid;
  471.     long chunksize;
  472. {
  473.     while( chunksize )
  474.         (void) get_byte(ifp, iffid, &chunksize);
  475. }
  476.  
  477.  
  478. static void
  479. display_chunk(ifp, iffid, chunksize)
  480.     FILE *ifp;
  481.     IFF_ID iffid;
  482.     long chunksize;
  483. {
  484.     int byte;
  485.  
  486.     pm_message("contents of %s chunk:", ID2string(iffid));
  487.  
  488.     while( chunksize ) {
  489.         byte = get_byte(ifp, iffid, &chunksize);
  490.         if( fputc(byte, stderr) == EOF )
  491.             pm_error("write error");
  492.     }
  493.     if( byte != '\n' )
  494.         if( fputc('\n', stderr) == EOF )
  495.             pm_error("write error");
  496. }
  497.  
  498.  
  499. static ColorMap *
  500. read_cmap(ifp, iffid, chunksize, cmap)
  501.     FILE *ifp;
  502.     IFF_ID iffid;
  503.     long chunksize;
  504.     ColorMap *cmap;
  505. {
  506.     int i, r, g, b;
  507.     long colors;
  508.  
  509.     colors = chunksize / 3;
  510.     if( colors == 0 ) {
  511.         pm_error("warning - empty %s colormap", ID2string(iffid));
  512.         skip_chunk(ifp, iffid, chunksize);
  513.         return cmap;
  514.     }
  515.  
  516.     if( !cmap )
  517.         cmap = alloc_cmap();
  518.     else
  519.     if( cmap->color )               /* prefer CMAP-chunk over CMYK-chunk */
  520.         ppm_freerow(cmap->color);
  521.     cmap->color = ppm_allocrow(colors);
  522.     cmap->ncolors = colors;
  523.  
  524.     for( i = 0; i < colors; i++ ) {
  525.         r = get_byte(ifp, iffid, &chunksize);
  526.         g = get_byte(ifp, iffid, &chunksize);
  527.         b = get_byte(ifp, iffid, &chunksize);
  528.         PPM_ASSIGN(cmap->color[i], r, g, b);
  529.     }
  530.     chunk_end(ifp, iffid, chunksize);
  531.     return cmap;
  532. }
  533.  
  534.  
  535. static ColorMap *
  536. read_cmyk(ifp, iffid, chunksize, cmap)
  537.     FILE *ifp;
  538.     IFF_ID iffid;
  539.     long chunksize;
  540.     ColorMap *cmap;
  541. {
  542.     long colors;
  543.     int i;
  544.  
  545.     if( HAS_COLORMAP(cmap) ) {      /* prefer RGB color map */
  546.         skip_chunk(ifp, iffid, chunksize);
  547.         return cmap;
  548.     }
  549.  
  550.     colors = chunksize/4;
  551.     if( colors == 0 ) {
  552.         pm_error("warning - empty %s colormap", ID2string(iffid));
  553.         skip_chunk(ifp, iffid, chunksize);
  554.         return cmap;
  555.     }
  556.     if( !cmap )
  557.         cmap = alloc_cmap();
  558.     cmap->color = ppm_allocrow(colors);
  559.     cmap->ncolors = colors;
  560.  
  561.     for( i = 0; i <colors; i++ ) {
  562.         int c, m, y, k;
  563.         c = get_byte(ifp, iffid, &chunksize);
  564.         m = get_byte(ifp, iffid, &chunksize);
  565.         y = get_byte(ifp, iffid, &chunksize);
  566.         k = get_byte(ifp, iffid, &chunksize);
  567.  
  568.         c = MAXCOLVAL - min(MAXCOLVAL, c*(MAXCOLVAL-k)+k);  /* cyan -> red */
  569.         m = MAXCOLVAL - min(MAXCOLVAL, m*(MAXCOLVAL-k)+k);  /* magenta -> green */
  570.         y = MAXCOLVAL - min(MAXCOLVAL, y*(MAXCOLVAL-k)+k);  /* yellow -> blue */
  571.         PPM_ASSIGN(cmap->color[i], c, m, y);
  572.     }
  573.     chunk_end(ifp, iffid, chunksize);
  574.     return cmap;
  575. }
  576.  
  577.  
  578. static ColorMap *
  579. read_clut(ifp, iffid, chunksize, cmap)
  580.     FILE *ifp;
  581.     IFF_ID iffid;
  582.     long chunksize;
  583.     ColorMap *cmap;
  584. {
  585.     long type;
  586.     unsigned char *lut;
  587.     int i;
  588.  
  589.     if( chunksize != CLUTSize ) {
  590.         pm_message("invalid size for %s chunk - skipping it", ID2string(iffid));
  591.         skip_chunk(ifp, iffid, chunksize);
  592.         return cmap;
  593.     }
  594.  
  595.     if( !cmap )
  596.         cmap = alloc_cmap();
  597.  
  598.     type = get_big_long(ifp, iffid, &chunksize);
  599.     (void) get_big_long(ifp, iffid, &chunksize);    /* skip reserved field */
  600.  
  601.     lut = MALLOC(256, unsigned char);
  602.     for( i = 0; i < 256; i++ )
  603.         lut[i] = get_byte(ifp, iffid, &chunksize);
  604.  
  605.     switch( type ) {
  606.         case CLUT_MONO:
  607.             cmap->monolut = lut;
  608.             break;
  609.         case CLUT_RED:
  610.             cmap->redlut = lut;
  611.             break;
  612.         case CLUT_GREEN:
  613.             cmap->greenlut = lut;
  614.             break;
  615.         case CLUT_BLUE:
  616.             cmap->bluelut = lut;
  617.             break;
  618.         default:
  619.             pm_message("warning - %s type %ld not supported", ID2string(iffid), type);
  620.             free(lut);
  621.     }
  622.     return cmap;
  623. }
  624.  
  625.  
  626. static BitMapHeader *
  627. read_bmhd(ifp, iffid, chunksize)
  628.     FILE *ifp;
  629.     IFF_ID iffid;
  630.     long chunksize;
  631. {
  632.     BitMapHeader *bmhd;
  633.  
  634.     if( chunksize != BitMapHeaderSize ) {
  635.         pm_message("invalid size for %s chunk - skipping it", ID2string(iffid));
  636.         skip_chunk(ifp, iffid, chunksize);
  637.         return NULL;
  638.     }
  639.  
  640.     bmhd = MALLOC(1, BitMapHeader);
  641.  
  642.     bmhd->w = get_big_short(ifp, iffid, &chunksize);        /* cols */
  643.     bmhd->h = get_big_short(ifp, iffid, &chunksize);        /* rows */
  644.     bmhd->x = get_big_short(ifp, iffid, &chunksize);        /* ignored */
  645.     bmhd->y = get_big_short(ifp, iffid, &chunksize);        /* ignored */
  646.     bmhd->nPlanes = get_byte(ifp, iffid, &chunksize);
  647.     bmhd->masking = get_byte(ifp, iffid, &chunksize);
  648.     bmhd->compression = get_byte(ifp, iffid, &chunksize);
  649.     bmhd->flags = get_byte(ifp, iffid, &chunksize);
  650.     bmhd->transparentColor = get_big_short(ifp, iffid, &chunksize);
  651.     bmhd->xAspect = get_byte(ifp, iffid, &chunksize);
  652.     bmhd->yAspect = get_byte(ifp, iffid, &chunksize);
  653.     bmhd->pageWidth  = get_big_short(ifp, iffid, &chunksize);   /* ignored */
  654.     bmhd->pageHeight = get_big_short(ifp, iffid, &chunksize);   /* ignored */
  655.  
  656.     if( typeid == ID_ILBM ) {
  657.         if( verbose ) {
  658.             pm_message("dimensions: %dx%d, %d planes", bmhd->w, bmhd->h, bmhd->nPlanes);
  659.             pm_message("compression: %s", bmhd->compression <= cmpMAXKNOWN ?
  660.                         cmpNAME[bmhd->compression] : "unknown");
  661.         }
  662.  
  663.         switch( bmhd->masking ) {
  664.             case mskNone:
  665.                 break;
  666.             case mskHasMask:
  667.             case mskHasTransparentColor:
  668.                 if( !maskfile )
  669.                     pm_message("use \"-maskfile <filename>\" to generate a PBM mask file from %s", mskNAME[bmhd->masking]);
  670.                 break;
  671.             case mskLasso:
  672.                 pm_message("warning - masking type \"%s\" not supported", mskNAME[bmhd->masking]);
  673.                 break;
  674.             default:
  675.                 pm_error("unknown masking type %d", bmhd->masking);
  676.         }
  677.     }
  678.     else {  /* RGBN/RGB8 */
  679.         if( verbose )
  680.             pm_message("dimensions: %dx%d", bmhd->w, bmhd->h);
  681.         if( !maskfile )
  682.             pm_message("use \"-maskfile <filename>\" to generate a PBM mask file from genlock bits");
  683.     }
  684.  
  685.     /* fix aspect ratio */
  686.     if( bmhd->xAspect == 0 || bmhd->yAspect == 0 ) {
  687.         pm_message("warning - illegal aspect ratio %d:%d, using 1:1", bmhd->xAspect, bmhd->yAspect);
  688.         bmhd->xAspect = bmhd->yAspect = 1;
  689.     }
  690.  
  691.     if( bmhd->xAspect != bmhd->yAspect ) {
  692.         pm_message("warning - non-square pixels; to fix do a 'pnmscale -%cscale %g'",
  693.             bmhd->xAspect > bmhd->yAspect ? 'x' : 'y',
  694.             bmhd->xAspect > bmhd->yAspect ? (float)(bmhd->xAspect)/bmhd->yAspect : (float)(bmhd->yAspect)/bmhd->xAspect);
  695.     }
  696.  
  697.     return bmhd;
  698. }
  699.  
  700.  
  701. /****************************************************************************
  702.  Conversion functions
  703.  ****************************************************************************/
  704.  
  705. static void
  706. ham_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes)
  707.     FILE *ifp;
  708.     long chunksize;
  709.     BitMapHeader *bmhd;
  710.     ColorMap *cmap;
  711.     long viewportmodes;
  712. {
  713.     int cols, rows, hambits, hammask, hamshift, hammask2, col, row;
  714.     pixval maxval;
  715.     rawtype *rawrow;
  716.     unsigned char hamlut[256];
  717.  
  718.     cols = bmhd->w;
  719.     rows = bmhd->h;
  720.     hambits = bmhd->nPlanes - 2;
  721.     hammask = (1 << hambits) - 1;
  722.     hamshift = 8 - hambits;
  723.     hammask2 = (1 << hamshift) - 1;
  724.  
  725.     if( hambits > 8 || hambits < 1 ) {
  726.         pm_message("%d-plane HAM?? - interpreting image as a normal ILBM", bmhd->nPlanes);
  727.         viewportmodes &= ~(vmHAM);
  728.         std_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes);
  729.         return;
  730.     }
  731.  
  732.     pm_message("input is a %sHAM%d file", HAS_MULTIPALETTE(cmap) ? "multipalette " : "", bmhd->nPlanes);
  733.  
  734.     if( HAS_COLORLUT(cmap) || HAS_MONOLUT(cmap) ) {
  735.         pm_message("warning - color lookup tables ignored in HAM");
  736.         if( cmap->redlut )      free(cmap->redlut);
  737.         if( cmap->greenlut )    free(cmap->greenlut);
  738.         if( cmap->bluelut )     free(cmap->bluelut);
  739.         if( cmap->monolut )     free(cmap->monolut);
  740.         cmap->redlut = cmap->greenlut = cmap->bluelut = cmap->monolut = NULL;
  741.     }
  742.     if( !HAS_COLORMAP(cmap) ) {
  743.         pm_message("no colormap - interpreting values as grayscale");
  744.         maxval = pm_bitstomaxval(hambits);
  745.         for( col = 0; col <= maxval; col++ )
  746.             hamlut[col] = col * MAXCOLVAL / maxval;
  747.         cmap->monolut = hamlut;
  748.     }
  749.  
  750.     if( transpName ) {
  751.         transpColor = MALLOC(1, pixel);
  752.         *transpColor = ppm_parsecolor(transpName, MAXCOLVAL);
  753.     }
  754.  
  755.     if( HAS_MULTIPALETTE(cmap) )
  756.         multi_init(cmap, viewportmodes);
  757.  
  758.     rawrow = alloc_rawrow(cols);
  759.  
  760.     ppm_writeppminit(stdout, cols, rows, MAXCOLVAL, 0);
  761.     for( row = 0; row < rows; row++ ) {
  762.         pixval r, g, b;
  763.  
  764.         if( HAS_MULTIPALETTE(cmap) )
  765.             multi_update(cmap, row);
  766.  
  767.         decode_row(ifp, &chunksize, rawrow, bmhd->nPlanes, bmhd);
  768.         decode_mask(ifp, &chunksize, rawrow, bmhd);
  769.  
  770.         r = g = b = 0;
  771.         for( col = 0; col < cols; col++ ) {
  772.             int idx = rawrow[col] & hammask;
  773.  
  774.             if( transpColor && maskrow && maskrow[col] == PBM_WHITE )
  775.                 pixelrow[col] = *transpColor;
  776.             else {
  777.                 switch((rawrow[col] >> hambits) & 0x03) {
  778.                     case HAMCODE_CMAP:
  779.                         get_color(cmap, idx, &r, &g, &b);
  780.                         break;
  781.                     case HAMCODE_BLUE:
  782.                         b = ((b & hammask2) | (idx << hamshift));
  783.                         /*b = hamlut[idx];*/
  784.                         break;
  785.                     case HAMCODE_RED:
  786.                         r = ((r & hammask2) | (idx << hamshift));
  787.                         /*r = hamlut[idx];*/
  788.                         break;
  789.                     case HAMCODE_GREEN:
  790.                         g = ((g & hammask2) | (idx << hamshift));
  791.                         /*g = hamlut[idx];*/
  792.                         break;
  793.                     default:
  794.                         pm_error("ham_to_ppm(): impossible HAM code - can\'t happen");
  795.                 }
  796.                 PPM_ASSIGN(pixelrow[col], r, g, b);
  797.             }
  798.         }
  799.         ppm_writeppmrow(stdout, pixelrow, cols, MAXCOLVAL, 0);
  800.     }
  801.     chunk_end(ifp, ID_BODY, chunksize);
  802. }
  803.  
  804.  
  805. static void
  806. deep_to_ppm(ifp, chunksize, bmhd, cmap)
  807.     FILE *ifp;
  808.     long chunksize;
  809.     BitMapHeader *bmhd;
  810.     ColorMap *cmap;     /* for CLUTs */
  811. {
  812.     int cols, rows, col, row;
  813.     rawtype *Rrow, *Grow, *Brow;
  814.     int planespercolor = bmhd->nPlanes / 3;
  815.     pixval maxval;
  816.  
  817.     cols = bmhd->w;
  818.     rows = bmhd->h;
  819.  
  820.     pm_message("input is a deep (%d-bit) ILBM", bmhd->nPlanes);
  821.     if( planespercolor > MAXPLANES )
  822.         pm_error("too many planes (max %d)", MAXPLANES * 3);
  823.  
  824.     if( bmhd->masking == mskHasTransparentColor || bmhd->masking == mskLasso ) {
  825.         pm_message("masking type \"%s\" in a deep ILBM?? - ignoring it", mskNAME[bmhd->masking]);
  826.         bmhd->masking = mskNone;
  827.     }
  828.  
  829.     maxval = lut_maxval(cmap, pm_bitstomaxval(planespercolor));
  830.     if( maxval > PPM_MAXMAXVAL )
  831.         pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS" );
  832.  
  833.     if( transpName ) {
  834.         transpColor = MALLOC(1, pixel);
  835.         *transpColor = ppm_parsecolor(transpName, maxval);
  836.     }
  837.  
  838.     Rrow = alloc_rawrow(cols);
  839.     Grow = alloc_rawrow(cols);
  840.     Brow = alloc_rawrow(cols);
  841.  
  842.     ppm_writeppminit(stdout, cols, rows, maxval, 0);
  843.     for( row = 0; row < rows; row++ ) {
  844.         decode_row(ifp, &chunksize, Rrow, planespercolor, bmhd);
  845.         decode_row(ifp, &chunksize, Grow, planespercolor, bmhd);
  846.         decode_row(ifp, &chunksize, Brow, planespercolor, bmhd);
  847.         decode_mask(ifp, &chunksize, Brow, bmhd);
  848.  
  849.         for( col = 0; col < cols; col++ ) {
  850.             if( transpColor && maskrow && maskrow[col] == PBM_WHITE )
  851.                 pixelrow[col] = *transpColor;
  852.             else
  853.                 PPM_ASSIGN(pixelrow[col],   lookup_red(cmap, Rrow[col]),
  854.                                             lookup_green(cmap, Grow[col]),
  855.                                             lookup_blue(cmap, Brow[col]) );
  856.         }
  857.         ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  858.     }
  859.     chunk_end(ifp, ID_BODY, chunksize);
  860. }
  861.  
  862.  
  863. static void
  864. cmap_to_ppm(cmap)
  865.     ColorMap *cmap;
  866. {
  867.     ppm_colorrowtomapfile(stdout, cmap->color, cmap->ncolors, MAXCOLVAL);
  868. #if 0
  869.     int i;
  870.     ppm_writeppminit(stdout, cmap->ncolors, 1, MAXCOLVAL, 1);
  871.     for( i = 0; i < cmap->ncolors; i++ )
  872.         ppm_writeppmrow(stdout, &(cmap->color[i]), 1, MAXCOLVAL, 1);
  873. #endif
  874. }
  875.  
  876.  
  877. static void
  878. std_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes)
  879.     FILE *ifp;
  880.     long chunksize;
  881.     BitMapHeader *bmhd;
  882.     ColorMap *cmap;
  883.     long viewportmodes;
  884. {
  885.     rawtype *rawrow;
  886.     int row, rows, col, cols;
  887.     pixval maxval;
  888.  
  889.     if( viewportmodes & vmHAM ) {
  890.         ham_to_ppm(ifp, chunksize, bmhd, cmap, viewportmodes);
  891.         return;
  892.     }
  893.  
  894.     cols = bmhd->w;
  895.     rows = bmhd->h;
  896.  
  897.     pm_message("input is a %d-plane %s%sILBM", bmhd->nPlanes,
  898.                 HAS_MULTIPALETTE(cmap) ? "multipalette " : "",
  899.                 viewportmodes & vmEXTRA_HALFBRITE ? "EHB " : ""
  900.               );
  901.  
  902.     if( bmhd->nPlanes > MAXPLANES )
  903.         pm_error("too many planes (max %d)", MAXPLANES);
  904.  
  905.     if( HAS_COLORMAP(cmap) ) {
  906.         if( viewportmodes & vmEXTRA_HALFBRITE )
  907.             cmap = ehbcmap(cmap);
  908.         maxval = MAXCOLVAL;
  909.     }
  910.     else {
  911.         pm_message("no colormap - interpreting values as grayscale");
  912.         maxval = lut_maxval(cmap, pm_bitstomaxval(bmhd->nPlanes));
  913.         if( maxval > PPM_MAXMAXVAL )
  914.             pm_error("nPlanes is too large - try reconfiguring with PGM_BIGGRAYS\n    or without PPM_PACKCOLORS" );
  915.     }
  916.  
  917.     if( transpName ) {
  918.         transpColor = MALLOC(1, pixel);
  919.         *transpColor = ppm_parsecolor(transpName, maxval);
  920.     }
  921.  
  922.     rawrow = alloc_rawrow(cols);
  923.  
  924.     if( HAS_MULTIPALETTE(cmap) )
  925.         multi_init(cmap, viewportmodes);
  926.  
  927.     ppm_writeppminit( stdout, cols, rows, maxval, 0 );
  928.     for( row = 0; row < rows; row++ ) {
  929.  
  930.         if( HAS_MULTIPALETTE(cmap) )
  931.             multi_update(cmap, row);
  932.  
  933.         decode_row(ifp, &chunksize, rawrow, bmhd->nPlanes, bmhd);
  934.         decode_mask(ifp, &chunksize, rawrow, bmhd);
  935.  
  936.         for( col = 0; col < cols; col++ ) {
  937.             pixval r, g, b;
  938.             if( transpColor && maskrow && maskrow[col] == PBM_WHITE )
  939.                 pixelrow[col] = *transpColor;
  940.             else {
  941.                 get_color(cmap, rawrow[col], &r, &g, &b);
  942.                 PPM_ASSIGN(pixelrow[col], r, g, b);
  943.             }
  944.         }
  945.         ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  946.     }
  947.     chunk_end(ifp, ID_BODY, chunksize);
  948. }
  949.  
  950.  
  951. static void
  952. rgbn_to_ppm(ifp, chunksize, bmhd, cmap)
  953.     FILE *ifp;
  954.     long chunksize;
  955.     BitMapHeader *bmhd;
  956.     ColorMap *cmap;     /* for CLUTs */
  957. {
  958.     int row, rows, col, cols, count, genlock, tries;
  959.     pixval r, g, b, maxval;
  960.  
  961.     pm_message("input is a %d-bit RGB image", (typeid == ID_RGB8 ? 8 : 4));
  962.  
  963.     rows = bmhd->h;
  964.     cols = bmhd->w;
  965.     if( bmhd->compression != 4 )
  966.         pm_error("invalid compression mode for %s: %d (must be 4)", ID2string(typeid), bmhd->compression);
  967.  
  968.     switch( typeid ) {
  969.         case ID_RGBN:
  970.             if( bmhd->nPlanes != 13 )
  971.                 pm_error("invalid number of planes for %s: %d (must be 13)", ID2string(typeid), bmhd->nPlanes);
  972.             maxval = lut_maxval(cmap, 15);
  973.             break;
  974.         case ID_RGB8:
  975.             if( bmhd->nPlanes != 25 )
  976.                 pm_error("invalid number of planes for %s: %d (must be 25)", ID2string(typeid), bmhd->nPlanes);
  977.             maxval = 255;
  978.             break;
  979.         default:
  980.             pm_error("rgbn_to_ppm(): invalid IFF ID %s - can\'t happen", ID2string(typeid));
  981.     }
  982.  
  983.     if( transpName ) {
  984.         transpColor = MALLOC(1, pixel);
  985.         *transpColor = ppm_parsecolor(transpName, maxval);
  986.     }
  987.  
  988.  
  989.     ppm_writeppminit(stdout, cols, rows, maxval, 0);
  990.     count = 0;
  991.     for( row = 0; row < rows; row++ ) {
  992.         for( col = 0; col < cols; col++ ) {
  993.             tries = 0;
  994.             while( !count ) {
  995.                 if( typeid == ID_RGB8 ) {
  996.                     r = lookup_red(cmap,   get_byte(ifp, ID_BODY, &chunksize));
  997.                     g = lookup_green(cmap, get_byte(ifp, ID_BODY, &chunksize));
  998.                     b = lookup_blue(cmap,  get_byte(ifp, ID_BODY, &chunksize));
  999.                     count = get_byte(ifp, ID_BODY, &chunksize);
  1000.                     genlock = count & 0x80;
  1001.                     count &= 0x7f;
  1002.                 }
  1003.                 else {
  1004.                     int word;
  1005.                     word = get_big_short(ifp, ID_BODY, &chunksize);
  1006.                     r = lookup_red(cmap, (word & 0xf000) >> 12);
  1007.                     g = lookup_green(cmap, (word & 0x0f00) >> 8);
  1008.                     b = lookup_blue(cmap, (word & 0x00f0) >> 4);
  1009.                     genlock = word & 0x0008;
  1010.                     count = word & 0x0007;
  1011.                 }
  1012.                 if( !count ) {
  1013.                     count = get_byte(ifp, ID_BODY, &chunksize);
  1014.                     if( !count )
  1015.                         count = get_big_short(ifp, ID_BODY, &chunksize);
  1016.                         if( !count )
  1017.                             ++tries;
  1018.                 }
  1019.             }
  1020.             if( tries ) {
  1021.                 pm_message("warning - repeat count 0 at col %d row %d: skipped %d RGB entr%s",
  1022.                             col, row, tries, (tries == 1 ? "y" : "ies"));
  1023.             }
  1024.             if( maskfile ) {
  1025.                 /* genlock bit set -> transparent */
  1026.                 if( genlock )
  1027.                     maskrow[col] = PBM_WHITE;
  1028.                 else
  1029.                     maskrow[col] = PBM_BLACK;
  1030.             }
  1031.             if( transpColor && maskrow && maskrow[col] == PBM_WHITE )
  1032.                 pixelrow[col] = *transpColor;
  1033.             else
  1034.                 PPM_ASSIGN(pixelrow[col], r, g, b);
  1035.             --count;
  1036.         }
  1037.         ppm_writeppmrow(stdout, pixelrow, cols, maxval, 0);
  1038.         if( maskfile ) {
  1039.             pbm_writepbmrow(maskfile, maskrow, cols, 0);
  1040.             wrotemask = 1;
  1041.         }
  1042.     }
  1043.     chunk_end(ifp, ID_BODY, chunksize);
  1044. }
  1045.  
  1046. /****************************************************************************
  1047.  ILBM functions
  1048.  ****************************************************************************/
  1049.  
  1050.  
  1051. static void
  1052. read_ilbm_plane(ifp, chunksizeP, cols, compression)
  1053.     FILE *ifp;
  1054.     long *chunksizeP;
  1055.     int cols, compression;
  1056. {
  1057.     unsigned char *ubp;
  1058.     int bytes, j, byte;
  1059.  
  1060.     bytes = RowBytes(cols);
  1061.  
  1062.     switch(compression) {
  1063.         case cmpNone:
  1064.             read_bytes(ifp, bytes, ilbmrow, ID_BODY, chunksizeP);
  1065.             break;
  1066.         case cmpByteRun1:
  1067.             ubp = ilbmrow;
  1068.             do {
  1069.                 byte = (int)get_byte(ifp, ID_BODY, chunksizeP);
  1070.                 if( byte <= 127 ) {
  1071.                     j = byte;
  1072.                     bytes -= (j+1);
  1073.                     if( bytes < 0 )
  1074.                         pm_error("error doing ByteRun1 decompression");
  1075.                     for( ; j >= 0; j-- )
  1076.                         *ubp++ = get_byte(ifp, ID_BODY, chunksizeP);
  1077.                 }
  1078.                 else
  1079.                 if ( byte != 128 ) {
  1080.                     j = 256 - byte;
  1081.                     bytes -= (j+1);
  1082.                     if( bytes < 0 )
  1083.                         pm_error("error doing ByteRun1 decompression");
  1084.                     byte = (int)get_byte(ifp, ID_BODY, chunksizeP);
  1085.                     for( ; j >= 0; j-- )
  1086.                         *ubp++ = (unsigned char)byte;
  1087.                 }
  1088.                 /* 128 is a NOP */
  1089.             }
  1090.             while( bytes > 0 );
  1091.             break;
  1092.         default:
  1093.             pm_error("unknown compression type %d", compression);
  1094.     }
  1095. }
  1096.  
  1097.  
  1098. static const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  1099.  
  1100. static void
  1101. decode_row(ifp, chunksizeP, chunkyrow, nPlanes, bmhd)
  1102.     FILE *ifp;
  1103.     long *chunksizeP;
  1104.     rawtype *chunkyrow;
  1105.     int nPlanes;
  1106.     BitMapHeader *bmhd;
  1107. {
  1108.     int plane, col, cols, cbit;
  1109.     unsigned char *ilp;
  1110.     rawtype *chp;
  1111.  
  1112.     cols = bmhd->w;
  1113.     for( plane = 0; plane < nPlanes; plane++ ) {
  1114.         int mask;
  1115.  
  1116.         mask = 1 << plane;
  1117.         read_ilbm_plane(ifp, chunksizeP, cols, bmhd->compression);
  1118.  
  1119.         ilp = ilbmrow;
  1120.         chp = chunkyrow;
  1121.  
  1122.         cbit = 7;
  1123.         for( col = 0; col < cols; col++, cbit--, chp++ ) {
  1124.             if( cbit < 0 ) {
  1125.                 cbit = 7;
  1126.                 ilp++;
  1127.             }
  1128.             if( *ilp & bit_mask[cbit] )
  1129.                 *chp |= mask;
  1130.             else
  1131.                 *chp &= ~mask;
  1132.         }
  1133.     }
  1134. }
  1135.  
  1136.  
  1137. static void
  1138. decode_mask(ifp, chunksizeP, chunkyrow, bmhd)
  1139.     FILE *ifp;
  1140.     long *chunksizeP;
  1141.     rawtype *chunkyrow;
  1142.     BitMapHeader *bmhd;
  1143. {
  1144.     int col, cols, cbit;
  1145.     unsigned char *ilp;
  1146.  
  1147.     cols = bmhd->w;
  1148.     switch( bmhd->masking ) {
  1149.         case mskNone:
  1150.             break;
  1151.         case mskHasMask:        /* mask plane */
  1152.             read_ilbm_plane(ifp, chunksizeP, cols, bmhd->compression);
  1153.             if( maskfile ) {
  1154.                 ilp = ilbmrow;
  1155.                 cbit = 7;
  1156.                 for( col = 0; col < cols; col++, cbit-- ) {
  1157.                     if( cbit < 0 ) {
  1158.                         cbit = 7;
  1159.                         ilp++;
  1160.                     }
  1161.                     if( *ilp & bit_mask[cbit] )
  1162.                         maskrow[col] = PBM_BLACK;
  1163.                     else
  1164.                         maskrow[col] = PBM_WHITE;
  1165.                 }
  1166.                 pbm_writepbmrow(maskfile, maskrow, cols, 0);
  1167.                 wrotemask = 1;
  1168.             }
  1169.             break;
  1170.         case mskHasTransparentColor:
  1171.             if( maskfile ) {
  1172.                 for( col = 0; col < cols; col++ ) {
  1173.                     if( chunkyrow[col] == bmhd->transparentColor )
  1174.                         maskrow[col] = PBM_WHITE;
  1175.                     else
  1176.                         maskrow[col] = PBM_BLACK;
  1177.                 }
  1178.                 pbm_writepbmrow(maskfile, maskrow, cols, 0);
  1179.                 wrotemask = 1;
  1180.             }
  1181.             break;
  1182.         default:
  1183.             pm_error("decode_mask(): unknown masking type %d - can\'t happen", bmhd->masking);
  1184.     }
  1185. }
  1186.  
  1187.  
  1188. static rawtype *
  1189. alloc_rawrow(cols)
  1190.     int cols;
  1191. {
  1192.     rawtype *r;
  1193.     int i;
  1194.  
  1195.     r = MALLOC(cols, rawtype);
  1196.  
  1197.     for( i = 0; i < cols; i++ )
  1198.         r[i] = 0;
  1199.  
  1200.     return r;
  1201. }
  1202.  
  1203.  
  1204. static void *
  1205. xmalloc(bytes)
  1206.     int bytes;
  1207. {
  1208.     void *mem;
  1209.  
  1210.     if( bytes == 0 )
  1211.         return NULL;
  1212.  
  1213.     mem = malloc(bytes);
  1214.     if( mem == NULL )
  1215.         pm_error("out of memory allocating %d bytes", bytes);
  1216.     return mem;
  1217. }
  1218.  
  1219.  
  1220. static char *
  1221. ID2string(id)
  1222.     IFF_ID id;
  1223. {
  1224.     static char str[] = "abcd";
  1225.  
  1226.     str[0] = (char)(id >> 24 & 0xff);
  1227.     str[1] = (char)(id >> 16 & 0xff);
  1228.     str[2] = (char)(id >>  8 & 0xff);
  1229.     str[3] = (char)(id >>  0 & 0xff);
  1230.  
  1231.     return str;
  1232. }
  1233.  
  1234.  
  1235. /****************************************************************************
  1236.  Multipalette chunk reader
  1237.  
  1238.     Currently there are three multipalette formats:
  1239.         SHAM - sliced HAM (obselete)
  1240.         CTBL - dynamic HAM/Hires (obselete)
  1241.         PCHG - palette change
  1242.     There is no official documentation available for SHAM and CTBL, so
  1243.    this is mostly guesswork from other sources and hexdumps of pictures...
  1244.  
  1245.     CTBL format (dynamic HAM/Hires):
  1246.         16 bigendian words per row (16 bit: 0000rrrrggggbbbb)
  1247.     This is simply an entire 4-bit colormap per row.
  1248.     I have no idea what the DYCP chunk is for.
  1249.  
  1250.     SHAM format (sliced HAM):
  1251.         1 word  - version info (?) - always 0
  1252.         16 bigendian words per row (16 bit: 0000rrrrggggbbbb)
  1253.     If the picture is laced, then there are only rows/2 changes, don't change
  1254.     palette on odd lines.
  1255.  
  1256.     PCHG format:
  1257.     A detailed description of this format is available from AmiNet as PCHGLib12.lha.
  1258.  
  1259.  ****************************************************************************/
  1260.  
  1261. /* local functions */
  1262. static void PCHG_Decompress ARGS((PCHGHeader *PCHG, PCHGCompHeader *CompHdr, unsigned char *compdata, unsigned long compsize, unsigned char *comptree, unsigned char *data));
  1263. static void PCHG_DecompHuff ARGS((unsigned char *src, unsigned char *dest, short *tree, unsigned long origsize));
  1264. static void PCHG_ConvertSmall ARGS((PCHGHeader *PCHG, ColorMap *cmap, unsigned char *data, unsigned long datasize));
  1265. static void PCHG_ConvertBig   ARGS((PCHGHeader *PCHG, ColorMap *cmap, unsigned char *data, unsigned long datasize));
  1266. static void multi_adjust ARGS((ColorMap *cmap, int row, PaletteChange *palchange));
  1267. /* Turn big-endian 4-byte long and 2-byte short stored at x (unsigned char *)
  1268.  * into the native format of the CPU
  1269.  */
  1270. #define BIG_LONG(x) (   ((unsigned long)((x)[0]) << 24) + \
  1271.                         ((unsigned long)((x)[1]) << 16) + \
  1272.                         ((unsigned long)((x)[2]) <<  8) + \
  1273.                         ((unsigned long)((x)[3]) <<  0) )
  1274. #define BIG_WORD(x) (   ((unsigned short)((x)[0]) << 8) + \
  1275.                         ((unsigned short)((x)[1]) << 0) )
  1276.  
  1277.  
  1278.  
  1279. static ColorMap *
  1280. read_4bit_mp(ifp, iffid, chunksize, cmap)
  1281.     FILE *ifp;
  1282.     IFF_ID iffid;
  1283.     long chunksize;
  1284.     ColorMap *cmap;
  1285. {
  1286.     int row, rows, i, type;
  1287.     short data;
  1288.  
  1289.     if( !cmap )
  1290.         cmap = alloc_cmap();
  1291.  
  1292.     type = (iffid == ID_SHAM ? MP_TYPE_SHAM : MP_TYPE_CTBL);
  1293.  
  1294.     if( cmap->mp_type >= type ) {
  1295.         skip_chunk(ifp, iffid, chunksize);
  1296.         return cmap;
  1297.     }
  1298.     if( cmap->mp_type )
  1299.         multi_free(cmap);
  1300.     cmap->mp_type = type;
  1301.  
  1302.     if( type == MP_TYPE_SHAM ) {
  1303.         cmap->mp_flags = MP_FLAGS_SKIPLACED;
  1304.         (void)get_big_short(ifp, iffid, &chunksize);   /* skip first word */
  1305.     }
  1306.  
  1307.     cmap->mp_rows = rows = chunksize/32;    /* sizeof(word) * 16 */
  1308.     cmap->mp_change = MALLOC(rows, PaletteChange *);
  1309.  
  1310.     for( row = 0; row < rows; row++ ) {
  1311.         cmap->mp_change[row] = MALLOC(17, PaletteChange);   /* 16 + sentinel */
  1312.         for( i = 0; i < 16; i++ ) {
  1313.             data = get_big_short(ifp, iffid, &chunksize);
  1314.             cmap->mp_change[row][i].reg = i;
  1315.             cmap->mp_change[row][i].r = ((data & 0x0f00) >> 8) * FACTOR_4BIT;
  1316.             cmap->mp_change[row][i].g = ((data & 0x00f0) >> 4) * FACTOR_4BIT;
  1317.             cmap->mp_change[row][i].b = ((data & 0x000f) >> 0) * FACTOR_4BIT;
  1318.         }
  1319.         cmap->mp_change[row][16].reg = MP_REG_END;   /* sentinel */
  1320.     }
  1321.     chunk_end(ifp, iffid, chunksize);
  1322.     return cmap;
  1323. }
  1324.  
  1325.  
  1326. static ColorMap *
  1327. read_pchg(ifp, iffid, chunksize, cmap)
  1328.     FILE *ifp;
  1329.     IFF_ID iffid;
  1330.     long chunksize;
  1331.     ColorMap *cmap;
  1332. {
  1333.     PCHGHeader      PCHG;
  1334.     unsigned char   *data;
  1335.     unsigned long   datasize;
  1336.     int i;
  1337.  
  1338.     if( !cmap )
  1339.         cmap = alloc_cmap();
  1340.  
  1341.     if( cmap->mp_type >= MP_TYPE_PCHG ) {
  1342.         skip_chunk(ifp, iffid, chunksize);
  1343.         return cmap;
  1344.     }
  1345.     if( cmap->mp_type )
  1346.         multi_free(cmap);
  1347.     cmap->mp_type = MP_TYPE_PCHG;
  1348.  
  1349.     PCHG.Compression = get_big_short(ifp, iffid, &chunksize);
  1350.     PCHG.Flags       = get_big_short(ifp, iffid, &chunksize);
  1351.     PCHG.StartLine   = get_big_short(ifp, iffid, &chunksize);
  1352.     PCHG.LineCount   = get_big_short(ifp, iffid, &chunksize);
  1353.     PCHG.ChangedLines= get_big_short(ifp, iffid, &chunksize);
  1354.     PCHG.MinReg      = get_big_short(ifp, iffid, &chunksize);
  1355.     PCHG.MaxReg      = get_big_short(ifp, iffid, &chunksize);
  1356.     PCHG.MaxChanges  = get_big_short(ifp, iffid, &chunksize);
  1357.     PCHG.TotalChanges= get_big_long(ifp, iffid, &chunksize);
  1358.  
  1359. #ifdef DEBUG
  1360.     pm_message("PCHG StartLine   : %d", PCHG.StartLine);
  1361.     pm_message("PCHG LineCount   : %d", PCHG.LineCount);
  1362.     pm_message("PCHG ChangedLines: %d", PCHG.ChangedLines);
  1363.     pm_message("PCHG TotalChanges: %d", PCHG.TotalChanges);
  1364. #endif
  1365.  
  1366.     if( PCHG.Compression != PCHG_COMP_NONE ) {
  1367.         PCHGCompHeader  CompHdr;
  1368.         unsigned char *compdata, *comptree;
  1369.         long treesize, compsize;
  1370.  
  1371.         CompHdr.CompInfoSize     = get_big_long(ifp, iffid, &chunksize);
  1372.         CompHdr.OriginalDataSize = get_big_long(ifp, iffid, &chunksize);
  1373.  
  1374.         treesize = CompHdr.CompInfoSize;
  1375.         comptree = MALLOC(treesize, unsigned char);
  1376.         read_bytes(ifp, treesize, comptree, iffid, &chunksize);
  1377.  
  1378.         compsize = chunksize;
  1379.         compdata= MALLOC(chunksize, unsigned char);
  1380.         read_bytes(ifp, compsize, compdata, iffid, &chunksize);
  1381.  
  1382.         datasize = CompHdr.OriginalDataSize;
  1383.         data    = MALLOC(datasize, unsigned char);
  1384.         PCHG_Decompress(&PCHG, &CompHdr, compdata, compsize, comptree, data);
  1385.  
  1386.         free(comptree);
  1387.         free(compdata);
  1388.     }
  1389.     else {
  1390. #ifdef DEBUG
  1391.         pm_message("uncompressed PCHG");
  1392. #endif
  1393.         datasize = chunksize;
  1394.         data = MALLOC(datasize, unsigned char);
  1395.         read_bytes(ifp, datasize, data, iffid, &chunksize);
  1396.     }
  1397.  
  1398.     if( PCHG.Flags & PCHGF_USE_ALPHA )
  1399.         pm_message("warning - PCHG alpha channel not supported");
  1400.  
  1401.     cmap->mp_rows = PCHG.StartLine + PCHG.LineCount;
  1402.     cmap->mp_change = MALLOC(cmap->mp_rows, PaletteChange *);
  1403.     for( i = 0; i < cmap->mp_rows; i++ )
  1404.         cmap->mp_change[i] = NULL;
  1405.     if( PCHG.StartLine < 0 ) {
  1406.         int nch;
  1407.         nch = PCHG.MaxReg - PCHG.MinReg +1;
  1408.         cmap->mp_init = MALLOC(nch + 1, PaletteChange);
  1409.         for( i = 0; i < nch; i++ )
  1410.             cmap->mp_init[i].reg = MP_REG_IGNORE;
  1411.         cmap->mp_init[nch].reg = MP_REG_END;
  1412.     }
  1413.  
  1414.     if( PCHG.Flags & PCHGF_12BIT ) {
  1415. #ifdef DEBUG
  1416.         pm_message("SmallLineChanges");
  1417. #endif
  1418.         PCHG_ConvertSmall(&PCHG, cmap, data, datasize);
  1419.     }
  1420.     else
  1421.     if( PCHG.Flags & PCHGF_32BIT ) {
  1422. #ifdef DEBUG
  1423.         pm_message("BigLineChanges");
  1424. #endif
  1425.         PCHG_ConvertBig(&PCHG, cmap, data, datasize);
  1426.     }
  1427.     else
  1428.         pm_error("unknown palette changes structure format in %s chunk", ID2string(iffid));
  1429.  
  1430.     free(data);
  1431.     chunk_end(ifp, iffid, chunksize);
  1432.     return cmap;
  1433. }
  1434.  
  1435.  
  1436. static void
  1437. PCHG_Decompress(PCHG, CompHdr, compdata, compsize, comptree, data)
  1438.     PCHGHeader *PCHG;
  1439.     PCHGCompHeader *CompHdr;
  1440.     unsigned char *compdata;
  1441.     unsigned long compsize;
  1442.     unsigned char *comptree;
  1443.     unsigned char *data;
  1444. {
  1445.     short *hufftree;
  1446.     unsigned long huffsize, i;
  1447.     unsigned long treesize = CompHdr->CompInfoSize;
  1448.  
  1449.     switch( PCHG->Compression ) {
  1450.         case PCHG_COMP_HUFFMAN:
  1451.  
  1452. #ifdef DEBUG
  1453.             pm_message("PCHG Huffman compression");
  1454. #endif
  1455.             /* turn big-endian 2-byte shorts into native format */
  1456.             huffsize = treesize/2;
  1457.             hufftree = MALLOC(huffsize, short);
  1458.             for( i = 0; i < huffsize; i++ ) {
  1459.                 hufftree[i] = (short)BIG_WORD(comptree);
  1460.                 comptree += 2;
  1461.             }
  1462.  
  1463.             /* decompress the change structure data */
  1464.             PCHG_DecompHuff(compdata, data, &hufftree[huffsize-1], CompHdr->OriginalDataSize);
  1465.  
  1466.             free(hufftree);
  1467.             break;
  1468.         default:
  1469.             pm_error("unknown PCHG compression type %d", PCHG->Compression);
  1470.     }
  1471. }
  1472.  
  1473.  
  1474. static void
  1475. PCHG_ConvertSmall(PCHG, cmap, mask, datasize)
  1476.     PCHGHeader *PCHG;
  1477.     ColorMap *cmap;
  1478.     unsigned char *mask;
  1479.     unsigned long datasize;
  1480. {
  1481.     unsigned char *data;
  1482.     unsigned char thismask;
  1483.     int bits, row, i, changes, masklen, reg;
  1484.     unsigned char ChangeCount16, ChangeCount32;
  1485.     unsigned short SmallChange;
  1486.     unsigned long totalchanges = 0;
  1487.     int changedlines = PCHG->ChangedLines;
  1488.  
  1489.     masklen = 4 * MaskLongWords(PCHG->LineCount);
  1490.     data = mask + masklen; datasize -= masklen;
  1491.  
  1492.     bits = 0;
  1493.     for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
  1494.         if( bits == 0 ) {
  1495.             if( masklen == 0 ) goto fail2;
  1496.             thismask = *mask++;
  1497.             --masklen;
  1498.             bits = 8;
  1499.         }
  1500.         if( thismask & (1<<7) ) {
  1501.             if( datasize < 2 ) goto fail;
  1502.             ChangeCount16 = *data++;
  1503.             ChangeCount32 = *data++;
  1504.             datasize -= 2;
  1505.  
  1506.             changes = ChangeCount16 + ChangeCount32;
  1507.             for( i = 0; i < changes; i++ ) {
  1508.                 if( totalchanges >= PCHG->TotalChanges ) goto fail;
  1509.                 if( datasize < 2 ) goto fail;
  1510.                 SmallChange = BIG_WORD(data); data += 2; datasize -= 2;
  1511.                 reg = ((SmallChange & 0xf000) >> 12) + (i >= ChangeCount16 ? 16 : 0);
  1512.                 cmap->mp_init[reg - PCHG->MinReg].reg = reg;
  1513.                 cmap->mp_init[reg - PCHG->MinReg].r = ((SmallChange & 0x0f00) >> 8) * FACTOR_4BIT;
  1514.                 cmap->mp_init[reg - PCHG->MinReg].g = ((SmallChange & 0x00f0) >> 4) * FACTOR_4BIT;
  1515.                 cmap->mp_init[reg - PCHG->MinReg].b = ((SmallChange & 0x000f) >> 0) * FACTOR_4BIT;
  1516.                 ++totalchanges;
  1517.             }
  1518.             --changedlines;
  1519.         }
  1520.         thismask <<= 1;
  1521.         bits--;
  1522.     }
  1523.  
  1524.     for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
  1525.         if( bits == 0 ) {
  1526.             if( masklen == 0 ) goto fail2;
  1527.             thismask = *mask++;
  1528.             --masklen;
  1529.             bits = 8;
  1530.         }
  1531.         if( thismask & (1<<7) ) {
  1532.             if( datasize < 2 ) goto fail;
  1533.             ChangeCount16 = *data++;
  1534.             ChangeCount32 = *data++;
  1535.             datasize -= 2;
  1536.  
  1537.             changes = ChangeCount16 + ChangeCount32;
  1538.             cmap->mp_change[row] = MALLOC(changes + 1, PaletteChange);
  1539.             for( i = 0; i < changes; i++ ) {
  1540.                 if( totalchanges >= PCHG->TotalChanges ) goto fail;
  1541.                 if( datasize < 2 ) goto fail;
  1542.                 SmallChange = BIG_WORD(data); data += 2; datasize -= 2;
  1543.                 reg = ((SmallChange & 0xf000) >> 12) + (i >= ChangeCount16 ? 16 : 0);
  1544.                 cmap->mp_change[row][i].reg = reg;
  1545.                 cmap->mp_change[row][i].r = ((SmallChange & 0x0f00) >> 8) * FACTOR_4BIT;
  1546.                 cmap->mp_change[row][i].g = ((SmallChange & 0x00f0) >> 4) * FACTOR_4BIT;
  1547.                 cmap->mp_change[row][i].b = ((SmallChange & 0x000f) >> 0) * FACTOR_4BIT;
  1548.                 ++totalchanges;
  1549.             }
  1550.             cmap->mp_change[row][changes].reg = MP_REG_END;
  1551.             --changedlines;
  1552.         }
  1553.         thismask <<= 1;
  1554.         bits--;
  1555.     }
  1556.     if( totalchanges != PCHG->TotalChanges )
  1557.         pm_message("warning - got %ld change structures, chunk header reports %ld", totalchanges, PCHG->TotalChanges);
  1558.     return;
  1559. fail:
  1560.     pm_error("insufficient data in SmallLineChanges structures");
  1561. fail2:
  1562.     pm_error("insufficient data in line mask");
  1563. }
  1564.  
  1565.  
  1566. static void
  1567. PCHG_ConvertBig(PCHG, cmap, mask, datasize)
  1568.     PCHGHeader *PCHG;
  1569.     ColorMap *cmap;
  1570.     unsigned char *mask;
  1571.     unsigned long datasize;
  1572. {
  1573.     unsigned char *data;
  1574.     unsigned char thismask;
  1575.     int bits, row, i, changes, masklen, reg;
  1576.     unsigned long totalchanges = 0;
  1577.     int changedlines = PCHG->ChangedLines;
  1578.  
  1579.     masklen = 4 * MaskLongWords(PCHG->LineCount);
  1580.     data = mask + masklen; datasize -= masklen;
  1581.  
  1582.     bits = 0;
  1583.     for( row = PCHG->StartLine; changedlines && row < 0; row++ ) {
  1584.         if( bits == 0 ) {
  1585.             if( masklen == 0 ) goto fail2;
  1586.             thismask = *mask++;
  1587.             --masklen;
  1588.             bits = 8;
  1589.         }
  1590.         if( thismask & (1<<7) ) {
  1591.             if( datasize < 2 ) goto fail;
  1592.             changes = BIG_WORD(data); data += 2; datasize -= 2;
  1593.  
  1594.             for( i = 0; i < changes; i++ ) {
  1595.                 if( totalchanges >= PCHG->TotalChanges ) goto fail;
  1596.                 if( datasize < 6 ) goto fail;
  1597.                 reg = BIG_WORD(data); data += 2;
  1598.                 cmap->mp_init[reg - PCHG->MinReg].reg = reg;
  1599.                 ++data; /* skip alpha */
  1600.                 cmap->mp_init[reg - PCHG->MinReg].r = *data++;
  1601.                 cmap->mp_init[reg - PCHG->MinReg].b = *data++;    /* yes, RBG */
  1602.                 cmap->mp_init[reg - PCHG->MinReg].g = *data++;
  1603.                 datasize -= 6;
  1604.                 ++totalchanges;
  1605.             }
  1606.             --changedlines;
  1607.         }
  1608.         thismask <<= 1;
  1609.         bits--;
  1610.     }
  1611.  
  1612.     for( row = PCHG->StartLine; changedlines && row < cmap->mp_rows; row++ ) {
  1613.         if( bits == 0 ) {
  1614.             if( masklen == 0 ) goto fail2;
  1615.             thismask = *mask++;
  1616.             --masklen;
  1617.             bits = 8;
  1618.         }
  1619.         if( thismask & (1<<7) ) {
  1620.             if( datasize < 2 ) goto fail;
  1621.             changes = BIG_WORD(data); data += 2; datasize -= 2;
  1622.  
  1623.             cmap->mp_change[row] = MALLOC(changes + 1, PaletteChange);
  1624.             for( i = 0; i < changes; i++ ) {
  1625.                 if( totalchanges >= PCHG->TotalChanges ) goto fail;
  1626.                 if( datasize < 6 ) goto fail;
  1627.                 reg = BIG_WORD(data); data += 2;
  1628.                 cmap->mp_change[row][i].reg = reg;
  1629.                 ++data; /* skip alpha */
  1630.                 cmap->mp_change[row][i].r = *data++;
  1631.                 cmap->mp_change[row][i].b = *data++;    /* yes, RBG */
  1632.                 cmap->mp_change[row][i].g = *data++;
  1633.                 datasize -= 6;
  1634.                 ++totalchanges;
  1635.             }
  1636.             cmap->mp_change[row][changes].reg = MP_REG_END;
  1637.             --changedlines;
  1638.         }
  1639.         thismask <<= 1;
  1640.         bits--;
  1641.     }
  1642.     if( totalchanges != PCHG->TotalChanges )
  1643.         pm_message("warning - got %ld change structures, chunk header reports %ld", totalchanges, PCHG->TotalChanges);
  1644.     return;
  1645. fail:
  1646.     pm_error("insufficient data in BigLineChanges structures");
  1647. fail2:
  1648.     pm_error("insufficient data in line mask");
  1649. }
  1650.  
  1651.  
  1652. static void
  1653. PCHG_DecompHuff(src, dest, tree, origsize)
  1654.     unsigned char *src, *dest;
  1655.     short *tree;
  1656.     unsigned long origsize;
  1657. {
  1658.     unsigned long i = 0, bits = 0;
  1659.     unsigned char thisbyte;
  1660.     short *p;
  1661.  
  1662.     p = tree;
  1663.     while( i < origsize ) {
  1664.         if( bits == 0 ) {
  1665.             thisbyte = *src++;
  1666.             bits = 8;
  1667.         }
  1668.         if( thisbyte & (1 << 7) ) {
  1669.             if( *p >= 0 ) {
  1670.                 *dest++ = (unsigned char)*p;
  1671.                 i++;
  1672.                 p = tree;
  1673.             }
  1674.             else
  1675.                 p += (*p / 2);
  1676.         }
  1677.         else {
  1678.             p--;
  1679.             if( *p > 0 && (*p & 0x100) ) {
  1680.                 *dest++ = (unsigned char )*p;
  1681.                 i++;
  1682.                 p = tree;
  1683.             }
  1684.         }
  1685.         thisbyte <<= 1;
  1686.         bits--;
  1687.     }
  1688. }
  1689.  
  1690.  
  1691. /****************************************************************************
  1692.  Multipalette handling
  1693.  ****************************************************************************/
  1694.  
  1695.  
  1696. static void
  1697. multi_adjust(cmap, row, palchange)
  1698.     ColorMap *cmap;
  1699.     int row;
  1700.     PaletteChange *palchange;
  1701. {
  1702.     int i, reg;
  1703.  
  1704.     for( i = 0; palchange[i].reg != MP_REG_END; i++ ) {
  1705.         reg = palchange[i].reg;
  1706.         if( reg >= cmap->ncolors ) {
  1707.             pm_message("warning - palette change register out of range");
  1708.             pm_message("    row %d  change structure %d  reg=%d (max %d)", row, i, reg, cmap->ncolors-1);
  1709.             pm_message("    ignoring it... colors might get messed up from here");
  1710.         }
  1711.         else
  1712.         if( reg != MP_REG_IGNORE ) {
  1713.             PPM_ASSIGN(cmap->color[reg], palchange[i].r, palchange[i].g, palchange[i].b);
  1714.         }
  1715.     }
  1716. }
  1717.  
  1718. static void
  1719. multi_init(cmap, viewportmodes)
  1720.     ColorMap *cmap;
  1721.     long viewportmodes;
  1722. {
  1723.     if( cmap->mp_init )
  1724.         multi_adjust(cmap, -1, cmap->mp_init);
  1725.     if( !(viewportmodes & vmLACE) )
  1726.         cmap->mp_flags &= ~(MP_FLAGS_SKIPLACED);
  1727. }
  1728.  
  1729. static void
  1730. multi_update(cmap, row)
  1731.     ColorMap *cmap;
  1732.     int row;
  1733. {
  1734.     if( cmap->mp_flags & MP_FLAGS_SKIPLACED ) {
  1735.         if( odd(row) )
  1736.             return;
  1737.         if( row/2 < cmap->mp_rows && cmap->mp_change[row/2] )
  1738.             multi_adjust(cmap, row, cmap->mp_change[row/2]);
  1739.     }
  1740.     else {
  1741.         if( row < cmap->mp_rows && cmap->mp_change[row] )
  1742.             multi_adjust(cmap, row, cmap->mp_change[row]);
  1743.     }
  1744. }
  1745.  
  1746. static void
  1747. multi_free(cmap)
  1748.     ColorMap *cmap;
  1749. {
  1750.     int i;
  1751.  
  1752.     if( cmap->mp_init ) {
  1753.         free(cmap->mp_init);
  1754.         cmap->mp_init = NULL;
  1755.     }
  1756.     if( cmap->mp_change ) {
  1757.         for( i = 0; i < cmap->mp_rows; i++ ) {
  1758.             if( cmap->mp_change[i] )
  1759.                 free(cmap->mp_change[i]);
  1760.         }
  1761.         free(cmap->mp_change);
  1762.         cmap->mp_change = NULL;
  1763.     }
  1764.     cmap->mp_rows = 0;
  1765.     cmap->mp_type = 0;
  1766.     cmap->mp_flags = 0;
  1767. }
  1768.  
  1769.  
  1770. /****************************************************************************
  1771.  Colormap handling
  1772.  ****************************************************************************/
  1773.  
  1774. static ColorMap *
  1775. alloc_cmap ARGS((void))
  1776. {
  1777.     ColorMap *cmap;
  1778.  
  1779.     cmap = MALLOC(1, ColorMap);
  1780.     cmap->color = NULL;
  1781.     cmap->ncolors = 0;
  1782.     cmap->monolut = cmap->redlut = cmap->greenlut = cmap->bluelut = NULL;
  1783.     cmap->mp_init = NULL;
  1784.     cmap->mp_change = NULL;
  1785.     cmap->mp_rows = cmap->mp_type = cmap->mp_flags = 0;
  1786.     return cmap;
  1787. }
  1788.  
  1789.  
  1790. static void
  1791. check_cmap(bmhd, cmap)
  1792.     BitMapHeader *bmhd;
  1793.     ColorMap *cmap;
  1794. {
  1795.     pixval colmaxval = 0;
  1796.     int shifted = 1;
  1797.     int i, r, g, b;
  1798.  
  1799.     if( bmhd ) {
  1800.         if( bmhd->masking == mskHasTransparentColor || bmhd->masking == mskLasso ) {
  1801.             transpIndex = bmhd->transparentColor;
  1802.             if( !transpName ) {
  1803.                 transpColor = MALLOC(1, pixel);
  1804.                 if( transpIndex >= cmap->ncolors ) {
  1805.                     pm_message("using default transparent color (black)");
  1806.                     PPM_ASSIGN(*transpColor, 0, 0, 0);
  1807.                 }
  1808.                 else
  1809.                     *transpColor = cmap->color[transpIndex];
  1810.             }
  1811.         }
  1812.  
  1813.         if( bmhd->flags & BMHD_FLAGS_CMAPOK )
  1814.             return;
  1815.     }
  1816.  
  1817.     if( !HAS_COLORMAP(cmap) )
  1818.         return;
  1819.  
  1820.     for( i = 0; i < cmap->ncolors; i++ ) {
  1821.         r = PPM_GETR(cmap->color[i]);
  1822.         if( r > colmaxval ) colmaxval = r;
  1823.         if( r & 0x0f ) shifted = 0;
  1824.  
  1825.         g = PPM_GETG(cmap->color[i]);
  1826.         if( g > colmaxval ) colmaxval = g;
  1827.         if( g & 0x0f ) shifted = 0;
  1828.  
  1829.         b = PPM_GETB(cmap->color[i]);
  1830.         if( b > colmaxval ) colmaxval = b;
  1831.         if( b & 0x0f ) shifted = 0;
  1832.     }
  1833.  
  1834. #ifdef DEBUG
  1835.     pm_message("colormap maxval is %d", colmaxval);
  1836. #endif
  1837.     if( colmaxval == 0 )
  1838.         pm_message("warning - black colormap");
  1839.     else
  1840.     if( shifted || colmaxval <= 15 ) {
  1841.         if( !adjustcolors ) {
  1842.             pm_message("warning - probably %s4-bit colormap",
  1843.                         shifted ? "shifted " : "");
  1844.             pm_message("    use \"-adjustcolors\" to scale colormap to 8 bits");
  1845.         }
  1846.         else {
  1847.             pm_message("scaling colormap to 8 bits");
  1848.             for( i = 0; i < cmap->ncolors; i++ ) {
  1849.                 r = PPM_GETR(cmap->color[i]);
  1850.                 g = PPM_GETG(cmap->color[i]);
  1851.                 b = PPM_GETB(cmap->color[i]);
  1852.                 if( shifted ) {
  1853.                     r >>= 4;
  1854.                     g >>= 4;
  1855.                     b >>= 4;
  1856.                 }
  1857.                 r *= FACTOR_4BIT;
  1858.                 g *= FACTOR_4BIT;
  1859.                 b *= FACTOR_4BIT;
  1860.                 PPM_ASSIGN(cmap->color[i], r, g, b);
  1861.             }
  1862.         }
  1863.     }
  1864. }
  1865.  
  1866.  
  1867. static void
  1868. get_color(cmap, idx, red, green, blue)
  1869.     ColorMap *cmap;
  1870.     int idx;
  1871.     pixval *red, *green, *blue;
  1872. {
  1873.     if( HAS_COLORMAP(cmap) ) {
  1874.         pixval r, g, b;
  1875.  
  1876.         if( idx >= cmap->ncolors )
  1877.             pm_error("color index out of range: %d (max %d)", idx, cmap->ncolors);
  1878.         r = PPM_GETR(cmap->color[idx]);
  1879.         g = PPM_GETG(cmap->color[idx]);
  1880.         b = PPM_GETB(cmap->color[idx]);
  1881.  
  1882.         *red    = lookup_red(cmap, r);
  1883.         *green  = lookup_green(cmap, g);
  1884.         *blue   = lookup_blue(cmap, b);
  1885.     }
  1886.     else {
  1887.         *red = *green = *blue = lookup_mono(cmap, idx);
  1888.     }
  1889. }
  1890.  
  1891.  
  1892. static pixval
  1893. lookup_red(cmap, oldval)
  1894.     ColorMap *cmap;
  1895.     int oldval;
  1896. {
  1897.     if( cmap && cmap->redlut && oldval < 256 )
  1898.         return cmap->redlut[oldval];
  1899.     else
  1900.         return oldval;
  1901. }
  1902.  
  1903. static pixval
  1904. lookup_green(cmap, oldval)
  1905.     ColorMap *cmap;
  1906.     int oldval;
  1907. {
  1908.     if( cmap && cmap->greenlut && oldval < 256 )
  1909.         return cmap->greenlut[oldval];
  1910.     else
  1911.         return oldval;
  1912. }
  1913.  
  1914. static pixval
  1915. lookup_blue(cmap, oldval)
  1916.     ColorMap *cmap;
  1917.     int oldval;
  1918. {
  1919.     if( cmap && cmap->bluelut && oldval < 256 )
  1920.         return cmap->bluelut[oldval];
  1921.     else
  1922.         return oldval;
  1923. }
  1924.  
  1925. static pixval
  1926. lookup_mono(cmap, oldval)
  1927.     ColorMap *cmap;
  1928.     int oldval;
  1929. {
  1930.     if( cmap && cmap->monolut && oldval < 256 )
  1931.         return cmap->monolut[oldval];
  1932.     else
  1933.         return oldval;
  1934. }
  1935.  
  1936. static ColorMap *
  1937. ehbcmap(cmap)
  1938.     ColorMap *cmap;
  1939. {
  1940.     pixel *tempcolor = NULL;
  1941.     int i, col;
  1942.  
  1943.     col = cmap->ncolors;
  1944.  
  1945.     tempcolor = ppm_allocrow(col * 2);
  1946.     for( i = 0; i < col; i++ ) {
  1947.         tempcolor[i] = cmap->color[i];
  1948.         PPM_ASSIGN(tempcolor[col + i],  PPM_GETR(cmap->color[i]) / 2,
  1949.                                         PPM_GETG(cmap->color[i]) / 2,
  1950.                                         PPM_GETB(cmap->color[i]) / 2 );
  1951.     }
  1952.     ppm_freerow(cmap->color);
  1953.     cmap->color = tempcolor;
  1954.     cmap->ncolors *= 2;
  1955.  
  1956.     return cmap;
  1957. }
  1958.  
  1959.  
  1960. static pixval
  1961. #if __STDC__
  1962. lut_maxval(ColorMap *cmap, pixval maxval)
  1963. #else
  1964. lut_maxval(cmap, maxval)
  1965.     ColorMap *cmap;
  1966.     pixval maxval;
  1967. #endif
  1968. {
  1969.     int i;
  1970.  
  1971.     if( maxval < 255 ) {
  1972.         if( HAS_COLORLUT(cmap) ) {
  1973.             pixval oldmaxval = maxval;
  1974.             for( i = 0; i < oldmaxval; i++ ) {
  1975.                 if( cmap->redlut   && cmap->redlut[i]   > maxval ) maxval = cmap->redlut[i];
  1976.                 if( cmap->greenlut && cmap->greenlut[i] > maxval ) maxval = cmap->greenlut[i];
  1977.                 if( cmap->bluelut  && cmap->bluelut[i]  > maxval ) maxval = cmap->bluelut[i];
  1978.             }
  1979.             pm_message("warning - %d-bit index into 8-bit color lookup table, table maxval=%d", pm_maxvaltobits(oldmaxval), maxval);
  1980.             if( maxval != oldmaxval )
  1981.                 maxval = 255;
  1982.             pm_message("    assuming image maxval=%d", maxval);
  1983.         }
  1984.     }
  1985.     return maxval;
  1986. }
  1987.  
  1988.  
  1989. /****************************************************************************
  1990.  Basic I/O functions
  1991.  ****************************************************************************/
  1992. static void readerr ARGS((FILE *f, IFF_ID iffid));
  1993.  
  1994.  
  1995. static void
  1996. readerr(f, iffid)
  1997.     FILE *f;
  1998.     IFF_ID iffid;
  1999. {
  2000.     if( ferror(f) )
  2001.         pm_error("read error");
  2002.     else
  2003.         pm_error("premature EOF in %s chunk", ID2string(iffid));
  2004. }
  2005.  
  2006.  
  2007. static void
  2008. read_bytes(ifp, bytes, buffer, iffid, counter)
  2009.     FILE *ifp;
  2010.     int bytes;
  2011.     unsigned char *buffer;
  2012.     IFF_ID iffid;
  2013.     long *counter;
  2014. {
  2015.     if( counter ) {
  2016.         if( *counter < bytes )
  2017.             pm_error("insufficient data in %s chunk", ID2string(iffid));
  2018.         *counter -= bytes;
  2019.     }
  2020.     if( fread(buffer, 1, bytes, ifp) != bytes )
  2021.         readerr(ifp, iffid);
  2022. }
  2023.  
  2024.  
  2025. static unsigned char
  2026. get_byte(ifp, iffid, counter)
  2027.     FILE* ifp;
  2028.     IFF_ID iffid;
  2029.     long *counter;
  2030. {
  2031.     int i;
  2032.  
  2033.     if( counter ) {
  2034.         if( *counter == 0 )
  2035.             pm_error("insufficient data in %s chunk", ID2string(iffid));
  2036.         --(*counter);
  2037.     }
  2038.     i = getc(ifp);
  2039.     if( i == EOF )
  2040.         readerr(ifp, iffid);
  2041.  
  2042.     return (unsigned char) i;
  2043. }
  2044.  
  2045. static long
  2046. get_big_long(ifp, iffid, counter)
  2047.     FILE *ifp;
  2048.     IFF_ID iffid;
  2049.     long *counter;
  2050. {
  2051.     long l;
  2052.  
  2053.     if( counter ) {
  2054.         if( *counter < 4 )
  2055.             pm_error("insufficient data in %s chunk", ID2string(iffid));
  2056.         *counter -= 4;
  2057.     }
  2058.     if( pm_readbiglong(ifp, &l) == -1 )
  2059.         readerr(ifp, iffid);
  2060.  
  2061.     return l;
  2062. }
  2063.  
  2064. static short
  2065. get_big_short(ifp, iffid, counter)
  2066.     FILE *ifp;
  2067.     IFF_ID iffid;
  2068.     long *counter;
  2069. {
  2070.     short s;
  2071.  
  2072.     if( counter ) {
  2073.         if( *counter < 2 )
  2074.             pm_error("insufficient data in %s chunk", ID2string(iffid));
  2075.         *counter -= 2;
  2076.     }
  2077.     if( pm_readbigshort(ifp, &s) == -1 )
  2078.         readerr(ifp, iffid);
  2079.  
  2080.     return s;
  2081. }
  2082.  
  2083.