/* bmp2gif.c -- See end-of-file for (C) */
/* This was written for Microsoft 32-bit-integer compilers--it
 * should compile with
 *	cl gif2bmp.c
 * to produce the executable gif2bmp.exe
 *
 * The Microsoft oddities are:
 *	 The funny include files -- they may be omitted on compilers
 *	 that can not find them (stdio.h better be there, however)
 * #pragma pack(1) -- This forces the BITMAPFILEHEADER structure
 *	 to be the same length in memory as in files (otherwise, the structure
 *	 is padded out to be a multiple of 8? bytes long
 * Note that Microsoft uses all-caps for typedefs.	Ugh.
 */
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

typedef unsigned char byte;
typedef unsigned short WORD;
typedef unsigned long DWORD;

#pragma pack(1)
typedef struct tagRGBQUAD {
	byte	rgbBlue;
	byte	rgbGreen;
	byte	rgbRed;
	byte	rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPFILEHEADER {
	WORD	bfType;
	DWORD	bfSize;
		WORD	bfReserved1;
		WORD	bfReserved2;
	DWORD	bfOffBits;
} BITMAPFILEHEADER;
typedef BITMAPFILEHEADER *PBITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
	DWORD	   biSize;
	DWORD	   biWidth;
	DWORD	   biHeight;
	WORD	   biPlanes;
	WORD	   biBitCount;

	DWORD	   biCompression;
	DWORD	   biSizeImage;
	DWORD	   biXPelsPerMeter;
	DWORD	   biYPelsPerMeter;
	DWORD	   biClrUsed;
	DWORD	   biClrImportant;
} BITMAPINFOHEADER;

BITMAPFILEHEADER hdr;
BITMAPINFOHEADER bi;
long wib;
int yat;
unsigned char cmap[256*4];	/* Bytes of blue, green, red, reserved */
unsigned char omap[256*4];	/* Output colormap */
unsigned char *scanline;
unsigned char used[256];

FILE *fpin; /* Input file fp */
int c666= 0;	/* Force output colormap to 666 colors */
int c555= 0;	/* Force output colormap to 555 colors */
int ncolors;

