/****************************************************************************
 *
 *  I2C (Image2'C') 1.2
 *  Copyright © 1994,1995 Udo Schuermann
 *  All rights reserved
 *
 *  This program uses  iffparse.library  to load an ILBM from a FORM IFF
 *  (in plain English, it loads an IFF picture) and produces output that
 *  can be used directly as part of a  struct Image  in your 'C' source
 *  code.
 *
 *  I make this code available as a demonstration of an exceedingly simple,
 *  yet functional program that uses  iffparse.library  and does something
 *  moderately useful with it.  Of some interest might be the fact that
 *  the program extracts a number of additional properties from the file,
 *  if they are present: ANNO, AUTH, (c), and FVER chunks are inserted in
 *  the output file as comments.  Hopefully, none of these contain the end-
 *  comment symbol... :-7
 *
 *  THIS PROGRAM MAY *NOT* BE DISTRIBUTED WITHOUT SOURCE CODE AND ALL
 *  NOTICES INTACT.  YOU MAY NOT SELL THIS PROGRAM OR INCLUDE IT WITH
 *  A COMMERCIAL PRODUCT WITHOUT EXPRESS WRITTEN PERMISSION FROM THE
 *  AUTHOR.  IT IS PERMITTED TO DISTRIBUTE THIS PROGRAM BY ELECTRONIC
 *  MEANS (USENET), OR AS PART OF FRED FISH'S CD-ROMS OR RELATED
 *  COLLECTIONS.  YOU MAY USE IT FOR INSTRUCTIONAL PURPOSES, AND EVEN
 *  GIVE IT TO FRIENDS, BUT DON'T YOU SELL IT OR YOUR NAME SHALL BE
 *  FOREVER STAINED.
 *
 *  Commodore is dead.  Long live the Amiga!
 *
 *  Share and enjoy!  ;-)
 *
 *  ---------------------------------------------------------------------
 *
 *  This program uses the following CLI template (I am not using standard
 *  code for that, but am parsing the command line on my own):
 *
 *  ILBMFILE/A,SYMPREFIX/A,NOINFO/S,NOPENS/S,NODATA/S,NOIMAGESTRUCT/S,
 *	NORGB4/S,USEIFDEFS/S,NOCHIP/S
 *
 *  ILBMFILE/A		Must always be given.  This is the IFF ILBM input
 *			file to be converted.  I2C supports images up to
 *			8 bitplanes deep (actually, any bitplane oriented
 *			ILBM)
 *
 *  SYMPREFIX/A		Must always be given.  The symbol prefix for this
 *			image file.  This forms the prefix to all symbols
 *			in the file.
 *			Example:  A prefix of "myImage_" will generate
 *			symbols such as "UWORD myImage_ImageData[]"
 *
 *  NOINFO/S		This switch will cause image information, such
 *			such as height, width, depth, number of colors
 *			to be omitted.  See also NOIMAGESTRUCT below!
 *
 *  NOPENS/S		This switch will cause pens (used by LoadRGB32()
 *			for example) to be omitted.
 *
 *  NODATA/S		This switch will cause the actual image data to
 *			be omitted.  See also NOIMAGESTRUCT below!
 *
 *  NOIMAGESTRUCT/S	This switch will cause a "struct Image ..." item
 *			to be omitted.  This item requires the presence
 *			of INFO and DATA items; if you specify that either
 *			or both of those should not be included (NOINFO
 *			and/or NODATA) but you do not also specify the
 *			NOIMAGESTRUCT, then I2C will reverse your decision
 *			on NOINFO and/or NODATA so that the Image struct
 *			can be built.
 *
 *  ADDRGB4/S		This switch will cause register color values to
 *			be added.  Such values are 12-bit only and are
 *			probably of use only for older software.  It is
 *			for this reason that this is the only switch that
 *		    	needs to be specified to add something to the
 *			code; i.e. if not specified you will NOT get the
 *			information for this item.
 *
 *  USEIFDEFS/S		This switch encloses the INFO, PENS, DATA, IMG,
 *			and RGB4 sections with #ifdef/#endif constructs
 *			to allow you to build a source file with ALL
 *			information, but decide at a later time which
 *			portions the compiler should include or ignore.
 *			Use of this switch enables an additional level
 *			of flexibility, which you may or may not find
 *			of use.
 *
 *			The following #define statements used BEFORE you
 *			#include the source code generated by I2C will
 *			tell the compiler which portions of the file to
 *			use and which to ignore:
 *
 *			#define I2C_IMAGE_INFO		Accept image info
 *			#define I2C_IMAGE_PENS		Accept RGB32 pens
 *			#define I2C_IMAGE_RGB4		Accept 4-bit pens
 *			#define I2C_IMAGE_DATA		Accept image data
 *			#define I2C_IMAGE_IMG		Accept struct Image
 *
 *  NOCHIP/S		Omit the __chip attribute on structures.  This may
 *			be desirable if you are going to remap image colors
 *			anyway and won't be needing the original in chip
 *			RAM.
 *
 *  If you are not clear on some of the points described above, you are
 *  hereby STRONGLY advised to run the program on a test image and see what
 *  the resulting output file contains.  Try this:
 *
 *	I2C  TestImage.IFF  MyTest_  USEIFDEFS
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <libraries/iffparse.h>

#include <proto/dos.h>
#include <proto/iffparse.h>


/* If we define __MYDATE__ from the commandline, then we'll use that instead of
 * redefining it to the standard Amiga __AMIGADATE__ (which is broken in SAS/C
 * 6.51 whenever both the month and the day require two digits.)
 */
