#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 */