int fread_chk(char *cp, int n, int count, FILE *fp){
	int c= fread(cp, n, count, fp);
	if(c!=count){
		perror("Read error:");
		exit(1);
	}
	return 1;
}
int fwrite_chk(char *cp, int n, int count, FILE *fp){
	int c= fwrite(cp, n, count, fp);
	if(c!=count){
		perror("Write error:");
		exit(1);
	}
	return 1;
}
static int dib_wib(int bitcount, int wi){
	switch (bitcount){
	case 1: wi= (wi+31) >> 3; break;
	case 4: wi= (wi+7)	>> 1; break;
	case 8: wi=  wi+3; break;
		case 24:wi= (wi*3)+3; break;
	}
	return wi & ~3;
}
void err(char *msg){
	fprintf(stderr, "%s\n", msg);
	exit(5);
}
unsigned char color555(unsigned char pv){
	static int itab[]= {0, 0x40, 0x80, 0xc0, 0xff};
	static int rtab[]= {0, 0x30, 0x60, 0xa0, 0xe0, 256};
	int k;
	for(k= 1; k<5; k++)if(pv<rtab[k])
		break;
	return itab[k-1];
}
void monout(unsigned char *buf, int wib){
	int x;
	unsigned char *bd= buf+wib*8;
	unsigned char *bs= buf+wib;
	while(bd>buf){
		unsigned char v= *--bs;
		for(x= 0; x<8; x++){
			*--bd= v&1;
			v >>= 1;
		}
	}
}
void gulp(char *dibname){
	int nbytes;
	int v, y;

	if((fpin= fopen (dibname, "rb"))==0){
		perror(dibname);
		exit(0);
	}
	fread_chk((char *)(&hdr),1,sizeof(hdr),fpin);
	if(hdr.bfType!= 0x4d42)
		err("Image not a .bmp");

	fread_chk((char *)(&bi), 1, sizeof(bi), fpin);

	wib= dib_wib((int)bi.biBitCount, (int)bi.biWidth);
	bi.biSizeImage= bi.biHeight * wib;
	if(bi.biBitCount != 8 && bi.biBitCount!=1)
		err("Only 8-bit or 1-bit .bmp images are permitted");
	if(bi.biBitCount==1){
		scanline= malloc(wib*8);
		fread_chk(scanline, 1, (int)wib, fpin);
		monout(scanline, wib);
		yat= 0;

		v= (int)((hdr.bfOffBits - bi.biSize - sizeof(BITMAPFILEHEADER))/sizeof(RGBQUAD));
		bi.biClrUsed= v;
		if(v>0)
			fread_chk(cmap, sizeof(RGBQUAD), v, fpin);
		cmap[0]= cmap[1]= cmap[2]= 255;
		cmap[4]= cmap[5]= cmap[6]= 0;
		return;
	}
	if(bi.biBitCount<=8){
		v= (int)((hdr.bfOffBits - bi.biSize - sizeof(BITMAPFILEHEADER))/sizeof(RGBQUAD));
		bi.biClrUsed= v;
		if(v>0)
			fread_chk(cmap, sizeof(RGBQUAD), v, fpin);
		if(c666){
			int k= 4*v;
			while(--k>=0)
				cmap[k]= 51*((cmap[k]+25)/51);
		}
		if(c555){
			int k= 4*v;
			while(--k>=0)
				cmap[k]= color555(cmap[k]);
		}
	}
	scanline= malloc((int)wib);
	if(scanline==0)
		err("Not enough room for the scanline");
	fread_chk(scanline, 1, (int)wib, fpin);
	yat= 0; 
}
static int GetPixel(int x, int y){
	y= (int)(bi.biHeight-1-y);	/* bmp files are upside-down */
	if(y!=yat){
		if(y!=yat+1)
			if(0!=fseek(fpin, (y-(yat+1))*wib, SEEK_CUR)){
				perror("Seek on input file");
				exit(1);
			}
		fread_chk(scanline, 1, (int)wib, fpin);
		if(bi.biBitCount==1)
			monout(scanline, wib);
		yat= y;
	}
	return used[scanline[x]];
}
unsigned char windows_first_10[]= {
	  0,  0,  0, 128,  0,  0,	0,128,	0, 128,128,  0,   0,  0,128,
	128,  0,128,   0,128,128, 192,192,192, 192,220,192, 166,202,240};
unsigned char windows_last_10[]= {
	255,251,240, 160,160,164, 128,128,128, 255,  0,  0,   0,255,  0,
	255,255,  0,   0,  0,255, 255,	0,255,	 0,255,255, 255,255,255};
int CreateRGBmap(){
	int i;
	int r,g,b, ur,ug;

	memcpy(omap, windows_first_10, sizeof(windows_first_10));
	i= 10*3;
	for(r= 0; r<6; r++){
		ur= r*51;
		for(g= 0; g<6; g++){
			ug= g*51;
			for(b= 0; b<6; b++){
				omap[i++]= ur;
				omap[i++]= ug;
				omap[i++]= b*51;
			}
		}
	}
	while(i<3*(256-10))
		omap[i++]= 0;
	memcpy(omap+i, windows_last_10, sizeof(windows_last_10));
	for(i= 0; i<256; i++){
		unsigned char *cp= &cmap[i*4];
		used[i]= 10+(cp[0]/51) + 6*((cp[1]/51) + 6*(cp[2]/51));
	}
	return 256;
}
int formoutputcmap(){
	int ncolors= 0;
	int x, y;
	for(x= 0; x<256; x++)used[x]= 0;
	if(bi.biBitCount>1)
	for(y= 0; y<(int)bi.biHeight; y++){
		if(y!=0)
			fread_chk(scanline, 1, (int)wib, fpin);
		for(x= 0; x<(int)bi.biWidth; x++)
			used[scanline[x]]= 1;
	}
	/* Count the number of colors used */
	for(x= 0; x<256; x++)ncolors += used[x];
	if(ncolors<2){
		ncolors= 2;
		used[0]= used[1]= 1;
	}
	for(x= y= 0; x<256; x++)if(used[x]!=0){
		used[x]= y/3;
		omap[y++]= cmap[4*x+2];
		omap[y++]= cmap[4*x+1];
		omap[y++]= cmap[4*x];
	}
	fclose(fpin);
	return ncolors;
}
int nearestcolor(int *rgb){
	int k;
	int pv= 0;
	int n= 1 << ((int)bi.biBitCount);
	long del[3], len, minlen= 3*256L*256L;
	unsigned char *cp= cmap;

	for(k= 0; k<n; k++, cp+= 4){
		del[0]= cp[0]-rgb[2];
		del[1]= cp[1]-rgb[1];
		del[2]= cp[2]-rgb[0];
		len= del[0]*del[0] + del[1]*del[1] + del[2]*del[2];
		if(len<minlen){
			minlen= len;
			pv= k;
		}
	}
	return pv;
}
char *note[]= {
	"Usage: [-i] [-x # [# #]] [-b # [# #]] source.bmp dest.gif",
	"Create a .gif file from a Windows .bmp file",
	"Options:",
	"-i    Interlace [default not]",
	"-x #  Set pvalue # transparent (# # # for transparent rgb)",
	"-b #  Set pvalue # background [default 0]",
//	"-p #  Bits per pixel (override the number in the .bmp file)",
	"-c X  Add comment X (use quoted string argument)",
	"-n    Convert colors to nearest Netscape color [multiple of 51]",
	"-5    Convert colors to nearest Netscape 125 colors (for Java)",
	0};
