#include "ztypes.h"
#include "pb_console.h"
#include <Quickdraw.h>
#include <QDOffscreen.h>

#define MAX_BIT 512 /* Must be less than or equal to CODE_TABLE_SIZE */
#define CODE_SIZE 8
#define CODE_TABLE_SIZE 4096
#define PREFIX 0
#define PIXEL 1
#define RED 0
#define GREEN 1
#define BLUE 2
#define CURRENT_VERSION "GIF87a"
#define HASH_SIZE 8192
#define HUFFMAN_FLAG 2			/* flags */
#define HUFFMAN_ONEDICT 4		/* flags: One huffman dictionary?  Only Shogun has more */
#define TRANSPARENCY_FLAG 2		/* flags */
#define NOT_COLOR_DOUBLE 8  /* flags */
#define hashfunc(a, b) ((long) ((long) (a) + (long) (b)) % HASH_SIZE)

int unpack_image(unsigned char *in, unsigned char *out, int width, long numcodes, size_t booga);
void get_huffman_dictionary(void);

static short mask[16] = {
    0x0000, 0x0001, 0x0003, 0x0007,
    0x000f, 0x001f, 0x003f, 0x007f,
    0x00ff, 0x01ff, 0x03ff, 0x07ff,
    0x0fff, 0x1fff, 0x3fff, 0x7fff
};


typedef struct image_s {
    short width;
    short height;
    short colours;
    long pixels;
    unsigned char *image;
    unsigned char (*colourmap)[3];
} image_t;

typedef struct compress_s {
    short next_code;
    short slen;
    short sptr;
    short tlen;
    short tptr;
} compress_t;

typedef struct nlist_s {
    struct nlist *next;
    short prefix;
    short pixel;
    short code;
} nlist_t;

typedef struct header_s {
    unsigned char part;
    unsigned char flags;
    unsigned short unknown1;
    unsigned short images;
    unsigned short unknown2;
    unsigned char dir_size;
    unsigned char unknown3;
    unsigned short checksum;
    unsigned short unknown4;
    unsigned short version;
} header_t;

typedef unsigned char color_t[3];

typedef struct colormap_s {
	unsigned char num_colors;
	color_t table[1];
} colormap_t;

typedef struct pdirectory_s {
    short image_number;
    short image_width;
    short image_height;
    short image_flags;
    long image_data_addr;
    long image_cm_addr;
	short huffman_dict_addr;
} pdirectory_t;

static colormap_t *get_color_table(FILE *fp, pdirectory_t *directory);
static void *get_image (FILE *, pdirectory_t *);
static void decompress_image (FILE *, image_t *);
static short read_code (FILE *, compress_t *);

static header_t picfile_header;
static int max_pic_index;
static int *pic_index;
static pdirectory_t *picture_directory = NULL;
static short code_table[CODE_TABLE_SIZE][2];
static unsigned char buffer[CODE_TABLE_SIZE];
static unsigned char code_buffer[CODE_TABLE_SIZE];
static signed short *huffman_dictionary = NULL;
static FILE *picfile;

#if defined(__STDC__)
static unsigned char read_byte (FILE *fp)
#else
static unsigned char read_byte (fp)
FILE *fp;
#endif
{
    int c;

    if ((c = fgetc (fp)) == EOF) {
        perror ("fgetc");
        exit (EXIT_FAILURE);
    }

    return ((unsigned char) c);

}/* read_byte */

#if defined(__STDC__)
static unsigned short read_word (FILE *fp)
#else
static unsigned short read_word (fp)
FILE *fp;
#endif
{
    unsigned short w;

    w = (unsigned short) read_byte (fp) << 8;
    w += (unsigned short) read_byte (fp) ;

    return (w);

}/* read_word */


