/*
 *	read a GIF file. decode and stuff into raster array and color maps.
 *
 *	this was adopted from PBMplus.
 */

static char *sccsid = "@(#) readgif.c 1.1 91/6/3 rosenkra\0\0                 ";

#include <stdio.h>
#include <osbind.h>
#include "mgif.h"


#ifdef LOCAL
#undef LOCAL
#endif
#ifdef GLOBAL
#undef GLOBAL
#endif
#define LOCAL		/*static*/
#define GLOBAL
#define reg_t		register

#define ENDFILE(f)	_Eof != 0	/* to track EOF on input file */


/*
 *	globals for GIF decode procedure (only needed in this file,
 *	should actually be static)
 */
LOCAL ulong_t	_BitOffset = 0;	/* Bit Offset of next code */
LOCAL int	_XC = 0;	/* Output X and Y coords of current pixel */
LOCAL int	_YC = 0;
LOCAL int	_HEIGHT;	/* image size */
LOCAL int	_WIDTH;
LOCAL int	_Pass = 0;	/* Used by output routine if interlaced pic */
LOCAL int	_OutCount = 0;	/* Decompressor output 'stack count' */
LOCAL int	_Interlace;	/* flag for interlaced image */
LOCAL int	_CodeSize;	/* Code size, read from GIF header */
LOCAL int	_InitCodeSize;	/* Start code size, used during Clear */
LOCAL int	_Code;		/* Value returned by read_code */
LOCAL int	_MaxCode;	/* limit value for current code size */
LOCAL int	_ClearCode;	/* GIF clear code */
LOCAL int	_EOFCode;	/* GIF end-of-information code */
LOCAL int	_CurCode;	/* Decompressor variables */
LOCAL int	_OldCode;
LOCAL int	_InCode;
LOCAL int	_FirstFree;	/* First free code, gen'd per GIF spec */
LOCAL int	_FreeCode;	/* Decompr, next free slot in hash table */
LOCAL int	_FinChar;	/* Decompr variable */
LOCAL int	_BitMask;	/* AND mask for data size */
LOCAL int	_ReadMask;	/* Code AND mask for cur code size */
LOCAL int	_Prefix[HASHSIZ];/* hash table used by the decompr */
LOCAL int	_Suffix[HASHSIZ];
LOCAL int	_OutCode[OUTSIZ];/* output array used by the decompr */
LOCAL int	_BitsPerPixel;	/* image attributes */
LOCAL int	_ColorMapSize;
LOCAL int	_ImageNum = 0;	/* if multi-image file (not used) */
LOCAL int	_Eof = 0;	/* EOF on input flag (_GETC) */


/*
 *	local functions
 */
LOCAL int	_ReadRaster ();
LOCAL int	_ReadCode ();
LOCAL int	_AddPixel ();
LOCAL void	_InstCMap ();
LOCAL int	_ScanSD ();
LOCAL void	_SkipEB ();
LOCAL int	_ScanID ();
LOCAL void	_ScanCM ();
LOCAL int	_ScanMAGIC ();
LOCAL int	_GetKey ();
LOCAL int	_GETC ();