char *comment;
typedef int (* ifunptr)(int, int);
static void GIFEncode(FILE *fp, int GWidth, int GHeight,
	int GInterlace, int Background, int Transparent,
	int BitsPerPixel, unsigned char *cmap, ifunptr GetPixel );

void main(int ac, char **av){
	int k;
	int GWidth;
	int GHeight;
	FILE *fp;
	int GInterlace= 0;
	int Background;
	int Transparent;
	int BitsPerPixel= -1;

	char *cp;
	static int xpar[3]= {-1,-1,-1};
	static int bg[3]= {0,-1,-1};
	char *srcname= 0;
	char *dstname= 0;

	while(cp= *++av)if(*cp++=='-')switch(*cp++){
	case '5':	c555= 1; break;
	case 'n':	c666= 1; break;
	case 'c':	comment= *++av; break;
//	case 'p':	BitsPerPixel= atoi(*++av);
//			if(BitsPerPixel>8)
//				BitsPerPixel= 8;
//			break;
	case 'i':	GInterlace= 1; break;
	case 'x':	xpar[0]= atoi(*++av);
			if(av[1][0]>='0' && av[1][0]<='9'){
				xpar[1]= atoi(*++av);
				xpar[2]= atoi(*++av);
			} break;
	case 'b':	bg[0]= atoi(*++av);
			if(av[1][0]>='0' && av[1][0]<='9'){
				bg[1]= atoi(*++av);
				bg[2]= atoi(*++av);
			} break;
	default:
	erra:		for(av= note; *av; ++av)
				fprintf(stderr, "%s\n", *av);
			exit(1);
	}else if(srcname==0)
		srcname= *av;
	else if(dstname==0)
		dstname= *av;
	else
		goto erra;
	if(dstname==0)
		goto erra;

	/* Open the source bmp */
	gulp(srcname);

	/* Choose the output colors */
	if(c666)	// Use 666 windows colormap
		ncolors= CreateRGBmap();
	else
		ncolors= formoutputcmap();
	for(BitsPerPixel= 0; (1 << BitsPerPixel)<ncolors; BitsPerPixel++);
	gulp(srcname);

	/* Create the gif file */
	fp= fopen(dstname, "wb");
	if(fp==0){
		perror(dstname);
		exit(1);
	}
	/* Transfer some parameters */
	GWidth= (int)bi.biWidth;
	GHeight= (int)bi.biHeight;
	Transparent= xpar[0];
	if(xpar[1]>=0)
		Transparent= used[nearestcolor(xpar)];
	if(Transparent>0)for(k= 0; k<256; k++){
		int i= used[k]*3, j= Transparent*3;
		if(omap[i]==omap[j] && omap[i+1]==omap[j+1] && omap[i+2]==omap[j+2])
			used[k]= Transparent;
	}
	Background= bg[0];
	if(bg[1]>=0)
		Background= used[nearestcolor(bg)];

	GIFEncode(fp, GWidth, GHeight,
		GInterlace, Background, Transparent,
		BitsPerPixel, omap, GetPixel);

	printf("%d colors in %s\n", ncolors, srcname);
}
/*****************************************************************************
 *
 * GIFENCODE.C	  - GIF Image compression interface
 *
 * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
 *		  BitsPerPixel, Red, Green, Blue, GetPixel )
 *
 *****************************************************************************/
