
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <tiga.h>
#include <extend.h>
#include <typedefs.h>


CONFIG config;


struct pal {
	int r;
	int g;
	int b;
	} Pal[256];

int PX, PY;
int Xoff = 0;
int Yoff = 0;

int Width, Height;		/* Width and Height of the entire image */

int iWidth, iHeight;		/* Width and Height of sub-image */



static unsigned char outrow[1024] = {0};
static unsigned char ostack[4096] = {0};


static unsigned char cmask[9] = {0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff};

static unsigned int rem = 0;

static int remct = 0;

static FILE *fp = NULL;
static int bufct = 0;

static int xsize = 0;
static int ysize = 0;
static int xadj = 0;
static int yadj = 0;

static int x = 0;
static int y = 0;
static int ix = 0;
static int iy = 0;
static int iw = 0;
static int ih = 0;

static int pass = 0;

static int rowcnt = 0;
static int done = 0;
static int interlaced = 0;

static unsigned char ctfirst[4096] = {0};
static unsigned char ctlast[4096] = {0};
static int ctlink[4096] = {0};

static int nextcode = 0;
static int nextlim = 0;




void inittiga()
{
int ip_result;
char outbuf[80];

	if (!(set_videomode(TIGA, INIT_GLOBALS | CLR_SCREEN) )) {
		printf("Error: set_videomode() has failed.\n");
		printf("Make sure that TIGACD has been loaded.\n");
		exit(-1);
		}


	/*
	 *
	 * Next, install the extended primitives.
	 *
	 * See page 3-99 of the TIGA-340 User's Guide for
	 * an explanation of the error result codes.
	 *
	 */

	 if (!function_implemented(DRAW_LINE)) {

		if ( (ip_result = install_primitives()) < 0) {
			set_videomode(PREVIOUS, INIT);
			printf("Error: install_primitives() has failed\n");
			printf("with an error code of %d.\n",ip_result);
			exit(-1);
			}

		}


	get_config(&config);



	init_text();

	set_fcolor(WHITE);

	set_bcolor(BLACK);

	sprintf(outbuf,"Current Display Mode: %d of %d",config.current_mode,
		config.num_modes);

	text_out(0,0,outbuf);

	sprintf(outbuf,"Resolution: %d by %d by %d bits",config.mode.disp_hres,
		config.mode.disp_vres, config.mode.disp_psize);

	text_out(0,20,outbuf);

	text_out(0,40,"Press a key to continue:");


	getch();

}


/*
 *	Put the card back in text mode
 */

void endtiga()
{

	set_videomode(PREVIOUS, INIT);

}




void FlushIn()
{
	do
	{
		while (bufct) {
			fgetc(fp);
			bufct--;
		}
	} while (bufct = fgetc(fp));
}



unsigned char getgb()
{
	unsigned char gb;

	if (bufct == 0) {
		bufct = fgetc(fp);
		if ((bufct == EOF) || (bufct == 0)) {
			endtiga();
			printf("Error: Unexpected End of Data");
			exit(2);
		}
	}
	if ((gb = fgetc(fp)) == EOF) {
		endtiga();
		printf("Error: Unexpected EOF");
		exit(1);
	}
	bufct--;
	return(gb);
}




unsigned char getbcode(reqct)
int	reqct;
{
	unsigned char retcode;

	if (remct == 0) {
		rem = getgb();
		remct = 8;
	}
	if (remct < reqct) {
		rem = rem | (((int) getgb()) << remct);
		remct += 8;
	}
	retcode = rem & cmask[reqct];
	remct -= reqct;
	rem = rem >> reqct;
	return(retcode);
}


unsigned int getcode(reqct)
int reqct;
{
	int	temp;

	if (reqct <= 8) return(getbcode(reqct));
	temp = getbcode(8);
	return((getbcode(reqct-8) << 8) | temp);
}


void init_codetable(cc)
int	cc;
{
	int	code = 0;

	nextcode = cc + 2;
	nextlim = cc << 1;
	while (code < cc) {
		ctfirst[code] = ctlast[code] = code;
		ctlink[code++] = -1;
	}
	while (code < 4096) ctlink[code++] = -2;
}


void insert_code(code, oldcode, csizeptr)
int code, oldcode, *csizeptr;
{
	ctlink[nextcode] = oldcode;
	ctlast[nextcode] = ctfirst[code];
	ctfirst[nextcode] = ctfirst[oldcode];
	if (++nextcode == nextlim) {
		if (*csizeptr < 12) {
			*csizeptr += 1;
			nextlim <<= 1;
		}
	}
}