#if defined(__STDC__)
int read_picture_data (void)
#else
int read_picture_data ()
#endif
{
    int i;
    char linebuf[80];
    FILE *fp;
	long dir_pos;

    if ((fp = fopen ("CPIC.DATA", "rb")) == NULL) {
        fatal ("Couldn't open picture file");
    }

    picfile_header.part = read_byte (fp);
    picfile_header.flags = read_byte (fp);
    picfile_header.unknown1 = read_word (fp);
    picfile_header.images = read_word (fp);
    picfile_header.unknown2 = read_word (fp);
    picfile_header.dir_size = read_byte (fp);
    picfile_header.unknown3 = read_byte (fp);
    picfile_header.checksum = read_word (fp);
    picfile_header.unknown4 = read_word (fp);
    picfile_header.version = read_word (fp);

    sprintf (linebuf, "Total number of images = %d", (int) picfile_header.images);
#ifdef V6_DEBUG
    output_string(linebuf);
    new_line();
#endif
    if ((picture_directory = (pdirectory_t *) NewPtr (picfile_header.images * sizeof (pdirectory_t))) == NULL) {
        fatal("Insufficient memory\n");
    }
	dir_pos = ftell(fp);

	max_pic_index = 0;
	for (i = 0; (unsigned int) i < picfile_header.images; i++) {
        picture_directory[i].image_number = read_word (fp);
        if (picture_directory[i].image_number > max_pic_index) {
        	max_pic_index = picture_directory[i].image_number;
        }
        picture_directory[i].image_width = read_word (fp);
        picture_directory[i].image_height = read_word (fp);
        picture_directory[i].image_flags = read_word (fp);
        picture_directory[i].image_data_addr = (unsigned long) read_byte (fp) << 16;
        picture_directory[i].image_data_addr += (unsigned long) read_byte (fp) << 8;
        picture_directory[i].image_data_addr += (unsigned long) read_byte (fp);
        if (picfile_header.dir_size >= 14) {
            picture_directory[i].image_cm_addr = (unsigned long) read_byte (fp) << 16;
            picture_directory[i].image_cm_addr += (unsigned long) read_byte (fp) << 8;
            picture_directory[i].image_cm_addr += (unsigned long) read_byte (fp);
        } else {
            picture_directory[i].image_cm_addr = 0;
            /* (void) read_byte (fp); */
        }
        if (picfile_header.dir_size >= 16) {
			picture_directory[i].huffman_dict_addr = read_word(fp);
		}
		fseek(fp,dir_pos += picfile_header.dir_size,SEEK_SET);
    }
    
    picfile = fp;
	if (picfile_header.flags & HUFFMAN_ONEDICT)
		get_huffman_dictionary();

	pic_index = (void *)NewPtr((max_pic_index + 1) * sizeof(int));
	memset(pic_index, 0xFF, (max_pic_index + 1) * sizeof(int));
	for (i = 0; (unsigned int) i < picfile_header.images; i++) {
		pic_index[picture_directory[i].image_number] = i;
	}
    return (0);

}/* read_picture_data */


void get_huffman_dictionary()
{
	unsigned long fpos;
	int maxentry, curentry;
	short entry;
	short *entryptr;
	
	fpos = ftell(picfile);
	maxentry = 1;
	curentry = 0;
	while (curentry++ <= maxentry) {
		entry = (signed char)read_byte(picfile);
		if (entry > 0) {
			maxentry = MAX(maxentry,entry + entry + 1);
		}
	}
	fseek(picfile, fpos, SEEK_SET);
	if (huffman_dictionary)
		DisposPtr((Ptr)huffman_dictionary);
	entryptr = huffman_dictionary = (void *)NewPtr(sizeof(short) * (maxentry+1));
	while (maxentry-- >= 0) {
		*entryptr++ = (signed char)read_byte(picfile);
	}
}

get_num_pictures(void)
{
	return max_pic_index;
} /* get_num_pictures */

int get_picture_size(zword_t picture_number, zword_t *w, zword_t *h)
{
	int picture_sequence;
	
	if (picture_directory == NULL)
		read_picture_data();

	if ((picture_number <= max_pic_index) &&
		((picture_sequence = pic_index[picture_number]) != -1)) {

		if (picture_directory[picture_sequence].image_number != picture_number) 
			DebugStr("\pMisindexed pictures");
		*w = picture_directory[picture_sequence].image_width;
		*h = picture_directory[picture_sequence].image_height;
		if (!(picture_directory[picture_sequence].image_flags&NOT_COLOR_DOUBLE)) {
			*w <<= 1;
			*h <<= 1;
		}
	}
	else {
		return FALSE;
	}
	return TRUE;
} /* get_picture_size */