#define TRUE 1
#define FALSE 0

static int Width, Height;
static int curx, cury;
static long CountDown;
static int Pass = 0;
static int Interlace;
typedef int code_int;

#ifdef SIGNED_COMPARE_SLOW
typedef unsigned long int count_int;
typedef unsigned short int count_short;
#else /*SIGNED_COMPARE_SLOW*/
typedef long int		  count_int;
#endif /*SIGNED_COMPARE_SLOW*/

static void Putword ( int w, FILE* fp );
static void compress ( int init_bits, FILE* outfile, ifunptr ReadValue );
static void output ( code_int code );
static void cl_block ( void );
static void cl_hash ( count_int hsize );
static void writeerr ( void );
static void char_init ( void );
static void char_out ( int c );
static void flush_char ( void );


/*
 * Bump the 'curx' and 'cury' to point to the next pixel
 */
static void BumpPixel() {
	/* Bump the current X position */
	++curx;
	/*
	 * If we are at the end of a scan line, set curx back to the beginning
	 * If we are interlaced, bump the cury to the appropriate spot,
	 * otherwise, just increment it.
	 */
	if( curx == Width ) {
		curx= 0;
		if( !Interlace )
			++cury;
		else switch( Pass ) {
		case 0:
			cury += 8;
			if( cury >= Height ) {
				++Pass;
				cury = 4;
			} break;
		case 1:
			cury += 8;
			if( cury >= Height ) {
				++Pass;
				cury = 2;
			} break;
		case 2:
			cury += 4;
			if( cury >= Height ) {
				 ++Pass;
				 cury = 1;
			} break;
		case 3:
			cury += 2;
			break;
		}
	}
}
/* Return the next pixel from the image  */
static int GIFNextPixel(ifunptr getpixel){
	int r;

	if( CountDown == 0 )
		return EOF;
	--CountDown;

	r = ( * getpixel )( curx, cury );
	BumpPixel();
	return r;
}
/* public */
static void GIFEncode(FILE *fp, int GWidth, int GHeight,
	int GInterlace, int Background, int Transparent,
	int BitsPerPixel, unsigned char *omap, ifunptr GetPixel ){

	int B;
	int RWidth, RHeight;
	int LeftOfs, TopOfs;
	int Resolution;
	int ColorMapSize;
	int InitCodeSize;
	int i;

	Interlace = GInterlace;

	ColorMapSize = 1 << BitsPerPixel;

	RWidth = Width = GWidth;
	RHeight = Height = GHeight;
	LeftOfs = TopOfs = 0;

	Resolution = BitsPerPixel;

	/* Calculate number of bits we are expecting */
	CountDown = (long)Width * (long)Height;

	/* Indicate which pass we are on (if interlace) */
	Pass = 0;

	/* The initial code size */
	if( BitsPerPixel <= 1 )
		InitCodeSize = 2;
	else
		InitCodeSize = BitsPerPixel;

	/* Set up the current x and y position */
	curx = cury = 0;

	/* Write the Magic header */
	fwrite_chk( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );

	/* Write out the screen width and height */
	Putword( RWidth, fp );
	Putword( RHeight, fp );

	/* Indicate that there is a global colour map */
	B = 0x80;	/* Yes, there is a color map */

	/* OR in the resolution */
	B |= (Resolution - 1) << 5;

	/* OR in the Bits per Pixel */
	B |= (BitsPerPixel - 1);

	/* Write it out */
	fputc( B, fp );

	/* Write out the Background colour */
	fputc( Background, fp );

	/* Byte of 0's (future expansion) */
	fputc( 0, fp );

	/* Write out the Global Colour Map */
	for( i=0; i<ColorMapSize; ++i ) {
		fputc( omap[0], fp );	// Red
		fputc( omap[1], fp );	// Green
		fputc( omap[2], fp );	// Blue
		omap += 3;
	}
	/* Write out extension for transparent colour index, if necessary. */
	if ( Transparent >= 0 ) {
		fputc( '!', fp );
		fputc( 0xf9, fp );
		fputc( 4, fp );
		fputc( 1, fp );
		fputc( 0, fp );
		fputc( 0, fp );
		fputc( Transparent, fp );
		fputc( 0, fp );
	}
	if (comment!=0 && *comment){
		fputc( '!', fp);
		fputc( 0xfe, fp);
		fputc( strlen(comment), fp);
		do
			fputc( *comment, fp);
		while(*comment++);
	}
	/* Write an Image separator */
	fputc( ',', fp );

	/* Write the Image header */
	Putword( LeftOfs, fp );
	Putword( TopOfs, fp );
	Putword( Width, fp );
	Putword( Height, fp );

	/* Write out whether or not the image is interlaced */
	if( Interlace )
		fputc( 0x40, fp );
	else
		fputc( 0x00, fp );

	/* Write out the initial code size */
	if(EOF==fputc( InitCodeSize, fp )){
		perror("Writing output");
		exit(1);
	}
	/* Go and actually compress the data */
	compress( InitCodeSize+1, fp, GetPixel );

	/* Write out a Zero-length packet (to end the series) */
	fputc( 0, fp );

	/* Write the GIF file terminator */
	fputc( ';', fp );

	/* And close the file */
	fclose( fp );
}