#ifndef __MYDATE__
#define __MYDATE__ __AMIGADATE__
#endif

#define VERSION  "1.2"
char const VER[] = "$VER: Image2'C' "VERSION" "__MYDATE__;

BOOL AddINFO = TRUE;
BOOL AddPENS = TRUE;
BOOL AddDATA = TRUE;
BOOL AddRGB4 = FALSE;
BOOL AddIMG  = TRUE;
BOOL UseIFDEFs = FALSE;
BOOL UseCHIP = TRUE;
char *ILBMFILE = NULL;
char *SYMPREFIX = NULL;

struct IFFHandle *OpenFileAsIFF( char *filename ) {

  struct IFFHandle *iff;

  if( iff = AllocIFF() ) {
    if( iff->iff_Stream = (ULONG)Open(filename,MODE_OLDFILE) ) { /* open the file stream */
      InitIFFasDOS( iff );                                       /* initialize this as a DOS stream */
      if( OpenIFF( iff, IFFF_READ ) == 0 )                       /* now open it as an IFF */
	return iff;                                              /* and return read-to-go IFF handle */
      else
	Close( iff->iff_Stream );                                /* not an IFF file; close file */
    } else
      fprintf(stderr,"File unavailable (%s)!\n",filename);
    FreeIFF( iff );                                              /* free the iff handle */
  } else
    fprintf(stderr,"Out of memory opening (%s)!\n",filename);
  return NULL;                                                   /* return failure */
} /* OpenFileAsIFF() */



#define ID_ILBM  MAKE_ID('I','L','B','M')
#define ID_BMHD  MAKE_ID('B','M','H','D')
#define ID_CMAP  MAKE_ID('C','M','A','P')
#define ID_BODY  MAKE_ID('B','O','D','Y')
#define ID_AUTH  MAKE_ID('A','U','T','H')
#define ID_CPRT  MAKE_ID('(','c',')',' ')
#define ID_ANNO  MAKE_ID('A','N','N','O')
#define ID_FVER  MAKE_ID('F','V','E','R')


#define mskHasMask 1      /* the only mask that REALLY needs handling */
#define ByteRun1   1      /* the only compression we understand */
typedef UBYTE Masking;
typedef UBYTE Compression;
struct BitMapHeader {
  UWORD       w, h;
  WORD        x, y;
  UBYTE       nPlanes;
  Masking     masking;
  Compression compression;
  UBYTE       reserved1;
  UWORD       transparentColor;
  UBYTE       xAspect, yAspect;
  WORD        pageWidth, pageHeight;
};



/* The ByteToWordStream() function, along with a limited set of global variables,
 * permits us to produce really lovely, and well-formatted output.
 *
 * OnNewLine is externally set to 1 whenever we have finished with a scanline so
 * that the next time we call ByteToWordStream, we start nicely on a new line.
 * If you never use OnNewLine, then all data is merely dumped one word after
 * another.  NO FUNCTIONALITY IS LOST, it just won't look nice.  Your compiler
 * doesn't care.  Lines are ALWAYS limited to 11 words per line.
 *
 * LineHeader, if not set to a "" string, is printed before a new line is output,
 * so we can print the nice "/× Plane 2 ×/" items before the new plane actually
 * begins, but still give this function the chance to clean up the previous line
 * by adding a comma and newline to it, etc.
 * If you never use LineHeader, you will simply be missing the human-readable
 * markers for the bit planes.  No biggie.  Again, your compiler couldn't care
 * less.
 */