RgnHandle pixmaptorgn(unsigned char *pixmap, int width, int height)
/* constructs a region containing the non-zero areas in the pixmap */
/* The region originates at 0,0 */
{
	unsigned char *row;
	unsigned char *rowflags;
	unsigned char current = 0;
	unsigned char row_num_flag;
	unsigned char emptyflag = 1;
	RgnHandle outputrgn;
	RgnPtr rgnptr;
	unsigned short *curptr;
	int i,j;
	int rgnleft, rgnright, rgntop, rgnbottom;
	
#define OUTPUT(w) { \
	if (((unsigned long)curptr - (unsigned long)rgnptr) == rgnptr->rgnSize) { \
		HUnlock((Handle)outputrgn); \
		SetHandleSize((Handle)outputrgn, rgnptr->rgnSize + 1024L); \
		HLock((Handle)outputrgn); \
		rgnptr = *outputrgn; \
		curptr = (unsigned short *)((unsigned long)rgnptr + rgnptr->rgnSize); \
		rgnptr->rgnSize += 1024L; \
	} \
	*curptr++ = w; \
}
	row = pixmap;
	rowflags = (unsigned char *)NewPtrClear((size_t)width + 1);
	
	outputrgn = (RgnHandle)NewHandle(sizeof(Region));
	HLock((Handle)outputrgn);
	rgnptr = *outputrgn;
	rgnptr->rgnBBox.top = 0;
	rgnptr->rgnBBox.left = 0;
	rgnptr->rgnBBox.bottom = height;
	rgnptr->rgnBBox.right = width;
	rgnleft = width;
	rgnright = 0;
	rgntop = height;
	rgnbottom = 0;
	rgnptr->rgnSize = sizeof(Region);
	curptr = (unsigned short *)(rgnptr+1);
	for (j = 0; j <= height; j++) {
		row_num_flag = 0;
		for (i = 0; i <= width; i++) {
			if (rowflags[i])
				current = !current;
			if ((((j == height) || (i == width))?0:(row[i]!=0)) != (current != 0)) {
				if (!row_num_flag) {
					OUTPUT(j);
					row_num_flag = 1;
					emptyflag = 0;
				}
				OUTPUT(i);
				if (i > rgnright) rgnright = i;
				if (i < rgnleft) rgnleft = i;
				if (j < rgntop) rgntop = j;
				if (j > rgnbottom) rgnbottom = j;
				current = !current;
				rowflags[i] = !rowflags[i];
			}
		}
		if (row_num_flag)
			OUTPUT(0x7FFF);
		row += width;
	}

	if (!emptyflag) {
		OUTPUT(0x7FFF);
		rgnptr->rgnBBox.top = rgntop;
		rgnptr->rgnBBox.left = rgnleft;
		rgnptr->rgnBBox.bottom = rgnbottom;
		rgnptr->rgnBBox.right = rgnright;
	}
	DisposPtr((Ptr)rowflags);
	rgnptr->rgnSize = ((unsigned long)curptr - (unsigned long)rgnptr);
	SetHandleSize((Handle)outputrgn, (size_t)rgnptr->rgnSize);
	HUnlock((Handle)outputrgn);
	return outputrgn;
#undef OUTPUT
}