/* Write out a word to the GIF file */
static void Putword(int w, FILE *fp ){
	fputc( w & 0xff, fp );
	fputc( (w / 256) & 0xff, fp );
}
/***************************************************************************
 *
 *	GIFCOMPR.C		 - GIF Image compression routines
 *
 *	Lempel-Ziv compression based on 'compress'.  GIF modifications by
 *	David Rowley (mgardi@watdcsu.waterloo.edu)
 *
 ***************************************************************************/

/* General DEFINEs	*/

#define BITS	12
#define HSIZE  5003 	   /* 80% occupancy */

#ifdef NO_UCHAR
 typedef char	char_type;
#else /*NO_UCHAR*/
 typedef	unsigned char	char_type;
#endif /*NO_UCHAR*/

/*
 *
 * GIF Image compression - modified 'compress'
 *
 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
 *
 * By Authors:	Spencer W. Thomas	(decvax!harpo!utah-cs!utah-gr!thomas)
 *		Jim McKie		(decvax!mcvax!jim)
 *		Steve Davies		(decvax!vax135!petsd!peora!srd)
 *		Ken Turkowski		(decvax!decwrl!turtlevax!ken)
 *		James A. Woods		(decvax!ihnp4!ames!jaw)
 *		Joe Orost		(decvax!vax135!petsd!joe)
 *
 */
#include <ctype.h>

#define ARGVAL() (*++(*argv) || (--argc && *++argv))

static int n_bits;			  /* number of bits/code */
static int maxbits = BITS;		  /* user settable max # bits/code */
static code_int maxcode;		  /* maximum code, given n_bits */
static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this code */
#ifdef COMPATIBLE		/* But wrong! */
# define MAXCODE(n_bits)	((code_int) 1 << (n_bits) - 1)
#else /*COMPATIBLE*/
# define MAXCODE(n_bits)	(((code_int) 1 << (n_bits)) - 1)
#endif /*COMPATIBLE*/

static count_int htab [HSIZE];
static unsigned short codetab [HSIZE];
#define HashTabOf(i)	   htab[i]
#define CodeTabOf(i)	codetab[i]

static code_int hsize = HSIZE;			   /* for dynamic table sizing */