/*------------------------------*/
/*	ReadGIF			*/
/*------------------------------*/
GLOBAL int ReadGIF (fname, codedgif, raster, scrninf, id, colormap, opt)
char	       *fname;		/* file name with .GIF */
uchar_t	       *codedgif;	/* place to put raw raster data, coded */
uchar_t	       *raster;		/* place to put raster */
screen_t       *scrninf;	/* image info struct */
image_t	       *id;		/* image id struct */
uchar_t		colormap[][3];	/* color map */
int		opt;		/* SILENT, INQUIRE, VERBOSE, NORMAL */
{

/*
 *	read a GIF87a image from open file infile into raster array.
 *	the array will contain index into color table. caller supplies
 *	all needed space (raster array, headers, color map, etc). colormap
 *	will contain either global or local color map, depending on image.
 *
 *	The following illustrates the general file layout of .GIF files:
 *
 *	+-----------------------+
 *	| +-------------------+ |
 *	| |   GIF Signature   | |	GIF87a			(required)
 *	| +-------------------+ |
 *	| +-------------------+ |
 *	| | Screen Descriptor | |	7 bytes, ends with 00	(required)
 *	| +-------------------+ |
 *	| +-------------------+ |
 *	| | Global Color Map  | |	3*2^bits bytes		(optional but
 *	| +-------------------+ |				 usual)
 *	| +-------------------+ |
 *	| | Extension Block   | |	!			(optional)
 *	| +-------------------+ |
 *	. . .		    . . .
 *	| +-------------------+ |
 *	| |  Image Descriptor | |	,			(required)
 *	| +-------------------+ |
 *	| +-------------------+ |
 *	| |  Local Color Map  | |				(optional)
 *	| +-------------------+ |
 *	| +-------------------+ |
 *	| |    Raster Data    | |				(required)
 *	| +-------------------+ |
 *	. . .		    . . .   
 *	|-    GIF Terminator   -|				(required)
 *	+-----------------------+
 */

	static int	firsttime = 1;

	uchar_t		lcm[MAPSIZ][3];
	uchar_t		gcm[MAPSIZ][3];
	int		infile;
	reg_t long	ii;
	int		flag;



	/*
	 *   open file...
	 */
	if (opt != SILENT)
	{
		printf ("   \n");
		printf ("\nEnter ReadGIF\n\n");
		printf ("Open file:                           %s\n", fname);
	}
	if ((infile = openb (fname, 0)) < 0)
	{
		return (EGIFFILE);
	}



	/*
	 *   get ready for next image by clearing variables, tables
	 */
	_BitOffset    = 0;
	_XC           = 0;
	_YC           = 0;
	_Pass         = 0;
	_OutCount     = 0;
	_CodeSize     = 0;
	_InitCodeSize = 0;
	_Code         = 0;
	_MaxCode      = 0;
	_ClearCode    = 0;
	_EOFCode      = 0;
	_CurCode      = 0;
	_OldCode      = 0;
	_InCode       = 0;
	_FirstFree    = 0;
	_FreeCode     = 0;
	_FinChar      = 0;
	_BitMask      = 0;
	_ReadMask     = 0;
	_Eof          = 0;

	for (ii = 0; ii < HASHSIZ; ii++)
	{
		_Prefix[ii] = 0;
		_Suffix[ii] = 0;
	}

	for (ii = 0; ii < OUTSIZ; ii++)
		_OutCode[ii] = 0;

	if (firsttime)
		firsttime = 0;
	else
	{
		/* these take a while to do */
		if (opt != SILENT)
			printf ("\nResetting tables\n");

		for (ii = 0; ii < MAXRAW; ii++)
			codedgif[ii] = 0;

		for (ii = 0; ii < MAXIMG; ii++)
			raster[ii] = 0;

	}


	/*
	 *   make sure it is a gif file (file header is this...)
	 */
	if (opt != SILENT)
		printf ("\nRead MAGIC\n");
	if (!_ScanMAGIC (infile, "GIF87a", opt))
	{
		close (infile);
		return (EGIFMAGIC);
	}



	/*
	 *   read screen descriptor...
	 */
	if (opt != SILENT)
		printf ("\nRead screen descriptor\n");
	if (!_ScanSD (infile, scrninf, opt))
	{
		close (infile);
		return (EGIFSDESC);
	}
	if (opt != SILENT)
	{
	  printf ("     Screen width (s_dx)       = %d\n", (int) (scrninf->s_dx));
	  printf ("     Screen height (s_dy)      = %d\n", (int) (scrninf->s_dy));
	  printf ("     Global map? (s_gcm)       = %d\n", (int) (scrninf->s_gcm));
	  printf ("     Color resolution (s_cr)   = %d\n", (int) (scrninf->s_cr));
	  printf ("     Bits/pixel (s_bits)       = %d\n", (int) (scrninf->s_bits));
	  printf ("     Num colors (s_colors)     = %d\n", (int) (scrninf->s_colors));
	  printf ("     Background color (s_bgnd) = %d\n", (int) (scrninf->s_bgnd));
	}



	/*
	 *   read global color map if we have one...
	 */
	if (scrninf->s_gcm)
	{
		if (opt != SILENT)
			printf ("\nRead global color map\n");
		_ScanCM (infile, scrninf->s_colors, (char *) gcm, opt);
	}
	else
	{
		if (opt != SILENT)
			printf ("\nNo global color map\n");
	}


	/*
	 *   read image descriptor
	 */
	_ImageNum++;
	if (opt != SILENT)
		printf ("\nRead image descriptor, image: %d\n", _ImageNum);

	flag = _ScanID (infile, id, opt);

	if (flag == 0)
	{
		return (EGIFEOF);
	}
	if (flag == 1)
		return (EGIFIDBAD);

	if (opt != SILENT)
	{
	  printf ("     Image left (i_x)         = %d\n", (int) (id->i_x));
	  printf ("     Image top (i_y)          = %d\n", (int) (id->i_y));
	  printf ("     Image width (i_dx)       = %d\n", (int) (id->i_dx));
	  printf ("     Image height (i_dy)      = %d\n", (int) (id->i_dy));
	  printf ("     Use local map? (i_gcm)   = %d\n", (int) (id->i_gcm));
	  printf ("     Interlaced? (i_intlace)  = %d\n", (int) (id->i_intlace));
	  printf ("     Bits per pixel (i_bits)  = %d\n", (int) (id->i_bits));
	  printf ("     Number colors (i_colors) = %d\n", (int) (id->i_colors));
	  printf ("     (If no local color map, use screen bits and colors)\n");
	}


	/*
	 *   read local color map, if there
	 */
	if (id->i_gcm)
	{
		if (opt != SILENT)
			printf ("\nRead local color map\n");
		_ScanCM (infile, id->i_colors, (char *) lcm, opt);
		_InstCMap (id->i_colors, (uchar_t *) lcm, colormap, opt);
	}
	else
	{
		if (opt != SILENT)
			printf ("\nUse global color map\n");
		_InstCMap (scrninf->s_colors, (uchar_t *) gcm, colormap, opt);

		/*
		 *   make sure to reset these from global info...
		 */
		id->i_colors = scrninf->s_colors;
		id->i_bits   = scrninf->s_bits;
	}

	_BitsPerPixel = id->i_bits;
	_ColorMapSize = 1 << _BitsPerPixel;
	_BitMask      = _ColorMapSize - 1;
	_WIDTH        = id->i_dx;
	_HEIGHT       = id->i_dy;
	_Interlace    = id->i_intlace;

	if (opt != SILENT)
	{
		printf ("     BitsPerPixel = %d\n", _BitsPerPixel);
		printf ("     ColorMapSize = %d\n", _ColorMapSize);
		printf ("     BitMask      = %04x\n", _BitMask);
		printf ("     WIDTH        = %d\n", _WIDTH);
		printf ("     HEIGHT       = %d\n", _HEIGHT);
		printf ("     Interlace    = %d\n", _Interlace);
	}



	/*
	 *   check size vs internal buffer...
	 */
	if (((long) _WIDTH * (long) _HEIGHT) > MAXIMG)
	{
		return (EGIFBIG);
	}



	/*
	 *   if just an inquiry, quit now...
	 */
	if (opt == INQUIRE)
		return (EGIFOK);



	/*
	 *   read raster data
	 */
	if (_ReadRaster (infile, codedgif, scrninf, raster, opt))
	{
		return (EGIFRAST);
	}

	/* at this point, Raster[] contains colormap indices at each pixel */

	return (EGIFOK);
}