void os_draw_picture(x, y, n, reverse)
int x,y,n;
{
	zword_t w,h;
	int i,j,err;
	Rect r;
	BitMap bm;
	GrafPtr saveport;
	PenState p;
	RgnHandle rgn;
	RGBColor saved_fg, saved_bg;
	PixMapHandle mypmh;
    unsigned char *mypixels, *ipixels, *image;
	unsigned long rowbytes;
	GWorldPtr mygworld;
	CTabHandle myctab;
	colormap_t *colormap;
	RgnHandle maskrgn;
	
	w = picture_directory[pic_index[n]].image_width;
	h = picture_directory[pic_index[n]].image_height;
	r.left = x - 1 ;
	r.right = x - 1 + w;
	r.top = y - 1;
	r.bottom = y - 1 + h;
	GetPort(&saveport);
	SetPort(FrontWindow());
	bm.bounds = r;
	ipixels = image = get_image(picfile, &picture_directory[pic_index[n]]);
	bm.rowBytes = ((w+15)>>3)&~1;
	
#if 1
	maskrgn = pixmaptorgn(ipixels, w, h);
#else
	maskrgn = NewRgn();
	SetRectRgn(maskrgn, 0, 0, w, h);
#endif
	OffsetRgn(maskrgn, r.left, r.top);
	if (picfile_header.flags&NOT_COLOR_DOUBLE){
		bm.baseAddr = (void *)NewPtrClear(bm.rowBytes * (long)h);
	    for (i = 0, mypixels = (unsigned char *)bm.baseAddr; i < h; i++, ipixels+=w, mypixels+=bm.rowBytes) {
			for (j = 0; j < w; j++)
				mypixels[j/8] |= (ipixels[j]&1) << (7-(j&7));
	    }
	}
	else {
		colormap = get_color_table(picfile, &picture_directory[pic_index[n]]);
		
		if (colormap != NULL) {
			myctab = (CTabHandle)NewHandleClear(sizeof(ColorTable) + sizeof(CSpecArray)*(colormap->num_colors+1));
			(**myctab).ctSeed = GetCTSeed();
			(**myctab).ctSize = colormap->num_colors + 1;
			(**myctab).ctFlags |= 0x8000;
			(**myctab).ctTable[0].rgb.red   =   0xFFFF;
			(**myctab).ctTable[0].rgb.green =   0xFFFF;
			(**myctab).ctTable[0].rgb.blue  =   0xFFFF;
			(**myctab).ctTable[1].rgb.red   =   0;
			(**myctab).ctTable[1].rgb.green =   0;
			(**myctab).ctTable[1].rgb.blue  =   0;
			for (i = 2; i < (colormap->num_colors + 2); i++) {
				(**myctab).ctTable[i].rgb.red   =   colormap->table[i-2][RED]<<8;
				(**myctab).ctTable[i].rgb.green =   colormap->table[i-2][GREEN]<<8;
				(**myctab).ctTable[i].rgb.blue  =   colormap->table[i-2][BLUE]<<8;
			}
			DisposPtr((Ptr)colormap);
		}
		else {
			myctab = NULL;
		}
		
		err = NewGWorld(&mygworld, 8, &r, myctab /*CTable*/,
		/*GDevice*/NULL, keepLocal|useTempMem);
		
	    DisposHandle((Handle)myctab);
	    mypmh = GetGWorldPixMap(mygworld);
		LockPixels(mypmh);
		rowbytes = (**mypmh).rowBytes&0x3FFF;
	    mypixels = (unsigned char *)GetPixBaseAddr(mypmh);
	   
	    for (i = 0; i < h; i++, ipixels+=w, mypixels+=rowbytes) {
			memcpy(mypixels, ipixels, w);
	    }
	}
    DisposPtr((Ptr)image);
	get_picture_size(n, &w, &h); /* this takes any doubling into account.  Who made up this stuff? */
	r.left = x - 1 ;
	r.right = x - 1 + w;
	r.top = y - 1;
	r.bottom = y - 1 + h;
	
		
    GetForeColor(&saved_fg);
    GetBackColor(&saved_bg);
    ForeColor(blackColor);
    BackColor(whiteColor);
	OffsetRect(&r, BORDER, BORDER);
	MapRgn(maskrgn, &bm.bounds, &r);
	if (picfile_header.flags&NOT_COLOR_DOUBLE){
		CopyBits(&bm, &qd.thePort->portBits, &bm.bounds, &r, srcCopy, maskrgn);
	}
	else {
		CopyBits((BitMap *)*mypmh, &qd.thePort->portBits, &bm.bounds, &r, srcCopy, maskrgn);
	}
	ValidRect(&r);
#if 0
	GetPenState(&p);
	PenMode(patCopy);
	rgn = NewRgn();
	RectRgn(rgn, &r);
	FillRgn(rgn, qd.gray);
	FrameRgn(rgn);
	DisposeRgn(rgn);
	SetPenState(&p);
#endif
    RGBForeColor(&saved_fg);
    RGBBackColor(&saved_bg);
	DisposeHandle((Handle)maskrgn);
	if (picfile_header.flags&NOT_COLOR_DOUBLE) {
		DisposPtr(bm.baseAddr);
	}
	else {
		UnlockPixels(mypmh);
		DisposeGWorld(mygworld);
	}
	SetPort(saveport);
}

void os_erase_picture(x, y, n)
int x,y,n;
{
	zword_t w,h;
	Rect r;
	GrafPtr saveport;
	PenState p;
	
	get_picture_size(n, &w, &h);
	r.left = x - 1 ;
	r.right = x - 1 + w;
	r.top = y - 1;
	r.bottom = y - 1 + h;
	GetPort(&saveport);
	SetPort(FrontWindow());
	GetPenState(&p);
	PenMode(patCopy);
	OffsetRect(&r, BORDER, BORDER);
	EraseRect(&r);
	SetPenState(&p);
	SetPort(saveport);
}