/*
 * To save much memory, we overlay the table used by compress() with those
 * used by decompress().  The tab_prefix table is the same size and type
 * as the codetab.	The tab_suffix table needs 2**BITS characters.	We
 * get this from the beginning of htab.  The output stack uses the rest
 * of htab, and contains characters.  There is plenty of room for any
 * possible stack (stack used to be 8000 characters).
 */

#define tab_prefixof(i) CodeTabOf(i)
#define tab_suffixof(i) 	   ((char_type*)(htab))[i]
#define de_stack		   ((char_type*)&tab_suffixof((code_int)1<<BITS))

static code_int free_ent = 0;			   /* first unused entry */

/*
 * block compression parameters -- after all codes are used up,
 * and compression rate changes, start over.
 */
static int clear_flg = 0;

static int offset;
static long int in_count = 1;		 /* length of input */
static long int out_count = 0;		 /* # of codes output (for debugging) */

/*
 * compress stdin to stdout
 *
 * Algorithm:  use open addressing double hashing (no chaining) on the
 * prefix code / next character combination.  We do a variant of Knuth's
 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
 * secondary probe.  Here, the modular division first probe is gives way
 * to a faster exclusive-or manipulation.  Also do block compression with
 * an adaptive reset, whereby the code table is cleared when the compression
 * ratio decreases, but after the table fills.	The variable-length output
 * codes are re-sized at this point, and a special CLEAR code is generated
 * for the decompressor.  Late addition:  construct the table according to
 * file size for noticeable speed improvement on small files.  Please direct
 * questions about this implementation to ames!jaw.
 */

static int g_init_bits;
static FILE* g_outfile;

static int ClearCode;
static int EOFCode;
static unsigned long cur_accum = 0;
static int cur_bits = 0;