/*------------------------------*/
/*	_ReadRaster		*/
/*------------------------------*/
LOCAL int _ReadRaster (infile, codedgif, scrninf, raster, opt)
int		infile;
uchar_t	       *codedgif;
screen_t       *scrninf;
uchar_t	       *raster;
int		opt;
{

/* externals: _CodeSize,_Eof,_ClearCode,_EOFCode,_FreeCode,_FirstFree,
              _InitCodeSize,_MaxCode,_ReadMask,... */

/*
 *	Decode a raster image
 */

	uchar_t	       *pcoded;
	uchar_t	       *praster;
	uint_t		ch;
	uint_t		ch1;
	int		i;
	int		nread;




	/*
	 *   Start reading the raster data. First we get the intial code size
	 *   and compute decompressor constant values, based on this code size.
	 */
	if (opt != SILENT)
		printf ("\nRead raster data\n");

	_CodeSize  = _GETC (infile);
	if (ENDFILE (infile))
	{
/*		fprintf (stderr, "_ReadRaster: unexpected EOF\n");*/
		return (1);
	}
	_ClearCode = (1 << _CodeSize);
	_EOFCode   = _ClearCode + 1;
	_FreeCode  = _FirstFree = _ClearCode + 2;



	/*
	 *   The GIF spec has it that the code size is the code size used to
	 *   compute the above values is the code size given in the file, but
	 *   the code size used in compression/decompression is the code size
	 *   given in the file plus one. (thus the ++).
	 */
	_CodeSize++;
	_InitCodeSize = _CodeSize;
	_MaxCode      = (1 << _CodeSize);
	_ReadMask     = _MaxCode - 1;

	if (opt != SILENT)
	{
		printf ("     CodeSize  = %04x\n", _CodeSize);
		printf ("     ClearCode = %04x\n", _ClearCode);
		printf ("     EOFCode   = %04x\n", _EOFCode);
		printf ("     MaxCode   = %04x\n", _MaxCode);
		printf ("     ReadMask  = %04x\n", _ReadMask);
	}



	/*
	 *   Read the raster data. Here we just transpose it from the GIF array
	 *   to the Raster array, turning it from a series of blocks into one
	 *   long data stream, which makes life much easier for _ReadCode().
	 */
	pcoded = codedgif;
	do
	{
		if (_GetKey ())
			return (1);

		ch = (uint_t) _GETC (infile);

		nread = read (infile, pcoded, ch);
		if (nread != ch)
		{
/*			fprintf (stderr, "error reading raster data\n");*/
			return (1);
		}
		pcoded += (long) ch;

		if (((long) pcoded - (long) codedgif) > MAXRAW-255)
		{
/*			fprintf (stderr, "corrupt GIF file (unblock)\n");*/
			return (1);
		}

	} while (ch);



	/*
	 *   Decompress the file, continuing until you see the GIF EOF code.
	 *   One obvious enhancement is to add checking for corrupt files here.
	 */
	if (opt != SILENT)
	{
		printf ("\nDecompressing data\n");
		printf ("     Width            = %d\n", (int) scrninf->s_dx);
		printf ("     Height           = %d\n", (int) scrninf->s_dy);
		printf ("     Bits/pixel       = %d\n", (int) scrninf->s_bits);
		printf ("     Number of colors = %d\n", (int) scrninf->s_colors);
	}

	_Code = _ReadCode (codedgif, opt);
	while (_Code != _EOFCode)
	{

		/*
		 *   Clear code sets everything back to its initial value,
		 *   then reads the immediately subsequent code as
		 *   uncompressed data.
		 */
		if (_Code == _ClearCode)
		{
			_CodeSize = _InitCodeSize;
			_MaxCode  = (1 << _CodeSize);
			_ReadMask = _MaxCode - 1;
			_FreeCode = _FirstFree;
			_Code     = _ReadCode (codedgif, opt);
			_CurCode  = _Code;
			_OldCode  = _Code;
			_FinChar  = _CurCode & _BitMask;

			_AddPixel ((uchar_t) _FinChar, raster, opt);
		}
		else
		{

			/*
			 *   If not a clear code, then must be data: save
			 *   same as _CurCode and _InCode
			 */
			_CurCode = _Code;
			_InCode  = _Code;

			/*
			 *   If greater or equal to _FreeCode, not in
			 *   the hash table yet;
			 *   repeat the last character decoded
			 */
			if (_CurCode >= _FreeCode)
			{
				_CurCode              = _OldCode;
				_OutCode[_OutCount++] = _FinChar;
			}

			/*
			 *   Unless this code is raw data, pursue the chain
			 *   pointed to by _CurCode through the hash table
			 *   to its end; each code in the chain puts its
			 *   associated output code on the output queue.
			 */
			while (_CurCode > _BitMask)
			{
				if (_OutCount > 1024)
				{
/*					fprintf (stderr, "corrupt GIF file (_OutCount)\n");*/
					return (1);
				}
				_OutCode[_OutCount++] = _Suffix[_CurCode];
				_CurCode              = _Prefix[_CurCode];
			}

			/*
			 *   The last code in the chain is treated as raw data
			 */
			_FinChar              = _CurCode & _BitMask;
			_OutCode[_OutCount++] = _FinChar;

			/*
			 *   Now we put the data out to the Output routine.
			 *   It's been stacked LIFO, so deal with it that way
			 */
			for (i = _OutCount - 1; i >= 0; i--)
				_AddPixel ((uchar_t) _OutCode[i], raster, opt);
			_OutCount = 0;

			/*
			 *   Build the hash table on-the-fly. No table is
			 *   stored in the file.
			 */
			_Prefix[_FreeCode] = _OldCode;
			_Suffix[_FreeCode] = _FinChar;
			_OldCode           = _InCode;

			/*
			 *   Point to the next slot in the table.  If we
			 *   exceed the current _MaxCode value, increment
			 *   the code size unless it's already 12.  If it
			 *   is, do nothing: the next code decompressed
			 *   better be CLEAR
			 */
			_FreeCode++;
			if (_FreeCode >= _MaxCode)
			{
				if (_CodeSize < 12)
				{
					_CodeSize++;
					_MaxCode *= 2;
					_ReadMask = (1 << _CodeSize) - 1;
				}
			}
		}
		_Code = _ReadCode (codedgif, opt);
	}
	return (0);
}