#if defined(__STDC__)
static colormap_t *get_color_table(FILE *fp, pdirectory_t *directory)
#else
static colormap_t *get_color_table (fp, directory)
FILE *fp;
pdirectory_t *directory;
#endif
{
	colormap_t *result = NULL;
	unsigned char num_colors;
	int i;
	static unsigned char last_colourmap[16][3] = {
	          0,  0,  0,
	          0,  0,170,
	          0,170,  0,
	          0,170,170,
	        170,  0,  0,
	        170,  0,170,
	        170,170,  0,
	        170,170,170,
	         85, 85, 85,
	         85, 85,255,
	         85,255, 85,
	         85,255,255,
	        255, 85, 85,
	        255, 85,255,
	        255,255, 85,
	        255,255,255
	};

	num_colors=0;
   	if (directory->image_cm_addr) {
        if (fseek (fp, directory->image_cm_addr, SEEK_SET) != 0) {
            perror ("fseek");
            exit (EXIT_FAILURE);
        }
        num_colors = read_byte (fp);
    }
 	result = (void *)NewPtr(sizeof(colormap_t) + (sizeof(color_t) * ((short)MAX(num_colors,16) - 1)));
    for (i = 0; i < num_colors; i++) {
   		result->table[i][RED] = read_byte (fp);
    	result->table[i][GREEN] = read_byte (fp);
    	result->table[i][BLUE] = read_byte (fp);
    	if (i < 16) {
	        last_colourmap[i][RED] = result->table[i][RED];
	       	last_colourmap[i][GREEN] = result->table[i][GREEN];
	       	last_colourmap[i][BLUE] = result->table[i][BLUE];
    	}
   	}
   	for (i = num_colors; i < 16; i++) {
       	result->table[i][RED] = last_colourmap[i][RED];
       	result->table[i][GREEN] = last_colourmap[i][GREEN];
       	result->table[i][BLUE] = last_colourmap[i][BLUE];
    }
    result->num_colors = (num_colors<16)?16:num_colors;
    return result;
}

#if defined(__STDC__)
static void *get_image (FILE *fp, pdirectory_t *directory)
#else
static void *get_image (fp, directory)
FILE *fp;
pdirectory_t *directory;
#endif
{
    int colours = 18, i;
    image_t image;
    unsigned long image_compsize, image_numcodes;
    char *comp_image;

#if 0
    for (i = 0; i < 32; i++) {
        colourmap[i][RED] = ega_colourmap[i][RED];
        colourmap[i][GREEN] = ega_colourmap[i][GREEN];
        colourmap[i][BLUE] = ega_colourmap[i][BLUE];
    }
    if (directory->image_cm_addr) {
        if (fseek (fp, directory->image_cm_addr, SEEK_SET) != 0) {
            perror ("fseek");
            exit (EXIT_FAILURE);
        }
        colours = read_byte (fp);
        read_bytes (fp, colours * 3, &colourmap[2][RED]);
        colours += 2;
    }

#endif
/*    fprintf (stderr, "Number = %5d, width = %5d, height = %5d, flags = %4x, colourmap = %6ld, data = %6ld, colours = %2d\n",
            (int) directory->image_number, (int) directory->image_width, (int) directory->image_height,
            (int) directory->image_flags, directory->image_cm_addr, directory->image_data_addr, colours);
*/
    if (directory->image_data_addr == 0)
        return;

    image.width = directory->image_width;
    image.height = directory->image_height;
    image.colours = colours;
    image.pixels = 0;
    if ((image.image = (unsigned char *) NewPtr ((size_t)directory->image_width * directory->image_height)) == NULL) {
        fprintf (stderr, "Insufficient memory\n");
        exit (EXIT_FAILURE);
    }
#if 0
    image.colourmap = colourmap;
#endif


	if (directory->image_flags & HUFFMAN_FLAG) {
		if (!(picfile_header.flags & HUFFMAN_ONEDICT)) {
	    	if (fseek (fp, 2L * directory->huffman_dict_addr, SEEK_SET) != 0) {
	    	    perror ("fseek");
				exit (EXIT_FAILURE);
			}
			get_huffman_dictionary();
	  	}
	    if (fseek (fp, directory->image_data_addr, SEEK_SET) != 0) {
	        perror ("fseek");
	        exit (EXIT_FAILURE);
	    }
	    if (fseek (fp, directory->image_data_addr, SEEK_SET) != 0) {
	        perror ("fseek");
	        exit (EXIT_FAILURE);
	    }
		image_compsize = 0;
		image_numcodes = 0;
		fread((char *)&image_compsize + 1, 3, 1, fp);
		fread((char *)&image_numcodes + 1, 3, 1, fp);
		comp_image = (void *)NewPtr(image_compsize);
		fread((char *)comp_image, 1, image_compsize, fp);
	
		unpack_image((unsigned char *)comp_image, (unsigned char *)image.image,
						directory->image_width, image_numcodes, (size_t)directory->image_width * directory->image_height);
	/*    decompress_image (fp, &image);*/
		DisposPtr((Ptr)comp_image);
	}
    return (image.image);

}/* get image */