static void compress(int init_bits, FILE *outfile, ifunptr ReadValue ){
	register long fcode;
	register code_int i /* = 0 */;
	register int c;
	register code_int ent;
	register code_int disp;
	register code_int hsize_reg;
	register int hshift;

	/*
	 * Set up the globals:	g_init_bits - initial number of bits
	 * 			g_outfile   - pointer to output file
	 */
	g_init_bits= init_bits;
	g_outfile= outfile;

	cur_accum= 0;
	cur_bits= 0;

	/* Set up the necessary values */
	offset= 0;
	out_count= 0;
	clear_flg= 0;
	in_count= 1;
	maxcode= MAXCODE(n_bits = g_init_bits);

	ClearCode= (1 << (init_bits - 1));
	EOFCode= ClearCode + 1;
	free_ent= ClearCode + 2;

	char_init();

	ent= GIFNextPixel( ReadValue );

	hshift= 0;
	for ( fcode= (long) hsize;  fcode < 65536L; fcode *= 2L )
	++hshift;
	hshift= 8 - hshift;		/* set hash code range bound */

	hsize_reg= hsize;
	cl_hash( (count_int) hsize_reg);/* clear hash table */

	output( (code_int)ClearCode );

#ifdef SIGNED_COMPARE_SLOW
	while ( (c= GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
#else /*SIGNED_COMPARE_SLOW*/
	while ( (c= GIFNextPixel( ReadValue )) != EOF ) {	/* } */
#endif /*SIGNED_COMPARE_SLOW*/

	++in_count;

	fcode= (long) (((long) c << maxbits) + ent);
	i= (((code_int)c << hshift) ^ ent);	/* xor hashing */

	if ( HashTabOf (i) == fcode ) {
		ent= CodeTabOf(i);
		continue;
	}else if( (long)HashTabOf (i) < 0 )	   /* empty slot */
		goto nomatch;
	disp= hsize_reg - i;		/* secondary hash (after G. Knott) */
	if ( i == 0 )
		disp= 1;
probe:
	if ( (i -= disp) < 0 )
		i += hsize_reg;

	if ( HashTabOf(i) == fcode ) {
		ent = CodeTabOf(i);
		continue;
	}
	if ( (long)HashTabOf(i) > 0 )
		goto probe;
nomatch:
	output ( (code_int) ent );
	++out_count;
	ent= c;
#ifdef SIGNED_COMPARE_SLOW
	if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
#else /*SIGNED_COMPARE_SLOW*/
	if ( free_ent < maxmaxcode ) {	/* } */
#endif /*SIGNED_COMPARE_SLOW*/
		CodeTabOf(i)= free_ent++; /* code -> hashtable */
		HashTabOf(i)= fcode;
	}else
		cl_block();
	}
	/* Put out the final code. */
	output( (code_int)ent );
	++out_count;
	output( (code_int) EOFCode );
}

/*****************************************************************
 * TAG( output )
 *
 * Output the given code.
 * Inputs:
 *	code:	A n_bits-bit integer.  If == -1, then EOF.	This assumes
 *		that n_bits =< (long)wordsize - 1.
 * Outputs:
 *	Outputs code to the file.
 * Assumptions:
 *	Chars are 8 bits long.
 * Algorithm:
 *	Maintain a BITS character long buffer (so that 8 codes will
 * fit in it exactly).	Use the VAX insv instruction to insert each
 * code in turn.  When the buffer fills up empty it and start over.
 */

static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
				  0x001F, 0x003F, 0x007F, 0x00FF,
				  0x01FF, 0x03FF, 0x07FF, 0x0FFF,
				  0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };

static void output(code_int  code){
	cur_accum &= masks[ cur_bits ];

	if( cur_bits > 0 )
		cur_accum |= ((long)code << cur_bits);
	else
		cur_accum = code;
	cur_bits += n_bits;

	while( cur_bits >= 8 ) {
		char_out( (unsigned int)(cur_accum & 0xff) );
		cur_accum >>= 8;
		cur_bits -= 8;
	}
	/*
	 * If the next entry is going to be too big for the code size,
	 * then increase it, if possible.
	 */
	if ( free_ent > maxcode || clear_flg ) {
		if( clear_flg ) {
			maxcode = MAXCODE (n_bits = g_init_bits);
			clear_flg = 0;
		} else {
			++n_bits;
			if ( n_bits == maxbits )
				maxcode = maxmaxcode;
			else
				maxcode = MAXCODE(n_bits);
		}
	}
	if( code == EOFCode ) {
		/* At EOF, write the rest of the buffer. */
		while( cur_bits > 0 ) {
			char_out( (unsigned int)(cur_accum & 0xff) );
			cur_accum >>= 8;
			cur_bits -= 8;
		}
		flush_char();
		fflush( g_outfile );

		if( ferror( g_outfile ) )
			writeerr();
	}
}
/* Clear out the hash table */
static void cl_block (){		/* table clear for block compress */
	cl_hash ( (count_int) hsize );
	free_ent = ClearCode + 2;
	clear_flg = 1;

	output( (code_int)ClearCode );
}
static void cl_hash(count_int hsize){
	memset(htab, 0xff, hsize*sizeof(htab[0]));
}
static void writeerr(){
	err( "error writing output file" );
}

/******************************************************************************
 *
 * GIF Specific routines
 *
 ******************************************************************************/

/* Number of characters so far in this 'packet' */
static int a_count;

/* Set up the 'byte output' routine */
static void char_init(){
	a_count = 0;
}
/* Define the storage for the packet accumulator */
static char accum[ 256 ];

/*
 * Add a character to the end of the current packet, and if it is 254
 * characters, flush the packet to disk.
 */
static void char_out( int c ){
	accum[ a_count++ ] = c;
	if( a_count >= 254 )
		flush_char();
}
/* Flush the packet to disk, and reset the accumulator */
static void flush_char(){
	if( a_count > 0 ) {
		fputc( a_count, g_outfile );
		fwrite_chk( accum, 1, a_count, g_outfile );
		a_count= 0;
	}
}
/*
**
** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
** Lempel-Zim compression based on "compress".
**
** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
**
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** The Graphics Interchange Format(c) is the Copyright property of
** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
** CompuServe Incorporated.
*/
/*****************************************************************************\
*	Windows functions, types, and definitions			      *
*	Version 3.10							      *
*	Copyright (c) 1985-1992, Microsoft Corp. All rights reserved.	      *
*******************************************************************************
*
*(C)1996 Ephraim Cohen--subject to the above,
** permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notices appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
**
*/