/*------------------------------*/
/*	_ReadCode		*/
/*------------------------------*/
LOCAL int _ReadCode (codedgif, opt)
uchar_t	       *codedgif;
int		opt;
{

/* externals: _BitOffset,_CodeSize,_ReadMask */

/*
 *	Fetch the next code from the raster data stream.  The codes can be
 *	any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
 *	maintain our location in the Raster array as a BIT Offset.  We compute
 *	the byte Offset into the raster array by dividing this by 8, pick up
 *	three bytes, compute the bit Offset into our 24-bit chunk, shift to
 *	bring the desired code to the bottom, then mask it off and return it. 
 */

	reg_t ulong_t		rawcode;
	reg_t ulong_t		byteoffset;
	reg_t ulong_t		shft;
	reg_t int		ret;

/*	byteoffset = _BitOffset / 8;*/
	byteoffset = _BitOffset >> 3;

	rawcode = codedgif[byteoffset] + (0x100 * codedgif[byteoffset + 1]);
	if (_CodeSize >= 8)
		rawcode += (0x10000 * codedgif[byteoffset + 2]);

	shft        = _BitOffset % 8;
	rawcode   >>= (shft);
	_BitOffset += _CodeSize;

	ret = (int) (rawcode & (ulong_t) _ReadMask);

	return (ret);
}