#define WORDS_PER_LINE 11
UBYTE OnNewLine = 0;
char LineHeader[64] = "";
void ByteToWordStream( char c ) {

  static char prev;
  static UBYTE odd=0;
  static UBYTE needComma=0;
  static UBYTE onLine=0;

  if( odd ) {
    odd = 0;
    if( needComma )   /* prevents leading comma AND unnecessary trailing comma */
      printf(",");
    else
      needComma = 1;
    if( (onLine == WORDS_PER_LINE) || OnNewLine ) {
      printf("\n");
      onLine = 0;
      OnNewLine = 0;
    }
    if( *LineHeader ) {
      printf("%s",LineHeader);
      *LineHeader = '\0';
    }
    if( onLine == 0 )
      printf("  ");
    
    printf("0x%02x%02x",prev,c);
    onLine++;
  } else
    odd = 1;
  prev = c;
} /* ByteToWordStream() */


/* These are all the properties in the IFF FORM ILBM that we are interested in.
 * We use a PropChunk() in conjunction with FindProp() in our main() function to
 * locate these and then obtain a pointer to their data.  If a pointer is NULL,
 * then no such property exists in the IFF FORM ILBM.
 */
struct StoredProperty *auth_prop,*cprt_prop,*anno_prop,*fver_prop;


/* Here is our nifty routine that scans the ILBM and creates nice 'C' code!
 * Here is how it works:  Most common ILBMs are stored in this way:
 *
 *       (Scanline 1, Plane 1)(mask)(Scanline 1, Plane 2)(mask)(Scanline 1, Plane 3)(mask)
 *       (Scanline 2, Plane 1)(mask)(Scanline 2, Plane 2)(mask)(Scanline 2, Plane 3)(mask)
 *       (Scanline 3, Plane 1)(mask)(Scanline 3, Plane 2)(mask)(Scanline 3, Plane 3)(mask)
 *       (Scanline 4, Plane 1)(mask)(Scanline 4, Plane 2)(mask)(Scanline 4, Plane 3)(mask)
 *       (Scanline 5, Plane 1)(mask)(Scanline 5, Plane 2)(mask)(Scanline 5, Plane 3)(mask)
 *
 * In order to extract only Plane 1 information, one scanline at a time,
 * we'd have to skip information in the file, i.e. read (Scanline 1, Plane 1)
 * and then skip (Scanline 1, Plane 2) and (Scanline 1, Plane 3)
 *    This, in fact, is what we do.  This process is quite fast, especially
 * with small images, and allows us to work without additional image buffers,
 * which is something nice, too.
 *    Once we have Plane 1 extracted, we start from the beginning again and
 * now we skip (Scanline 1, Plane 1), process (Scanline 1, Plane 2) and again
 * skip (Scanline 1, Plane 3).  We continue once again through the whole file,
 * extracting all scanlines for the 2nd plane.
 *    And the 3rd plane is handled the same way.  Once we have processed all
 * bitplanes, we're done!
 *    All this is handled with 3 nested while-loops.
 */