void putpixel(val)
unsigned char val;
{

	set_fcolor(val);
	draw_point(PX + Xoff,PY + Yoff);

	PX++;
	if (PX == iWidth) {
		PX = 0;
		PY++;
		}

}


void putx(code, psize)
int code, psize;
{
	int ccount = 0;
	unsigned char *s;

	s=ostack;
	do
	{
		*s++ = ctlast[code];
		ccount++;
		code = ctlink[code];
	} while (code != -1);
	if (psize == 1) {
		do
		{
			putpixel(*--s & 1);
			putpixel(*s >> 1);
		} while (--ccount);
	}
	else do {
		putpixel(*--s);
	} while (--ccount);
}




void ximage(codestart,pixelsize)
int codestart,pixelsize;
{
	int reqct, code, cc, eoi, oldcode;

	cc = 1 << codestart;
	eoi = cc + 1;
	reqct = codestart + 1;
	init_codetable(cc);
	oldcode = -1;
	done = 0;
	pass = 0;
	rowcnt = iw;
	x = 0;
	y = 0;
	do {
		code = getcode(reqct);
		if (code == cc) {
			init_codetable(cc);
			reqct = codestart + 1;
			oldcode = -1;
		} else if (code == eoi) {
			FlushIn();
			done = -1;
		} else {
			if (ctlink[code] != -2) {
				if (oldcode != -1) insert_code(code, oldcode, &reqct);
			} else {
				insert_code(oldcode, oldcode, &reqct);
			}
			putx(code, pixelsize);
			oldcode = code;
		}

	} while (!done);


}




void bgfill(background)
unsigned char background;
{

	clear_page(background);


}



void getcolors(psize)
int psize;
{
	int cindex, cmax;

	cmax = 1 << psize;
	for (cindex = 0; cindex < cmax; cindex++) {


			Pal[cindex].r = fgetc(fp);
			Pal[cindex].g = fgetc(fp);
			Pal[cindex].b = fgetc(fp);

			set_palet_entry(cindex,Pal[cindex].r,Pal[cindex].g,Pal[cindex].b,0);

			}




}



/*
 *	Get a two-byte word (LSB first) from the file.
 *
 */

int gword()
{
	return(fgetc(fp) | (fgetc(fp) << 8));
}



main(int argc,char *argv[])
{
	int	n;
	int	alldone, bitspixel, pixelsize, csize, blen;
	unsigned char sflags, background, work, iflags;
	char namework[64];



	if (argc != 2) {
		printf("Usage: gsgif filename\n");
		exit(-1);
		}



	if ( ( fp = fopen(argv[1],"rb") ) == NULL) {
		strcpy(namework,argv[1]);
		strcat(namework,".GIF");

		if ( ( fp = fopen(namework,"rb") ) == NULL) {
			printf("Error: File Not Found");
			exit(-1);
			}

		}


	if (fgetc(fp) != 'G') {
		printf("Error: Invalid File Format\n");
		exit(1);
	}
	for (n=1;n<=5;n++) fgetc(fp);

	Width = gword();
	Height = gword();

	sflags = fgetc(fp);
	bitspixel = (sflags & 7) + 1;

	background = fgetc(fp);

	if (fgetc(fp)) {
		printf("Error: Invalid File Format\n");
		exit(1);
	}

	inittiga();

	if (config.mode.disp_hres > Width) Xoff = ( (config.mode.disp_hres - Width) / 2);
	if (config.mode.disp_vres > Height) Yoff = ( (config.mode.disp_vres - Height) / 2);

	if (sflags & 0x80) getcolors(bitspixel);

	bgfill(background);

	alldone = 0;

	while (!alldone && ((work = fgetc(fp)) != EOF)) {
		if (work == ',') {

			Xoff += gword();		/* center the image */
			Yoff += gword();
			iWidth = gword();
			iHeight = gword();

			iflags = fgetc(fp);
			interlaced = iflags & 0x40;
			if (interlaced) {
				endtiga();
				printf("Error: Can't handle interlaced image.");
				exit(-1);
				}

			pixelsize = bitspixel;

			if (iflags & 0x80) {
				pixelsize = (iflags & 7) + 1;
				getcolors(pixelsize);				/* only last map used */
			}

			csize = fgetc(fp);
			bufct = 0;
			ximage(csize, pixelsize);

		} else if (work == '!') {
			fgetc(fp);
			while (blen = fgetc(fp)) {
				for (n=0; n<blen; n++) fgetc(fp);
			}
		} else if (work = ';') alldone = -1;
		else {
			endtiga();
			printf("Error: Invalid File Format\n");
			exit(1);
		}
	}
	getch();
	endtiga();

}