/*------------------------------*/
/*	_AddPixel		*/
/*------------------------------*/
LOCAL int _AddPixel (indx, raster, opt)
uchar_t		indx;
uchar_t	       *raster;
int		opt;
{

/* externals: _XC,_YC,_WIDTH,_HEIGHT,_Interlace,_Pass */

	reg_t long	oset;		/* linear ptr into Raster */


	/*
	 *   check for array overflow...
	 */
	oset = ((long) _YC * (long) _WIDTH) + (long) _XC;

	if (opt == VERBOSE && _XC == _WIDTH/2)
		fprintf (stderr, "_AddPixel: _XC,_YC = %d,%d, oset = %ld, indx = %02x\n",
				_XC, _YC, oset, (uint_t) indx);

	if (oset > MAXIMG)
	{
		fprintf (stderr, "_AddPixel: image too large\n");
		exit (1);
	}


	/*
	 *   add to raster array...
	 */
	if (_YC < _HEIGHT)
	{
		raster[oset] = indx;
	}


	/*
	 *   Update the X-coordinate, and if it overflows, update the
	 *   Y-coordinate
	 */
	if (++_XC == _WIDTH)
	{
		_XC = 0;

		/*
		 *   If a non-interlaced picture, just increment _YC to the
		 *   next scan line. If it's interlaced, deal with the
		 *   interlace as described in the GIF spec.  Put the
		 *   decoded scan line out to the screen if we haven't gone
		 *   past the bottom of it
		 */
		if (!_Interlace)
			_YC++;
		else
		{
			switch (_Pass)
			{
			case 0:
				_YC += 8;
				if (_YC >= _HEIGHT)
				{
					_Pass++;
					_YC = 4;
				}
				break;
			case 1:
				_YC += 8;
				if (_YC >= _HEIGHT)
				{
					_Pass++;
					_YC = 2;
				}
				break;
			case 2:
				_YC += 4;
				if (_YC >= _HEIGHT)
				{
					_Pass++;
					_YC = 1;
				}
				break;
			case 3:
				_YC += 2;
				break;
			default:
				fprintf (stderr, "_AddPixel: can't happen\n");
			}
		}
	}
}