#define GETBIT(b,p) ((((unsigned char *)(p))[(b)>>3])&(1<<(7-((b)&7))))
unpack_image(unsigned char *in, unsigned char *out, int width, long numcodes, size_t booga)
{
	unsigned long bit=0;
	signed char entry, temp;
	signed char state = 0;
	char *lines, *lastptr, *curptr;

	lines = (void *)NewPtrClear(2 * width);
	lastptr = lines;
	curptr = lines+width;
	entry = 0;
	do {
		if (GETBIT(bit, in))
			entry++;
		entry = huffman_dictionary[((unsigned char)entry)];
		if (entry >= 0) {
			entry += entry;
		}
		else {
			entry -= 0x90;
			if (entry < 0) {
				entry += 0x10;
				/* here's the wierd XOR with entry */
				temp = entry ^ *lastptr++;
				*out++ = temp;
				*curptr++ = temp;
				if (lastptr == lines+width) {
					lastptr = lines;
					curptr = lines+width;		
					memcpy(lastptr, curptr, width);		
				}
				state = entry;
			}
			else {
				do {
				/* here's the wierd XOR with state */
					temp = state ^ *lastptr++;
					*curptr++ = temp;
					*out++ = temp;
					if (lastptr == lines+width) {
						lastptr = lines;
						curptr = lines+width;		
						memcpy(lastptr, curptr, width);		
					}
				} while (--entry != -1);
			}
			entry = 0;
			numcodes--;
		}
		bit++;
	}
	while (numcodes > 0);
	DisposPtr((Ptr)lines);
}

#if defined(__STDC__)
static void decompress_image (FILE *fp, image_t *image)
#else
static void decompress_image (fp, image)
FILE *fp;
image_t *image;
#endif
{
    int i;
    short code, old = 0, first, clear_code;
    compress_t comp;

    clear_code = 1 << CODE_SIZE;
    comp.next_code = clear_code + 2;
    comp.slen = 0;
    comp.sptr = 0;
    comp.tlen = CODE_SIZE + 1;
    comp.tptr = 0;

    for (i = 0; i < CODE_TABLE_SIZE; i++) {
        code_table[i][PREFIX] = CODE_TABLE_SIZE;
        code_table[i][PIXEL] = i;
    }

    for (;;) {
        if ((code = read_code (fp, &comp)) == (clear_code + 1))
            return;
        if (code == clear_code) {
            comp.tlen = CODE_SIZE + 1;
            comp.next_code = clear_code + 2;
            code = read_code (fp, &comp);
        } else {
            first = (code == comp.next_code) ? old : code;
            while (code_table[first][PREFIX] != CODE_TABLE_SIZE)
                first = code_table[first][PREFIX];
            code_table[comp.next_code][PREFIX] = old;
            code_table[comp.next_code++][PIXEL] = code_table[first][PIXEL];
        }
        old = code;
        i = 0;
        do
            buffer[i++] = (unsigned char) code_table[code][PIXEL];
        while ((code = code_table[code][PREFIX]) != CODE_TABLE_SIZE);
        do
            image->image[image->pixels++] = buffer[--i];
        while (i > 0);
    }

}/* decompress_image */

#if defined(__STDC__)
static short read_code (FILE *fp, compress_t *comp)
#else
static short read_code (fp, comp)
FILE *fp;
compress_t *comp;
#endif
{
    short code, bsize, tlen, tptr;
    int i;
    short sw;

    code = 0;
    tlen = comp->tlen;
    tptr = 0;

    while (tlen) {
        if (comp->slen == 0) {
            if ((comp->slen = fread (code_buffer, 1, MAX_BIT, fp)) == 0) {
                perror ("fread");
                exit (EXIT_FAILURE);
            }
            comp->slen *= 8;
            comp->sptr = 0;
        }
        bsize = ((comp->sptr + 8) & ~7) - comp->sptr;
        bsize = (tlen > bsize) ? bsize : tlen;
        code |= ((code_buffer[comp->sptr >> 3] >> (comp->sptr & 7)) & mask[bsize]) << tptr;

        tlen -= bsize;
        tptr += bsize;
        comp->slen -= bsize;
        comp->sptr += bsize;
    }
    if ((comp->next_code == mask[comp->tlen]) && (comp->tlen < 12))
        comp->tlen++;

    return (code);

}/* read_code */