void CreateSource(struct IFFHandle *iff,
		  struct BitMapHeader *bmhd,
		  UBYTE *cmap,
		  struct ContextNode *body_context,
		  char *Filename,
		  char *ID ) {

  ULONG n;
  UWORD ColorReg;
  UBYTE *colors;
  ULONG bodysize;
  char *bodybuffer;
  char *iffInfo;
  BOOL Mask = bmhd->masking;


  printf("/* Source created by Image2'C' "VERSION"\n"
	 " * Copyright \© 1994,1995 Udo Schuermann\n"
	 " * All rights reserved\n"
	 " *\n");
  printf(" * · Inputfile:  \"%s\"\n",
	 Filename);
  if( AddDATA && !UseCHIP )
    printf(" * · Image data is not stored in Chip RAM\n");
  if( UseIFDEFs )
    printf(" * · #ifdef/#endif pairs permit selective activation of sections\n");
  printf(" * · Symbol prefix = \"%s\"\n",SYMPREFIX);
  printf(" *\n");

  if( fver_prop )
    if( iffInfo = (UBYTE *)fver_prop->sp_Data )
      printf(" * Version:   %s=n",iffInfo);
  if( auth_prop )
    if( iffInfo = (UBYTE *)auth_prop->sp_Data )
      printf(" * Author:    %s\n",iffInfo);
  if( cprt_prop )
    if( iffInfo = (UBYTE *)cprt_prop->sp_Data )
      printf(" * Copyright: %s\n",iffInfo);
  if( anno_prop )
    if( iffInfo = (UBYTE *)anno_prop->sp_Data )
      printf(" * %s\n",iffInfo);

  printf(" */\n\n");


  if( AddIMG ) {
    AddINFO = TRUE;  /* we MUST have this part */
    AddDATA = TRUE;  /* same with this one! */
    if( UseIFDEFs ) {
      printf("#ifdef I2C_IMAGE_IMG\n");
      printf("/* make sure we have all components for the (struct Image) stuff */\n");
      printf("#ifndef I2C_IMAGE_INFO\n");
      printf("#define I2C_IMAGE_INFO\n");
      printf("#endif\n");
      printf("#ifndef I2C_IMAGE_DATA\n");
      printf("#define I2C_IMAGE_DATA\n");
      printf("#endif\n");
      printf("#endif\n\n");
    }
  }


  if( AddINFO ) {
    if( UseIFDEFs )
      printf("#ifdef I2C_IMAGE_INFO\n");
    printf("/* Image information */\n");
    printf("#define %sImageWide   %d	/* pixels */\n",ID,bmhd->w);
    printf("#define %sImageHigh   %d	/* lines */\n",ID,bmhd->h);
    printf("#define %sImageDeep   %d	/* bit planes */\n",ID,bmhd->nPlanes);
    printf("#define %sImageColors %ld	/* planes^2 */\n",ID,1L<<bmhd->nPlanes);
    if( UseIFDEFs )
      printf("#endif\n");
  }

  
  if( AddPENS ) {
    if( UseIFDEFs )
      printf("\n#ifdef I2C_IMAGE_PENS");
    printf("\n/* Register color table (32 bit RGB register values)\n"
	   " * Leading these is a WORD with total count and a word\n"
	   " * with the first color to be obtained.  We'll start\n"
	   " * with the first color there (0)\n"
	   " */\n");
    printf("ULONG %sColorPENS[] = {\n",ID);
    n = 1L<<bmhd->nPlanes;
    printf("  (%dL<<16)+0,\n",n);
    colors = cmap;
    while( n-- ) {
      printf("  0x%02x%02x%02x%02x, 0x%02x%02x%02x%02x, 0x%02x%02x%02x%02x",
	     *colors,*colors,*colors,*colors,
	     *(colors+1),*(colors+1),*(colors+1),*(colors+1),
	     *(colors+2),*(colors+2),*(colors+2),*(colors+2));
      colors += 3;
      printf(",\n");
    } /* while */
    printf("  0\n");  /* is this one really necessary? */
    printf("}; /* %sColorPENS[] */\n",ID);
    if( UseIFDEFs )
      printf("#endif\n");
  }


  if( AddRGB4 ) {
    if( UseIFDEFs )
      printf("\n#ifdef I2C_IMAGE_RGB4");
    printf("\n/* Register color table (4-bit RGB register values):\n"
	   " * One packed register value for each `ImageColors`\n"
	   " * This table is compatible with the LoadRGB4() function\n"
	   " * BUT IS ACCURATE ONLY TO 4 BITS (I.E. A 12-BIT PALETTE)\n"
	   " */\n");
    printf("UWORD %sColorRGB4[] = {\n",ID);
    n = 1L<<bmhd->nPlanes;
    colors = cmap;
    while( n-- ) {
      ColorReg = (((UWORD)(*colors) & 0x00f0) << 4) | ((UWORD)(*(colors+1))) & 0x00f0 | (((UWORD)(*(colors+2))) &0x00f0) >> 4;
      printf("  0x%03x",ColorReg);
      colors += 3;
      if( n )
	printf(",\n");
      else
	printf("\n");
    } /* while */
    printf("}; /* %sColorRGB4[] */\n",ID);
    if( UseIFDEFs )
      printf("#endif\n");
  }


  if( AddDATA )
    if( bodybuffer = malloc(bodysize=body_context->cn_Size) ) {
      if( (bodysize = ReadChunkBytes( iff, bodybuffer, body_context->cn_Size )) == body_context->cn_Size ) {
	char *p;
	UBYTE n;
	UWORD Wide = ((bmhd->w + 15) >> 4) * 2;          /* actual width of a scanline in bytes */
	UWORD Plane;                                     /* Bitplane being output to the 'C' file */
	UWORD curPlane;                                  /* Bitplane being scanned out of the IFF file */
	UWORD curLine;                                   /* Scanline being scanned out of the IFF file */
	UWORD curWide;                                   /* What's been output from the scanline */
	
	if( UseIFDEFs )
	  printf("\n#ifdef I2C_IMAGE_DATA");
	printf("\n/* Image data,%s one scanline at a time */\n",((bmhd->nPlanes > 1)?" plane-by-plane, and":""));
	printf("UWORD %s%sImageData[] = {\n",(UseCHIP?"__chip ":""),ID);
	
	Plane = 1;
	while( Plane <= bmhd->nPlanes ) {
	  
	  if( bmhd->nPlanes > 1 )
	    sprintf(LineHeader,"	/* Plane %d */\n",Plane);
	  
	  p = bodybuffer;                                /* point at the beginning of the buffer */
	  curPlane = 1;
	  curLine = bmhd->h;
	  while( curLine ) {
	    
	    if( bmhd->compression == 1 ) {
	      curWide = Wide;
	      while( curWide ) {
		n = *p++;                                  /* get a character from the buffer */
		if( (n >= 0) && (n <= 0x7f) ) {            /* this is a 'copy next n bytes literally' code? */
		  n++;
		  curWide -= n;
		  if( Plane == curPlane ) {
		    while( n-- )
		      ByteToWordStream(*p++);
		  } else
		    p += n;
		} else
		  if( n != -128 ) {                        /* this is a 'duplicate next byte n times' code? */
		    char c = *p++;
		    n = 1 - n;
		    curWide -= n;
		    if( Plane == curPlane ) {
		      while( n-- )
			ByteToWordStream(c);
		    }
		  }
	      } /* while */	
	      
	      /* if we have a standard mask, we'll just skip and ignore it.  Tough luck, mate! */
	      if( Mask == mskHasMask ) {
		curWide = Wide;
		while( curWide ) {
		  n = *p++;                                  /* get a character from the buffer */
		  if( (n >= 0) && (n <= 0x7f) ) {            /* this is a 'copy next n bytes literally' code? */
		    n++;
		    curWide -= n;
		    while( n-- )
		      p++;
		  } else
		    if( n != -128 ) {                        /* this is a 'duplicate next byte n times' code? */
		      p++;
		      n = 1 - n;
		      curWide -= n;
		    }
		} /* while */	
	      }
	    } else {
	      /* UNCOMPRESSED; the same code structure would work as we used above, but we've
	       * optimized this a bit to avoid excessive checking of (Plane==curPlane)...
	       */
	      curWide = Wide;
	      if( Plane == curPlane ) {
		while( curWide-- )
		  ByteToWordStream(*p++);
	      } else
		p += curWide;
	      
	      /* if we have a standard mask, we'll just skip and ignore it.  Tough luck, mate! */
	      if( Mask == mskHasMask )
		p += curWide;
	    }
	    
	    if( curPlane == bmhd->nPlanes ) {            /* reached last plane info for this scanline? */
	      curPlane = 1;
	      curLine--;
	      OnNewLine = 1;
	    } else
	      curPlane++;
	    
	  } /* while */
	  Plane++;
	  
	} /* while */
	printf("\n}; /* %sImageData[] */\n",ID);
	if( UseIFDEFs )
	  printf("#endif\n");
	
	if( AddIMG ) {
	  if( UseIFDEFs )
	    printf("\n#ifdef I2C_IMAGE_IMG");
	  printf("\nstruct Image %sImage = {0,0,%sImageWide,%sImageHigh,%sImageDeep,%sImageData,0x%02x,0,NULL};\n",
		 ID,ID,ID,ID,ID,(1<<bmhd->nPlanes)-1);
	  if( UseIFDEFs )
	    printf("#endif\n");
	}
      } else
	fprintf(stderr,"Read only %ld bytes instead of %ld from BODY chunk of file (%s)\n",bodysize,body_context->cn_Size,ILBMFILE);
      free( bodybuffer );
    } else
      fprintf(stderr,"No memory to load %ld bytes from BODY chunk of file (%s)\n",body_context->cn_Size,ILBMFILE);

} /* CreateSource() */