/*------------------------------*/
/*	_InstCMap		*/
/*------------------------------*/
LOCAL void _InstCMap (ncolors, cm, map, opt)
int		ncolors;
uchar_t	       *cm;
uchar_t		map[][3];
int		opt;
{

/*
 *	copy cm colormap to map color map for ncolors
 */

	reg_t uchar_t	       *scan;
	reg_t int		i;

	/*
	 *   most all images currently use global map, though this will
	 *   copy whatever cm points to (either local or global) into the
	 *   real map we use...
	 */
	for (scan = cm, i = 0; ncolors > 0; i++, ncolors--)
	{
		map[i][0] = *scan++;
		map[i][1] = *scan++;
		map[i][2] = *scan++;
	}

}




/*------------------------------*/
/*	_ScanSD			*/
/*------------------------------*/
LOCAL int _ScanSD (infile, sd, opt)
int		infile;
screen_t       *sd;
int		opt;
{

/*
 *	read logical screen descriptor (req'd)
 *
 *		bits
 *	 7 6 5 4 3 2 1 0  Byte #
 *	+---------------+
 *	|		|  1
 *	+-Screen Width -+	Raster width in pixels (LSB first)
 *	|		|  2
 *	+---------------+
 *	|		|  3
 *	+-Screen Height-+	Raster height in pixels (LSB first)
 *	|		|  4
 *	+-+-----+-+-----+	M = 1, Global color map follows Descriptor
 *	|M|  cr |0|pixel|  5	cr+1 = # bits of color resolution
 *	+-+-----+-+-----+	pixel+1 = # bits/pixel in image
 *	|   background  |  6	background=Color index of screen background
 *	+---------------+	     (color is defined from the Global color
 *	|0 0 0 0 0 0 0 0|  7	      map or default map if none specified)
 *	+---------------+
 */


	reg_t uchar_t	data;
	reg_t uint_t	idata;



	idata        = (uint_t) _GETC (infile);		/* width */
	sd->s_dx     = idata + ((uint_t) _GETC (infile) << 8);

	idata        = (uint_t) _GETC (infile);		/* height */
	sd->s_dy     = idata + ((uint_t) _GETC (infile) << 8);


	idata        = _GETC (infile);
	if (idata & 8)					/* bit must be 0 */
		return (0);				/* error... */

	sd->s_gcm    = (idata >> 7) & 0x01;		/* global color map?*/
	sd->s_cr     = (idata & 0x70) >> 4;		/* color resolution */
	sd->s_bits   = (idata & 7) + 1;			/* pix size, bits */
	sd->s_colors = 1 << sd->s_bits;			/* num colors */
	sd->s_bgnd   = _GETC (infile);			/* background color */

	idata        = _GETC (infile);
	if (idata != 0)					/* sorted map? */
		return (0);

	return (!0);
}




/*------------------------------*/
/*	_SkipEB			*/
/*------------------------------*/
LOCAL void _SkipEB (infile, opt)
int	infile;
int	opt;
{

/*
 *	skips extension block
 *
 *	 7 6 5 4 3 2 1 0  Byte #
 *	+---------------+
 *	|0 0 1 0 0 0 0 1|  1	   '!' - GIF Extension Block Introducer
 *	+---------------+
 *	| function code |  2	   Extension function code (0 to 255)
 *	+---------------+    ---+
 *	|  byte count	|	|
 *	+---------------+	|
 *	:		:	+-- Repeated as many times as necessary
 *	|func data bytes|	|
 *	:		:	|
 *	+---------------+    ---+
 *	. . .	    . . .
 *	+---------------+
 *	|0 0 0 0 0 0 0 0|	zero byte count (terminates block)
 *	+---------------+
 */

	reg_t uint_t	count;
	char		garbage[256];



	if (opt != SILENT)
		printf ("\nSkip extension block\n");

	_GETC (infile);			/* get function */

	while (count = (uint_t) _GETC (infile))	/* get data */
	{
		if (ENDFILE (infile))
		{
			fprintf (stderr, "_SkipEB: unexpected EOF\n");
			exit (1);
		}

		read (infile, garbage, count);

		if (ENDFILE (infile))
		{
			fprintf (stderr, "_SkipEB: unexpected EOF\n");
			exit (1);
		}
	}
}




/*------------------------------*/
/*	_ScanID			*/
/*------------------------------*/
LOCAL int _ScanID (infile, id, opt)
int		infile;
image_t        *id;
int		opt;
{

/*
 *	read image descriptor (req'd)
 *
 *	      bits
 *	 7 6 5 4 3 2 1 0  Byte #
 *	+---------------+
 *	|0 0 1 0 1 1 0 0|  1	',' - Image separator character
 *	+---------------+
 *	|		|  2	Start of image in pixels from the
 *	+-  Image Left -+	left side of the screen (LSB first)
 *	|		|  3
 *	+---------------+
 *	|		|  4
 *	+-  Image Top  -+	Start of image in pixels from the
 *	|		|  5	top of the screen (LSB first)
 *	+---------------+
 *	|		|  6
 *	+- Image Width -+	Width of the image in pixels (LSB first)
 *	|		|  7
 *	+---------------+
 *	|		|  8
 *	+- Image Height-+	Height of the image in pixels (LSB first)
 *	|		|  9
 *	+-+-+-+-+-+-----+	M=0 - Use global color map, ignore 'pixel'
 *	|M|I|0|0|0|pixel| 10	M=1 - Local color map follows, use 'pixel'
 *	+-+-+-+-+-+-----+	I=0 - Image formatted in Sequential order
 *				I=1 - Image formatted in Interlaced order
 *				pixel+1 - # bits per pixel for this image
 */

	reg_t uchar_t	data;


	/*
	 *   skip extension block
	 */
	do
	{
		data = (uchar_t) _GETC (infile);

		if (ENDFILE (infile))
			return (0);
		if (data == ';')
			return (1);
		if (data == 0x21)
			_SkipEB (infile, opt);

	} while (data != 0x2c);				/* ',' is ID start */

	data       = (uchar_t) _GETC (infile);		/* left coord */
	id->i_x    = data + ((uchar_t) _GETC (infile) << 8);

	data       = (uchar_t) _GETC (infile);		/* top coord */
	id->i_y    = data + ((uchar_t) _GETC (infile) << 8);

	data       = (uchar_t) _GETC (infile);		/* width */
	id->i_dx   = data + ((uchar_t) _GETC (infile) << 8);

	data       = (uchar_t) _GETC (infile);		/* height */
	id->i_dy   = data + ((uchar_t) _GETC (infile) << 8);

	data         = (uchar_t) _GETC (infile);		/* flag: */
	id->i_gcm    = (data >> 7) & 0x01;		/* local color map? */
	id->i_intlace= (data >> 6) & 0x01;		/* interlaced? */
	id->i_bits   = (data & 7) + 1;
	id->i_colors = 1 << id->i_bits;

	return (2);
}