#ifdef DEBUG
#define MASKING(n)  (n==0?"None":(n==1?"Mask":(n==2?"Transparent":(n==3?"Lasso":"<unknown>"))))
#define COMPRESS(n) (n==0?"None":(n==1?"ByteRun1":"<unknown>"))
#endif

int main( int argc, char *argv[] ) {

  struct IFFHandle *IFF;
  struct StoredProperty *bmhd_prop,*cmap_prop;
  struct ContextNode *body_context;
  int argn;
  BOOL badargs = FALSE;

  for( argn=1; argn<argc; argn++ ) {
    if( strnicmp("ILBMFILE",argv[argn],8) == 0 ) {
      if( argv[argn][8] == '=' )
	ILBMFILE = &argv[argn][9];
      else {
	argn++;
	if( argn < argc )
	  ILBMFILE = argv[argn];
	else {
	  fprintf(stderr,"No argument for ILBMFILE key\n");
	  badargs = TRUE;
	}
      }
    } else
    if( strnicmp("SYMPREFIX",argv[argn],9) == 0 ) {
      if( argv[argn][9] == '=' )
	SYMPREFIX = &argv[argn][10];
      else {
	argn++;
	if( argn < argc )
	  SYMPREFIX = argv[argn];
	else {
	  fprintf(stderr,"No argument for SYMPREFIX key\n");
	  badargs = TRUE;
	}
      }
    } else
    if( stricmp("NOINFO",argv[argn]) == 0 ) {
      AddINFO = FALSE;
    } else
    if( stricmp("NOPENS",argv[argn]) == 0 ) {
      AddPENS = FALSE;
    } else
    if( stricmp("NODATA",argv[argn]) == 0 ) {
      AddDATA = FALSE;
    } else
    if( stricmp("NOIMAGESTRUCT",argv[argn]) == 0 ) {
      AddIMG = FALSE;
    } else
    if( stricmp("NOIMG",argv[argn]) == 0 ) {
      AddIMG = FALSE;
    } else
    if( stricmp("ADDRGB4",argv[argn]) == 0 ) {
      AddRGB4 = TRUE;
    } else
    if( stricmp("USEIFDEFS",argv[argn]) == 0 ) {
      UseIFDEFs = TRUE;
    } else
    if( stricmp("NOCHIP",argv[argn]) == 0 ) {
      UseCHIP = FALSE;
    } else {
      if( ILBMFILE )
	if( SYMPREFIX ) {
	  fprintf(stderr,"Too many arguments; don't know what do to with \"%s\"\n",argv[argn]);
	  badargs = TRUE;
	} else
	  SYMPREFIX = argv[argn];
      else
	ILBMFILE = argv[argn];
    }
  }
  if( (ILBMFILE == NULL) || (SYMPREFIX == NULL) || badargs ) {
    if( badargs )
      fprintf(stderr,"\n");
    fprintf(stderr,"Image2'C' "VERSION"\n"
	    "Copyright © 1994,1995 Udo Schuermann\n"
	    "All rights reserved\n\n"
	    "Template:  ILBMFILE/A,SYMPREFIX/A,NOINFO/S,NOPENS/S,NODATA/S,NOIMG=NOIMAGESTRUCT/S,ADDRGB4/S,USEIFDEFS/S,NOCHIP/S\n"
	    "   ILBMFILE/A		An IFF ILBM (picture) file\n"
	    "   SYMPREFIX/A		Prefix for symbols (may be \"\")\n"
	    "   NOINFO/S		Suppress image size/depth information\n"
	    "   NOPENS/S		Suppress RGB32 pens\n"
	    "   NODATA/S		Suppress image data\n"
	    "   NOIMG=NOIMAGESTRUCT/S	Suppress \"struct Image...\"\n"
	    "   ADDRGB4/S		Add old 4-bit RGB color table\n"
	    "   USEIFDEFS/S		Enclose sections with #ifdef/#endif pairs\n"
	    "   NOCHIP/S		Omit the __chip attribute on structs\n");
    exit(10);
  }

  if( IFF = OpenFileAsIFF( ILBMFILE ) ) {                         /* open file for IFF parsing */
    struct BitMapHeader   *bmhd;
    UBYTE                 *cmap;
    int                   error;

    PropChunk( IFF, ID_ILBM, ID_AUTH );                          /* collect AUTH (if any) */
    PropChunk( IFF, ID_ILBM, ID_CPRT );                          /* collect (c)  (if any) */
    PropChunk( IFF, ID_ILBM, ID_ANNO );                          /* collect ANNO (if any) */
    PropChunk( IFF, ID_ILBM, ID_FVER );                          /* collect FVER (if any) */

    if( error = PropChunk( IFF, ID_ILBM, ID_BMHD ) )             /* collect BMHD */
      fprintf(stderr,"Error %ld with PropChunk(ILBM,BMHD) in file (%s)\n",error,ILBMFILE);

    if( error = PropChunk( IFF, ID_ILBM, ID_CMAP ) )             /* collect CMAP */
      fprintf(stderr,"Error %ld with PropChunk(ILBM,CMAP) in file (%s)\n",error,ILBMFILE);

    if( error = StopChunk( IFF, ID_ILBM, ID_BODY ) )             /* stop when we reach BODY */
      fprintf(stderr,"Error %ld with StopChunk(ILBM,BODY) in file (%s)\n",error,ILBMFILE);

    if( ParseIFF( IFF, IFFPARSE_SCAN ) == 0 ) {                  /* Let's BOOGIE!!! (we stop at BODY) */
      auth_prop = FindProp( IFF, ID_ILBM, ID_AUTH );             /* get pointer to AUTH, if any */
      cprt_prop = FindProp( IFF, ID_ILBM, ID_CPRT );
      anno_prop = FindProp( IFF, ID_ILBM, ID_ANNO );
      fver_prop = FindProp( IFF, ID_ILBM, ID_FVER );
      if( bmhd_prop = FindProp( IFF, ID_ILBM, ID_BMHD ) ) {      /* get pointer to BMHD; required! */
	bmhd = (struct BitMapHeader *)bmhd_prop->sp_Data;
	if( cmap_prop = FindProp( IFF, ID_ILBM, ID_CMAP ) ) {    /* get pointer to CMAP; required! */
	  cmap = (UBYTE *)cmap_prop->sp_Data;
	  if( body_context = CurrentChunk( IFF ) ) {             /* where we stopped is the BODY chunk */
#ifdef DEBUG
	    fprintf(stderr,"BMHD.width       = %4d\n",bmhd->w);
	    fprintf(stderr,"BMHD.height      = %4d\n",bmhd->h);
	    fprintf(stderr,"BMHD.depth       = %4d\n",bmhd->nPlanes);
	    fprintf(stderr,"BMHD.masking     = %s\n",MASKING(bmhd->masking));
	    fprintf(stderr,"BMHD.compression = %s\n",COMPRESS(bmhd->compression));
	    fprintf(stderr,"BMHD.transpColor = %4d\n",bmhd->transparentColor);
	    fprintf(stderr,"BMHD.Aspect (x:y)= %d:%d\n",bmhd->xAspect,bmhd->yAspect);
	    fprintf(stderr,"\n");
	    
	    fprintf(stderr,"CMAP.SIZE        = %ld\n",cmap_prop->sp_Size);
	    fprintf(stderr,"\n");
	    
	    fprintf(stderr,"BODY.SIZE        = %ld\n",body_context->cn_Size);
#endif
	    /* make sure we can handle the masking and compression that is used */
	    if(((bmhd->compression == 0) || (bmhd->compression == 1)) &&
	       ((bmhd->masking == 0) || (bmhd->masking == 1) || (bmhd->masking == 2) ||
		(bmhd->masking == 3)))
	      CreateSource( IFF, bmhd, cmap, body_context, ILBMFILE, SYMPREFIX );
	    else {
	      /* error messages as to why we can't process this file */
	      printf("Sorry, I do not know how to handle images (%s) with compression code %d!\n",
		     ILBMFILE,bmhd->compression);
	    }
	  } else
	    fprintf(stderr,"Missing BODY chunk in file (%s)\n",ILBMFILE);
	} else
	  fprintf(stderr,"Missing CMAP chunk in file (%s)\n",ILBMFILE);
      } else
	fprintf(stderr,"Missing BMHD chunk in file (%s)\n",ILBMFILE);
    } else
      fprintf(stderr,"File (%s) seems to contain no images\n",ILBMFILE);

    CloseIFF( IFF );                                             /* close iff parsing */
    Close( IFF->iff_Stream );                                    /* close file stream */
    FreeIFF( IFF );                                              /* free associated internal structures */
  } else
    fprintf(stderr,"File (%s) unavailable or not a FORM IFF\n",ILBMFILE);
} /* main() */