/*------------------------------*/
/*	_ScanCM			*/
/*------------------------------*/
LOCAL void _ScanCM (infile, colors, cm, opt)
int		infile;
int		colors;
char	       *cm;
int		opt;		/* SILENT, INQUIRE, VERBOSE */
{

/*
 *	read a color map (optional)
 *
 *	      bits
 *	 7 6 5 4 3 2 1 0  Byte #
 *	+---------------+
 *	| red intensity |  1	Red value for color index 0
 *	+---------------+
 *	|green intensity|  2	Green value for color index 0
 *	+---------------+
 *	| blue intensity|  3	Blue value for color index 0
 *	+---------------+
 *	| red intensity |  4	Red value for color index 1
 *	+---------------+
 *	|green intensity|  5	Green value for color index 1
 *	+---------------+
 *	| blue intensity|  6	Blue value for color index 1
 *	+---------------+
 *	:		:	(Continues for remaining colors)
 *
 */

	reg_t char	       *scan;
	reg_t int		i;


	if (opt != SILENT)
		printf (stderr, "\nRead color map\n");

	for (scan = cm, i = colors; i > 0; i--, scan += 3)
	{
		*scan =     (char) _GETC (infile);
		*(scan+1) = (char) _GETC (infile);
		*(scan+2) = (char) _GETC (infile);

		if (opt == VERBOSE)
		{
			fprintf (stderr, "addr:     %08lx %08lx %08lx\n",
				(long) (scan),
				(long) (scan+1),
				(long) (scan+2));
			fprintf (stderr, "vals:     %02x %02x %02x\n",
				(uint_t) (*scan),
				(uint_t) (*(scan+1)),
				(uint_t) (*(scan+2)));
		}
	}

	if (opt == VERBOSE)
	{
		printf ("\n     Color map for %d colors:\n\n", colors);
		for (scan = cm, i = colors; i > 0; i--, scan += 3)
			printf ("     %02x %02x %02x\n",
				(uint_t) (*scan),
				(uint_t) (*(scan+1)),
				(uint_t) (*(scan+2)));
		printf ("\n");
	}
}



/*------------------------------*/
/*	_ScanMAGIC		*/
/*------------------------------*/
LOCAL int _ScanMAGIC (infile, parse, opt)
int	infile;
char   *parse;
int	opt;
{

/*
 *	read chars from file "infile" and look for string "parse" from
 *	current file position. return 0 if no match at first mismatch.
 */

	reg_t char  *scan;


	for (scan = parse; *scan; scan++)
	{
		if (_GETC (infile) != (int) *scan)
			return (0);
	}
	return (!0);
}




/*------------------------------*/
/*	_GETC			*/
/*------------------------------*/
LOCAL int _GETC (fd)
int	fd;
{
	reg_t int	ret;
	uchar_t		buf[10];

	ret = read (fd, buf, 1);

	if (ret < 0)
		_Eof = 1;

	return ((int) buf[0]);
}




/*------------------------------*/
/*	_GetKey			*/
/*------------------------------*/
LOCAL int _GetKey ()
{

/*
 *	ckecks for a key and flushes keyboard buffer. same as check_key().
 */

	if (Bconstat (2))			/* if CONSOLE has a char... */
	{
		while (Bconstat (2))		/* read char while there are */
			Bconin (2);		/* chars to read (flush) */
		return (1);			/* yes, there was a key */
	}
	return (0);				/* no key */
}

