/* gifread.c given a filename.gif, alpha, returns width, height, rgb pixels */
/*     int width, height; int alpha=0 to 255, or -1 for just rgb            */
/*     unsigned char pixels[4*width*height]; or 3*width*height for alpha=-1 */
/* call:  status = gifread("your-filename", alpha, &width, &height, pixels);*/
/* status==0 for OK                                                         */

#include "gif.h"
#include <stdio.h>
#include <stdlib.h>

static FILE *fpGif;        /* Pointer to the input FILE stream, global for decoder  */
static int bad_code_count; /* set by decoder */
static int gifReadHead(char gifFileName[], BYTE rgbpix[]);
static short int gif_decode(short int linewidth, BYTE rgbpix[]);
static int nrgbpix;
static int debug = 0; /* set to 1 for full debug printout */
static int line_num;
static int ipass;
static int rgba=0;
static int alph;

static GIFHEAD           gifHead;           /* GIF Header structure            */
static GIFIMAGEDESC      gifImageDesc;      /* Logical Image Descriptor struct */

#define OUT_OF_MEMORY -10
#define BAD_CODE_SIZE -20
#define READ_ERROR -1
#define WRITE_ERROR -2
#define OPEN_ERROR -3
#define CREATE_ERROR -4

int gifread(char filename[], int alpha, int *width, int *height, BYTE rgbpix[])
{
  int status;
  
  line_num = 0; /* needed for multiple calls in one program */
  nrgbpix = 0;
  ipass = 1;    /* pass number of interlace */
  rgba = 0;
  if(alpha>=0 && alpha<=255) { rgba = 1; alph = alpha; } /* 4 bytes per pixel */
  
  status = gifReadHead(filename, rgbpix);
  *width  = gifImageDesc.ImageWidth;
  *height = gifImageDesc.ImageHeight; 
  return status;
} /* end gifread */

static int gifReadHead(char gifFileName[], BYTE rgbpix[])
{
    WORD i, j;              /* Loop counter                                 */
    WORD tableSize;         /* Number of entires in the global color table  */
    WORD lineCount;         /* Count of the number of table lines displayed */
    WORD imageCount;        /* Count of the number of images in the file    */
    WORD blockCount;        /* Running count of the number of data blocks   */
    BYTE Identifier;        /* Extension block identifier holder            */
    BYTE Label;             /* Extension block label holder                 */
    BYTE dataSize;          /* Size of data sub-block holder                */
    int  blkSize;           /* Data block byte count, (int) of above        */
    BYTE dataBlock[256];    /* Hold a data block                            */
    BYTE *ptr;              /* Scratch pointer variable                     */
    BYTE code_size;
    short int err;

    GIFPLAINTEXT      gifPlainText;      /* Plain Text Extension structure  */
    GIFAPPLICATION    gifApplication;    /* Application Extension structure */
    GIFCOMMENT        gifComment;        /* Comment Extension structure     */
    GIFGRAPHICCONTROL gifGraphicControl; /* Graphic Control Extension strct */

    if(debug)printf("gifhead - Display the header info within a GIF image file \n");

    /* Open the GIF image file */
    if ((fpGif = fopen(gifFileName, "rb")) == (FILE *) NULL)
    {
        printf("gifhead: Cannot open file %s\n", gifFileName);
        return -1;
    }

    /* Read the GIF image file header information */
    ReadGifHeader(&gifHead, fpGif);

    /* Check for FILE stream error */
    if (ferror(fpGif))
    {
        printf("gifhead: Error reading header information!\n");
        return -1;
    }

    if(debug)printf("                       Signature: %.*s\n",
      sizeof(gifHead.Signature), gifHead.Signature);

    if(debug)printf("                         Version: %.*s\n",
      sizeof(gifHead.Version), gifHead.Version);

    if(debug)printf("                     ScreenWidth: %u\n", gifHead.ScreenWidth);
    if(debug)printf("                    ScreenHeight: %u\n", gifHead.ScreenHeight);

    if(debug)printf("           Global Color Table is: %s\n",
      gifHead.PackedField & 0x80 ? "Present" : "Not Present");
    
    if(debug)printf("             Original Resolution: %u (%u bits per primary color)\n",
       (gifHead.PackedField & 0x70) >> 4,
      ((gifHead.PackedField & 0x70) >> 4) + 1);
    
    if(debug)printf("           Global Color Table is: %s\n",
      gifHead.PackedField & 0x08 ? "Sorted" : "Not Sorted");
    
    if(debug)printf("      Size of Global Color Table: %lu entries (%lu bytes)\n",
      1L << ((gifHead.PackedField & 0x07) + 1),
      3L * (1L << ((gifHead.PackedField & 0x07) + 1)));
    
    if(debug)printf("Size of Global Color Table Entry: %u bits per pixel\n",
      (gifHead.PackedField & 0x07) + 1);
    
    if(debug)printf("          Background Color Index: %u\n", gifHead.ColorIndex);
    if(debug)printf("              Pixel Aspect Ratio: %u\n", gifHead.AspectRatio);

    /*
    ** Read and display the global color table if present.
    */
    if (gifHead.PackedField & 0x80)
    {
        lineCount = 0;  /* Count of the number of lines displayed */
        tableSize = (WORD) (1L << ((gifHead.PackedField & 0x07) + 1));

        if(debug)puts("\n\n\t\t\t\tGlobal Color Table\n");
        if(debug)printf("Color  Red Grn Blu  Color  Red Grn Blu  Color");
        if(debug)printf(" Red Grn Blu  Color  Red Grn Blu\n");

        /* Display the palette values */
        for (i = 0; i < tableSize; i++)
        {
            if(debug)printf(" %3d   %03u %03u %03u",
              i,
              gifHead.GlobalCT[i].Red,
              gifHead.GlobalCT[i].Green,
              gifHead.GlobalCT[i].Blue);

            /* Four entries per row */
            if (i && i % 4 == 3)
            {
                if(debug)putchar('\n');
                lineCount++;
            }
            else
                if(debug)fputs("  ", stdout);

            if (lineCount == 22)
            {
                if(debug)printf("\n\nColor  Red Grn Blu  Color  Red Grn Blu");
                if(debug)printf("  Color  Red Grn Blu  Color  Red Grn Blu\n");
                lineCount = 0;
            }
        }
    }

    /*
    ** Identify, read, and display block information.
    */
    imageCount = 0;     /* Clear the image counter */

    for (;;)
    {
        Identifier = GetByte(fpGif);

        switch (Identifier)
        {
            case 0x3B:  /* Trailer */
                if(debug)printf("\n\nGIF Trailer found (end of GIF image file).\n\n");
                fclose(fpGif);
                return(0);
            case 0x2C:  /* Image Descriptor */
                gifImageDesc.ImageSeparator = Identifier;
                if (ReadGifImageDesc(&gifImageDesc, fpGif) == -1)
                    fputs("Error reading Image Descriptor information\n", stderr);
                imageCount++;

                if(debug)printf("\n\nImage Descriptor for Image %d\n\n",
                  imageCount);
                if(debug)printf("            Image Left Position: %u\n",
                  gifImageDesc.ImageLeft);     
                if(debug)printf("             Image Top Position: %u\n",
                  gifImageDesc.ImageTop);      
                if(debug)printf("                    Image Width: %u\n",
                  gifImageDesc.ImageWidth);
                if(debug)printf("                   Image Height: %u\n",
                  gifImageDesc.ImageHeight);
                if(debug)printf("           Local Color Table is: %s\n",
                  gifImageDesc.PackedField & 0x80 ? "Present" : "Not Present");
                if(debug)printf("  Local Color Table Entries are: %s\n",
                  gifImageDesc.PackedField & 0x20 ? "Sorted" : "Not Sorted");
                if(debug)printf("                       Image is: %sInterlaced\n",
                  gifImageDesc.PackedField & 0x40 ? "" : "Not ");
                if(debug)printf("                       Reserved: %u\n",
                  (gifImageDesc.PackedField & 0x18) >> 3);
                if(debug)printf("      Size of Local Color Table: %lu entries (%lu bytes)\n",
                  1L << ((gifImageDesc.PackedField & 0x07) + 1),
                  3L * (1L << ((gifImageDesc.PackedField & 0x07) + 1)));
                if(debug)printf("Size of Local Color Table Entry: %u bits per pixel\n",
                  (gifImageDesc.PackedField & 0x07) + 1);

                /*
                ** Read and display local color table, if present.
                */
                if (gifImageDesc.PackedField & 0x80)
                {
                    lineCount = 0;  /* Count of the number of lines displayed */
                    tableSize =
                      (WORD) (1L << ((gifImageDesc.PackedField & 0x07) + 1));

                    if(debug)puts("\n\n\t\t\t\tLocal Color Table\n");
                    if(debug)printf("Color  Red Grn Blu  Color  Red Grn Blu");
                    if(debug)printf("  Color  Red Grn Blu  Color  Red Grn Blu\n");

                    /* Display the palette values */
                    for (i = 0; i < tableSize; i++)
                    {
                        if(debug)printf(" %3d   %03u %03u %03u",
                          i,
                          gifImageDesc.LocalCT[i].Red,
                          gifImageDesc.LocalCT[i].Green,
                          gifImageDesc.LocalCT[i].Blue);

                        /* Four entries per row */
                        if (i && i % 4 == 3)
                        {
                            if(debug)putchar('\n');
                            lineCount++;
                        }
                        else
                            if(debug)fputs("  ", stdout);

                        if (lineCount == 22)
                        {
                            if(debug)printf("\n\nColor  Red Grn Blu  Color  Red Grn Blu");
                            if(debug)printf("  Color  Red Grn Blu  Color  Red Grn Blu\n");
                            lineCount = 0;
                        }
                    }
                    if(debug)puts("\n");
                }

                /*
                ** Skip past the encoded image data.
                */
                if(debug)printf(" Image data: doing via gif_decode.c \n");
                err=gif_decode(gifImageDesc.ImageWidth, rgbpix);
                err=GetByte(fpGif); /* final zero block */

                if(debug)printf("gif_decode returned err=%d, bad_code_count=%d\n",
                       (int)err, (int)bad_code_count);
                break;
            case 0x21:  /* Extension Block */  
                Label = GetByte(fpGif);
                switch (Label)
                {
                    case 0x01:  /* Plain Text Extension */
                        if(debug)puts("\n\nPlain Text Extension\n");
                        gifPlainText.Introducer = Identifier;
                        gifPlainText.Label = Label;
                        if (ReadGifPlainText(&gifPlainText, fpGif))
                            fprintf(stderr,
                              "Error reading Plain Text Extension information.\n");

                        if(debug)printf("                  Block Size: %u\n",
                          gifPlainText.BlockSize);
                        if(debug)printf("     Text Grid Left Position: %u\n",
                          gifPlainText.TextGridLeft);
                        if(debug)printf("    Text Grid Right Position: %u\n",
                          gifPlainText.TextGridTop);
                        if(debug)printf("             Text Grid Width: %u\n",
                          gifPlainText.TextGridWidth);
                        if(debug)printf("            Text Grid Height: %u\n",
                          gifPlainText.TextGridHeight);
                        if(debug)printf("        Character Cell Width: %u\n",
                          gifPlainText.CellWidth);
                        if(debug)printf("       Character Cell Height: %u\n",
                          gifPlainText.CellHeight);
                        if(debug)printf(" Text Foreground Color Index: %u\n",
                          gifPlainText.TextFgColorIndex);
                        if(debug)printf(" Text Background Color Index: %u\n",
                          gifPlainText.TextBgColorIndex);
      
                        /* Display Plain Text Data */
                        ptr = gifPlainText.PlainTextData;
                        while ((dataSize = *ptr++) != 0)
                        {
                            if(debug)printf("\nSize of Plain Text sub-block: %u\n",
                              dataSize);
                            if(debug)puts("\nText:");
                            while (dataSize--)
                                if(debug)fputc(*ptr++, stdout);
                            if(debug)putchar('\n');
                        }
                        break;
                    case 0xFE:  /* Comment Extension */
                        if(debug)puts("\n\nComment Extension");
                        gifComment.Introducer = Identifier;
                        gifComment.Label = Label;

                        if (ReadGifComment(&gifComment, fpGif))
                            fprintf(stderr,
                              "Error reading Comment Extension information\n");

                        /* Display Comment Data */
                        ptr = gifComment.CommentData;
                        while ((dataSize = *ptr++) != 0)
                        {
                            if(debug)printf("\nSize of Comment sub-block: %u\n", dataSize);
                            if(debug)puts("\nComment:");
                            while (dataSize--)
                                if(debug)fputc(*ptr++, stdout);
                            if(debug)putchar('\n');
                        }
                        break;
                    case 0xF9:  /* Graphic Control Extension */
                        if(debug)puts("\n\nGraphics Control Extension\n");
                        gifGraphicControl.Introducer = Identifier;
                        gifGraphicControl.Label = Label;
                        if (ReadGifGraphicControl(&gifGraphicControl, fpGif))
                            fprintf(stderr,
                              "Error reading Graphic Control Extension information\n");
                        if(debug)printf("             Block Size: %u\n",
                          gifGraphicControl.BlockSize);
                        if(debug)printf("               Reserved: %u\n",
                          (gifGraphicControl.PackedField & 0xE0) >> 5);
                        if(debug)printf("        Disposal Method: %u ",
                          (gifGraphicControl.PackedField & 0x1D) >> 2);
                        switch((gifGraphicControl.PackedField & 0x1D) >> 2)
                        {
                            case 0x00:
                                if(debug)puts("(No Disposal Method Defined)");
                                break;
                            case 0x01:
                                if(debug)puts("(Do Not Dispose)");
                                break;
                            case 0x02:
                                if(debug)puts("(Restore to Background Color)");
                                break;
                            case 0x03:
                                if(debug)puts("(Restore to Previous Graphic)");
                                break;
                            default:
                                if(debug)puts("(To Be Defined)");
                        }
                        if(debug)printf("        User Input Flag: User Input is %sExpected\n",
                          gifGraphicControl.PackedField & 0x02 ? "" : "Not ");
                        if(debug)printf(" Transparent Color Flag: Color Index Is %sPresent\n",
                          gifGraphicControl.PackedField & 0x01 ? "" : "Not ");

                        if(debug)printf("             Delay Time: %u\n",
                          gifGraphicControl.DelayTime);
                        if(debug)printf("Transparent Color Index: %u\n",
                          gifGraphicControl.ColorIndex);

                        /* Display Graphic Control Information */
                        while ((dataSize = GetByte(fpGif)) != 0)
                        {
                            if(debug)printf("\nSize of Graphic Control sub-block: %u\n",
                              dataSize);
                            if(debug)puts("Graphic Control Information:");
                            for (i = 0; i < dataSize; i++)
                                if(debug)fputc(GetByte(fpGif), stdout);
                            if(debug)putchar('\n');
                        }
                        break;
                    case 0xFF:  /* Application Extension */
                        if(debug)puts("\n\nApplication Extension\n");
                        gifApplication.Introducer = Identifier;
                        gifApplication.Label = Label;

                        if (ReadGifApplication(&gifApplication, fpGif))
                            fprintf(stderr,
                              "Error reading Application Extension information\n");

                        if(debug)printf("Block Size: %u\n", gifApplication.BlockSize);
                        if(debug)printf("Application Identifier: %*u\n",
                            sizeof(gifApplication.Identifier),
                            gifApplication.Identifier);
                        if(debug)printf("Authentication Code: %*u\n",
                            sizeof(gifApplication.AuthentCode),
                            gifApplication.AuthentCode);

                        /* Display Application Data */
                        ptr = gifApplication.ApplicationData;
                        while ((dataSize = *ptr++) != 0)
                        {
                            if(debug)printf("\nSize of Application sub-block: %u\n", dataSize);
                            if(debug)puts("\nApplication Data:");
                            while (dataSize--)
                                if(debug)fputc(*ptr++, stdout);
                            if(debug)putchar('\n');
                        }
                        break;
                    default:
                        if(debug)printf("\n\nUnknown Extension Label: 0x%02x\n", Label);
                        break;
                }
                break;
            default:
                fprintf(stderr, "\n\nUnknown Block Separator Character: 0x%02x\n\n",
                  Identifier);
                fclose(fpGif);
                return(-1);
        }
    }
} /* end gifHead */

/* gif_decode.c - An LZW decoder for GIF    JSS mods                       */
/* Copyright (C) 1987, by Steven A. Bennett                                */
/* Permission is given by the author to freely redistribute and include    */
/* this code in any program as long as this credit is given where due.     */
/* In accordance with the above, I want to credit Steve Wilhite who wrote  */
/* the code which this is heavily inspired by...                           */
/*                                                                         */
/* GIF and 'Graphics Interchange Format' are trademarks (tm) of            */
/* Compuserve, Incorporated, an H&R Block Company.                         */
/*                                                                         */
/* Release Notes: This file contains a decoder routine for GIF images      */
/* which is similar, structurally, to the original routine by Steve Wilhite*/
/* It is, however, somewhat noticably faster in most cases.                */


/*  Various error codes used by decode.c */

/* extern int get_byte(); replaced by  getc(fpGif)                  */
/* This external (machine specific) function is expected to return  */
/* either the next byte from the GIF file, or a negative number, as */
/* defined in above errors                                          */


/* extern int out_line(BYTE pixels[], int linelen, BYTE rgbpix[]); Now here. */
/* This function takes a full line of pixels (one byte per pixel) and        */
/* displays them (or does whatever your program wants with them...).  It     */
/* should return zero, or negative if an error or some other event occurs    */
/* which would require aborting the decode process...  Note that the length  */
/* passed will almost always be equal to the line length passed to the       */
/* decoder function, with the sole exception occurring when an ending code   */
/* occurs in an odd place in the GIF file...  In any case, linelen will be   */
/* equal to the number of pixels passed...                                   */

int out_line(BYTE pixels[], int linelen, BYTE rgbpix[]) /* JSS */
{
  int i, j;
  BYTE r, g, b;
  int enough=26;
  int w, h, hw, x, y;
  
  w = gifImageDesc.ImageWidth;
  h = gifImageDesc.ImageHeight;
  if(rgba) { hw = 4*h*w; x = 4*w; }
  else     { hw = 3*h*w; x = 3*w; }
  line_num++; /* number, not subscript */

  for(i=0; i<linelen; i++)
  {
    if(i%enough==0) if(debug)printf("\n");
    if(debug)printf("%d ", (int)pixels[i]);
  }
  if(debug)printf("\n");
  y = hw-x*(2*(nrgbpix/x)+1);   /* invert image y */
  if(debug)printf("out_line %d with length=%d, nrgbpix=%d, y=%d \n",
         line_num, linelen, nrgbpix, y);
  for(i=0; i<linelen; i++)
  {
    j = (int)pixels[i];
    /* have index into color table, now get colors */
    r = gifHead.GlobalCT[j].Red;
    g = gifHead.GlobalCT[j].Green;
    b = gifHead.GlobalCT[j].Blue;
    if(debug)printf("r=%03u, g=%03u, b=%03u, row=%d, col=%d, inv=%d \n",
           r, g, b, line_num, i, y+nrgbpix);
    rgbpix[y+nrgbpix] = r;   /* invert y */
    rgbpix[y+nrgbpix+1] = g;
    rgbpix[y+nrgbpix+2] = b;
    if(rgba) { rgbpix[y+nrgbpix+3] = alph; nrgbpix += 4; }
    else     {                             nrgbpix += 3; }
  }
  if(gifImageDesc.PackedField & 0x40)
  {
    if(ipass==4)
    {
      nrgbpix = nrgbpix + x;       /* every other */
    }
    if(ipass==3)
    {
      nrgbpix = nrgbpix + (4-1)*x; /* every fourth */
      if(nrgbpix>=hw)
      {
        ipass = 4;
        nrgbpix = x;               /* start row 1 */
      }
    }
    if(ipass==2)
    {
      nrgbpix = nrgbpix + (8-1)*x; /* every eighth */
      if(nrgbpix>=hw)
      {
        ipass = 3;
        nrgbpix = 2*x;             /* start row 2 */
      }
    }
    if(ipass==1)
    {
      nrgbpix = nrgbpix + (8-1)*x; /* every eighth */
      if(nrgbpix>=hw)
      {
        ipass = 2;
        nrgbpix = 4*x;             /* start row 4 */
      }
    }
  }
  return 0;
} /* end out_line */


/* extern int bad_code_count;                                               */
/* This value is the only other global required by the using program, and   */
/* is incremented each time an out of range code is read by the decoder.    */
/* When this value is non-zero after a decode, your GIF file is probably    */
/* corrupt in some way...                                                   */

#define MAX_CODES 4095

/* Static variables */
static WORD curr_size;                     /* The current code size */
static WORD clear;                         /* Value for a clear code */
static WORD ending;                        /* Value for a ending code */
static WORD newcodes;                      /* First available code */
static WORD top_slot;                      /* Highest code for current size */
static WORD slot;                          /* Last read code */

/* The following static variables are used */
/* for separating out codes */
static WORD navail_bytes = 0;              /* # bytes left in block */

static WORD nbits_left = 0;                /* # bits left in current byte */
static BYTE b1;                           /* Current byte */
static BYTE byte_buff[257];               /* Current block */
static BYTE *pbytes;                      /* Pointer to next byte in block */

static int code_mask[13] = {
     0,
     0x0001, 0x0003,
     0x0007, 0x000F,
     0x001F, 0x003F,
     0x007F, 0x00FF,
     0x01FF, 0x03FF,
     0x07FF, 0x0FFF
     };

/* This function initializes the decoder for reading a new image. */
static WORD init_exp(WORD size)
{
  if(debug)printf("gif_decode.c init_exp size=%d\n", (int)size);
  curr_size = size + 1;
  top_slot = 1 << curr_size;
  clear = 1 << size;
  ending = clear + 1;
  slot = newcodes = ending + 1;
  navail_bytes = nbits_left = 0;
  return(0);
} /* end init_exp */

/* get_next_code() */
/* - gets the next code from the GIF file.  Returns the code, or else */
/* a negative number in case of file errors... */
static WORD get_next_code()
{
  WORD i, x;
  int ret;
  if (nbits_left == 0)
  {
    if (navail_bytes <= 0)
    {
      /* Out of bytes in current block, so read next block */
      pbytes = byte_buff;
      if ((navail_bytes = getc(fpGif)) < 0)
      {
        printf("gif_decode.c get_next_code bad block size=%d\n",
               (int)navail_bytes);
        return navail_bytes;
      }
      else if (navail_bytes)
      {
        if(debug)printf("gif_decode.c get_next_code block size=%d\n",
               (int)navail_bytes);
        for (i = 0; i < navail_bytes; ++i)
        {
          if ((x = getc(fpGif)) < 0) return x;
          byte_buff[i] = x;
        }
      }
      else
      {
        printf("gif_decode.c get_next_code zero block size=%d\n",
               (int)navail_bytes);
      }
    }
    b1 = *pbytes++;
    nbits_left = 8;
    --navail_bytes;
  }
  ret = b1 >> (8 - nbits_left);
  while (curr_size > nbits_left)
  {
    if (navail_bytes <= 0)
    {
      /* Out of bytes in current block, so read next block */
      pbytes = byte_buff;
      if ((navail_bytes = getc(fpGif)) < 0) return(navail_bytes);
      else if (navail_bytes)
      {
        for (i = 0; i < navail_bytes; ++i)
        {
          if ((x = getc(fpGif)) < 0) return x;
          byte_buff[i] = x;
        }
      }
    }
    b1 = *pbytes++;
    ret |= b1 << nbits_left;
    nbits_left += 8;
    --navail_bytes;
  }
  nbits_left -= curr_size;
  ret &= code_mask[curr_size];
  /* printf("gif_decode.c get_next_code code=%d\n", (int)ret); */
  return (WORD)ret;
} /* end get_next_code */


/* The reason we have these seperated like this instead of using         */
/* a structure like the original Wilhite code did, is because this       */
/* stuff generally produces significantly faster code when compiled...   */
/* This code is full of similar speedups...  (For a good book on writing */
/* C for speed or for space optomisation, see Efficient C by Tom Plum,   */
/* published by Plum-Hall Associates...)                                 */

static BYTE stack[MAX_CODES + 1];            /* Stack for storing pixels */
static BYTE suffix[MAX_CODES + 1];           /* Suffix table */
static unsigned int prefix[MAX_CODES + 1];           /* Prefix linked list */


/* - This function decodes an LZW image, according to the method used      */
/* in the GIF spec.  Every *linewidth* "characters" (ie. pixels) decoded   */
/* will generate a call to out_line(), which is a user specific function   */
/* to display a line of pixels.  The function gets it's codes from         */
/* get_next_code() which is responsible for reading blocks of data and     */
/* seperating them into the proper size codes.  Finally, getc(fpGif) is*/
/* the global routine to read the next byte from the GIF file.             */

/* It is generally a good idea to have linewidth correspond to the actual  */
/* width of a line (as specified in the Image header) to make your own     */
/* code a bit simpler, but it isn't absolutely necessary.                  */
/* Returns: 0 if successful, else negative.  (See ERRS.H)                  */

static short int gif_decode(short int linewidth, BYTE rgbpix[])
   /* call with width, LZW initial code size, return is error code */
{
  register BYTE *sp, *bufptr;
  BYTE *buf;
  register WORD code, fc, oc, bufcnt;
  WORD c, size, ret;

  if(debug)printf("gif_decode.c linewidth=%d\n", (int)linewidth);
  /* Initialize for decoding a new image... */
  if ((size = getc(fpGif)) < 0) return size;
  if (size < 2 || 9 < size) return BAD_CODE_SIZE;
  init_exp(size);
  /* Initialize in case they forgot to put in a clear code.         */
  /* (This shouldn't happen, but we'll try and decode it anyway...) */
  oc = fc = 0;

  /* Allocate space for the decode buffer */
  if ((buf = (BYTE *)malloc(linewidth + 1)) == NULL) return OUT_OF_MEMORY;

  /* Set up the stack pointer and decode buffer pointer */
  sp = stack;
  bufptr = buf;
  bufcnt = linewidth;

  /* This is the main loop.  For each code we get we pass through the       */
  /* linked list of prefix codes, pushing the corresponding "character" for */
  /* each code onto the stack.  When the list reaches a single "character"  */
  /* we push that on the stack too, and then start unstacking each          */
  /* character for output in the correct order.  Special handling is        */
  /* included for the clear code, and the whole thing ends when we get      */
  /* an ending code.                                                        */
  while ((c = get_next_code()) != ending)
  {
    /* If we had a file error, return without completing the decode */
    if (c < 0)
    {
      free(buf);
      return 0;
    }
    /* If the code is a clear code, reinitialize all necessary items. */
    if (c == clear)
    {
      curr_size = size + 1;
      slot = newcodes;
      top_slot = 1 << curr_size;

      /* Continue reading codes until we get a non-clear code  */
      /* (Another unlikely, but possible case...)              */
      while ((c = get_next_code()) == clear) ;
      /* If we get an ending code immediately after a clear code  */
      /* (Yet another unlikely case), then break out of the loop. */
      if (c == ending) break;
      /* Finally, if the code is beyond the range of already set codes,  */
      /* (This one had better NOT happen...  I have no idea what will    */
      /* result from this, but I doubt it will look good...) then set it */
      /* to color zero.                                                  */
      if (c >= slot) c = 0;
      oc = fc = c;
      /* And let us not forget to put the char into the buffer... And  */
      /* if, on the off chance, we were exactly one pixel from the end */
      /* of the line, we have to send the buffer to the out_line()     */
      /* routine...                                                    */
      *bufptr++ = c;
      if (--bufcnt == 0)
      {
        if ((ret = out_line(buf, linewidth, rgbpix)) < 0)
        {
          free(buf);
          return(ret);
        }
        bufptr = buf;
        bufcnt = linewidth;
     }
  }
  else
  {
    /* In this case, it's not a clear code or an ending code, so        */
    /* it must be a code code...  So we can now decode the code into    */
    /* a stack of character codes. (Clear as mud, right?)               */
    code = c;
    /* Here we go again with one of those off chances...  If, on the    */
    /* off chance, the code we got is beyond the range of those already */
    /* set up (Another thing which had better NOT happen...) we trick   */
    /* the decoder into thinking it actually got the last code read.    */
    /* (Hmmn... I'm not sure why this works...  But it does...)         */
    if (code >= slot)
    {
      if (code > slot) ++bad_code_count;
      code = oc;
      *sp++ = fc;
    }
    /* Here we scan back along the linked list of prefixes, pushing     */
    /* helpless characters (ie. suffixes) onto the stack as we do so.   */
    while (code >= newcodes)
    {
      *sp++ = suffix[code];
      code = prefix[code];
    }
    /* Push the last character on the stack, and set up the new       */
    /* prefix and suffix, and if the required slot number is greater  */
    /* than that allowed by the current bit size, increase the bit    */
    /* size.  (NOTE - If we are all full, we *don't* save the new     */
    /* suffix and prefix...  I'm not certain if this is correct...    */
    /* it might be more proper to overwrite the last code...          */
    *sp++ = code;
    if (slot < top_slot)
    {
      suffix[slot] = fc = code;
      prefix[slot++] = oc;
      oc = c;
    }
    if (slot >= top_slot)
      if (curr_size < 12)
      {
        top_slot <<= 1;
        ++curr_size;
      } 

      /* Now that we've pushed the decoded string (in reverse order) */
      /* onto the stack, lets pop it off and put it into our decode  */
      /* buffer...  And when the decode buffer is full, write another*/
      /* line... */
      while (sp > stack)
      {
        *bufptr++ = *(--sp);
        if (--bufcnt == 0)
        {
          if ((ret = out_line(buf, linewidth, rgbpix)) < 0)
          {
            free(buf);
            return ret;
          }
          bufptr = buf;
          bufcnt = linewidth;
        }
      }
    }
  }
  ret = 0;
  if (bufcnt != linewidth) ret = out_line(buf, (linewidth - bufcnt), rgbpix);
  free(buf);
  return(ret);
} /* end gif_decode */

/* gif_io.c  implement low level I/O for Gif */ 

WORD GetWord(FILE *FpGif) /* little endian */
{
  int low, high; /* native machine */
  WORD word;
  low  = getc(FpGif);
  high = getc(FpGif);
  word = low;
  word = word+ (high<<8);
  return word;
} /* end GetWord */

BYTE GetByte(FILE *FpGif)
{
  return getc(FpGif);
} /* end GetByte */

DWORD GetDword(FILE *FpGif)
{
  int b1, b2, b3, b4; /* native machine */
  WORD word;
  b1   = getc(FpGif);
  b2   = getc(FpGif);
  b3   = getc(FpGif);
  b4   = getc(FpGif);
  word = b1;
  word = word + (b2<<8) + (b3<<16) + (b4<24);
  return word;
} /* end GetDword */

void GetString(char * str, int len, FILE *FpGif)
{
  int i;
  for(i=0; i<len; i++)
  {
    str[i] = (BYTE)getc(FpGif);
  }
} /* end GetString */

VOID  PutByte(BYTE x, FILE *FpGif)
{
  putc(x, FpGif);
} /* end PutByte */

void PutWord(WORD x, FILE *FpGif)
{
  BYTE low, high;
  low  = (BYTE)(x & 0xFF);
  high = (BYTE)(x>>8);
  putc(low, FpGif);
  putc(high, FpGif); 
} /* end PutWord */

void PutDword(DWORD x, FILE *FpGif)
{
  BYTE b1, b2, b3, b4;
  b1 = (BYTE)(x & 0xFF);
  b2 = (BYTE)( (x>>8) & 0xFF);
  b3 = (BYTE)( (x>>16) * 0xFF);
  b4 = (BYTE)(x>>24);
  putc(b1, FpGif);
  putc(b2, FpGif);
  putc(b3, FpGif);
  putc(b4, FpGif);
} /* end PutDword */

void PutString(char * str, int len, FILE *FpGif)
{
  int i;
  for(i=0; i<len; i++)
  {
    putc(str[i],FpGif);
  }
} /* end PutString */


/****************************************************************************\
**  This module contains six functions which read various data structures   **
**  stored in GIF 87a and 89a-format files.                                 **
**                                                                          **
**  This module contains the following functions:                           **
**                                                                          **
**      ReadGifHeader         - Read a GIF image file Header                **
**      ReadGifImageDesc      - Read a GIF Local Image Descriptor           **
**      ReadGifGraphicControl - Read a GIF Graphic Control Extension block  **
**      ReadGifPlainText      - Read a GIF Plain Text Extension block       **
**      ReadGifApplication    - Read a GIF Application Extension block      **
**      ReadGifComment        - Read a GIF Comment Extension block          **
**      ReadDataSubBlocks     - Read one or more GIF data sub-blocks        **
**                                                                          **
**  Copyright (C) 1991,92 by Graphics Software Labs.  All rights reserved.  **
\****************************************************************************/

/* Local function prototype */
BYTE *ReadDataSubBlocks(FILE *FpGif);

/*
**  Read a GIF image file Header.
**
**  This function reads the Header, Logical Screen Descriptor, and
**  Global Color Table (if any) from a GIF image file.  The information
**  is stored in a GIFHEAD structure.
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifHeader(GIFHEAD *GifHead,   /* Pointer to GIF header structure  */
              FILE    *FpGif)     /* GIF image file input FILE stream */
{
    register WORD i;    /* Loop counter                                */
    WORD tableSize;     /* Number of entires in the Global Color Table */

    /* GetWord = GetLittleWord;     Read using little-endian byte order */

    GetString(GifHead->Signature, sizeof(GifHead->Signature), FpGif);
    GetString(GifHead->Version, sizeof(GifHead->Version), FpGif);

    GifHead->ScreenWidth    = GetWord(FpGif);
    GifHead->ScreenHeight   = GetWord(FpGif);
    GifHead->PackedField    = GetByte(FpGif);
    GifHead->ColorIndex     = GetByte(FpGif);
    GifHead->AspectRatio    = GetByte(FpGif);

    /* Check if a Global Color Table is present */
    if (GifHead->PackedField & 0x80)
    {
        /* Read number of color table entries */
        tableSize = (WORD) (1L << ((GifHead->PackedField & 0x07) + 1));

        /* Read the Global Color Table */
        for (i = 0; i < tableSize; i++)
        {
            GifHead->GlobalCT[i].Red   = GetByte(FpGif);
            GifHead->GlobalCT[i].Green = GetByte(FpGif);
            GifHead->GlobalCT[i].Blue  = GetByte(FpGif);
        }
    }

    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0;          /* No FILE stream error occured */
}


/*
**  Read a GIF Local Image Descriptor.
**
**  This function reads the Local Image Descriptor, and Local Color
**  Table (if any) from a GIF image file.  The information is stored
**  in a GIFIMAGEDESC structure.
**
**  Note that the ImageSeparator field value in the GIFIMAGEDESC
**  structure is assigned by the function calling ReadGifImageDesc().
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifImageDesc(
  GIFIMAGEDESC *GifImageDesc, /* Pointer to GIF image descriptor structure */
  FILE         *FpGif)        /* GIF image file input FILE stream          */
{
    WORD i;                 /* Loop counter                               */
    WORD tableSize;         /* Number of entries in the Local Color Table */

    /* GetWord = GetLittleWord;    Read using little-endian byte order    */

    GifImageDesc->ImageLeft   = GetWord(FpGif);
    GifImageDesc->ImageTop    = GetWord(FpGif);
    GifImageDesc->ImageWidth  = GetWord(FpGif);
    GifImageDesc->ImageHeight = GetWord(FpGif);
    GifImageDesc->PackedField = GetByte(FpGif);

    /* Check if a Local Color Table is present */
    if (GifImageDesc->PackedField & 0x80)
    {
        /* Read number of color table entries */
        tableSize = (WORD) (1L << ((GifImageDesc->PackedField & 0x07) + 1));

        /* Read the Local Color Table */
        for (i = 0; i < tableSize; i++)
        {
            GifImageDesc->LocalCT[i].Red   = GetByte(FpGif);
            GifImageDesc->LocalCT[i].Green = GetByte(FpGif);
            GifImageDesc->LocalCT[i].Blue  = GetByte(FpGif);
        }
    }

    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0;          /* No FILE stream error occured */
}


/*
**  Read a GIF Graphic Control Extension block.
**
**  Note that the Introducer and Label field values in the GIFGRAPHICCONTROL
**  structure are assigned by the function calling ReadGifGraphicControl().
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifGraphicControl(
  GIFGRAPHICCONTROL *GifGraphicControl, /* Pointer to GC Extension structure */
  FILE              *FpGif)             /* GIF image file input FILE stream  */
{
    /* GetWord = GetLittleWord;   Read using little-endian byte order     */

    GifGraphicControl->BlockSize   = GetByte(FpGif);
    GifGraphicControl->PackedField = GetByte(FpGif);
    GifGraphicControl->DelayTime   = GetWord(FpGif);
    GifGraphicControl->ColorIndex  = GetByte(FpGif);

    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0;          /* No FILE stream error occured */
}


/*
**  Read a GIF Plain Text Extension block.
**
**  Note that the Introducer and Label field values in the GIFLPLAINTEXT
**  structure are assigned by the function calling ReadGifPlainText().
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifPlainText(
  GIFPLAINTEXT *GifPlainText, /* Pointer to Plain Text Extension structure */
  FILE         *FpGif)        /* GIF image file input FILE stream          */
{
    /* GetWord = GetLittleWord;    Read using little-endian byte order   */

    GifPlainText->BlockSize        = GetByte(FpGif);
    GifPlainText->TextGridLeft     = GetWord(FpGif);
    GifPlainText->TextGridTop      = GetWord(FpGif);
    GifPlainText->TextGridWidth    = GetWord(FpGif);
    GifPlainText->TextGridHeight   = GetWord(FpGif);
    GifPlainText->CellWidth        = GetByte(FpGif);
    GifPlainText->CellHeight       = GetByte(FpGif);
    GifPlainText->TextFgColorIndex = GetByte(FpGif);
    GifPlainText->TextBgColorIndex = GetByte(FpGif);

    /* Read in the Plain Text data sub-blocks */
    if (!(GifPlainText->PlainTextData = ReadDataSubBlocks(FpGif)))
        return 1;

    GifPlainText->Terminator       = 0;

    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0;          /* No FILE stream error occured */
}


/*
**  Read a GIF Application Extension block.
**
**  Note that the Introducer and Label field values in the GIFAPPLICATION
**  structure are assigned by the function calling ReadGifApplication().
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifApplication(
  GIFAPPLICATION *GifApplication, /* Pointer to Application Extension struct */
  FILE           *FpGif)          /* GIF image file input FILE stream        */
{
    GifApplication->BlockSize      = GetByte(FpGif);

    GifApplication->Identifier[0]  = GetByte(FpGif);
    GifApplication->Identifier[1]  = GetByte(FpGif);
    GifApplication->Identifier[2]  = GetByte(FpGif);
    GifApplication->Identifier[3]  = GetByte(FpGif);
    GifApplication->Identifier[4]  = GetByte(FpGif);
    GifApplication->Identifier[5]  = GetByte(FpGif);
    GifApplication->Identifier[6]  = GetByte(FpGif);
    GifApplication->Identifier[7]  = GetByte(FpGif);

    GifApplication->AuthentCode[0] = GetByte(FpGif);
    GifApplication->AuthentCode[1] = GetByte(FpGif);
    GifApplication->AuthentCode[2] = GetByte(FpGif);

    /* Read in the Plain Text data sub-blocks */
    if (!(GifApplication->ApplicationData = ReadDataSubBlocks(FpGif)))
        return(1);

    GifApplication->Terminator     = 0;

    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0;          /* No FILE stream error occured */
}


/*
**  Read a GIF Comment Extension block.
**
**  Note that the Introducer and Label field values in the GIFCOMMENT
**  structure are assigned by the function calling ReadGifComment().
**
**  Returns: -1 if a FILE stream error occured during the read,
**           otherwise 0 if no error occured.
*/
int
ReadGifComment(
  GIFCOMMENT *GifComment, /* Pointer to GIF Comment Extension structure */
  FILE       *FpGif)      /* GIF image file input FILE stream           */
{
    /* Read in the Plain Text data sub-blocks */
    if (!(GifComment->CommentData = ReadDataSubBlocks(FpGif)))
        return(1);

    GifComment->Terminator = 0;
    
    /* Check for a FILE stream error */
    if (ferror(FpGif))
        return -1;     /* FILE stream error occured during read */

    return 0 ;          /* No FILE stream error occured */
}


/*
**  Read one or more GIF data sub-blocks and write the information
**  to a buffer.
**
**  A GIF "sub-block" is a single count byte followed by 1 to 255
**  additional data bytes.
**
**  Returns: A NULL pointer if a memory allocation error occured,
**           otherwise a valid pointer if no error occured.
*/
BYTE *
ReadDataSubBlocks(FILE *FpGif) /* GIF image file input FILE stream   */
{
    BYTE *ptr1;     /* Pointer used to "walk the heap"               */
    BYTE *ptr2;     /* Pointer used to mark the top of the heap      */
    BYTE dataSize;  /* Size of the current data sub-block being read */
    WORD bufSize;   /* Total size of the Plain Text data buffer      */

    bufSize = 0;    /* The output buffer is empty                    */

    dataSize = GetByte(FpGif);  /* Get the size of the first sub-block */

    /* Allocate initial data buffer */
    if (!(ptr1 = ptr2 = (BYTE *) malloc(dataSize + 1)))
        return((BYTE *) NULL);

    for (;;)
    {
        bufSize += (dataSize + 1);  /* Running total of the buffer size */

        *ptr1++ = dataSize; /* Write the data count */
        while (dataSize--)  /* Read/write the Plain Text data */
            *ptr1++ = GetByte(FpGif);
        
        /* Check if there is another data sub-block */
        if ((dataSize = GetByte(FpGif)) == 0)
            break;  /* Block Terminator encountered */

        /* Increase the buffer size to accomodate the next sub-block */
        if (!(ptr1 = ptr2 = (BYTE *) realloc(ptr2, dataSize + 1)))
            return((BYTE *) NULL);

        ptr1 += bufSize;    /* Move pointer to the end of the data */
    }
    *ptr1++ = (BYTE) NULL;  /* Add NULL to simulate Terminator value */

    return(ptr2);   /* Return a pointer to the sub-block data */
}




/* gifwrite.c */

/* These functions are the complement of the reader functions in GIFREAD.C.
 * They are used to write the header and data blocks found within the GIF
 *image file format.
 */

/****************************************************************************\
**  Title:       gifwrite.c                                                 **
**  Purpose:     Write GIF header information to a file.                    **
**  Version:     1.0                                                        **
**  Date:        May 1991                                                   **
**  Author:      James D. Murray, Anaheim, CA  USA                          **
**  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
**                                                                          **
**  Write the information contained within a GIFHEADER structure            **
**  to a file.  Used to construct GIF-format files.                         **
**                                                                          **
**  This module contains the following functions:                           **
**                                                                          **
**      WriteGifHeader - Write a GIF header to a file stream                **
**                                                                          **
**  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
\****************************************************************************/
#include "gif.h"


VOID
WriteGifHeader(GIFHEAD *GifHead,   /* Pointer to GIF header structure  */
               FILE    *FpGif)     /* GIF image file output FILE stream */
{
    /* PutWord = PutLittleWord;  write using little-endian byte order */

    PutString(GifHead->Signature, sizeof(GifHead->Signature), FpGif);
    PutString(GifHead->Version, sizeof(GifHead->Version), FpGif);
    PutWord(GifHead->ScreenWidth,  FpGif);
    PutWord(GifHead->ScreenHeight, FpGif);
    PutByte(GifHead->PackedField,  FpGif);
    PutByte(GifHead->ColorIndex,   FpGif);
    PutByte(GifHead->AspectRatio,  FpGif);                              
}





/* gifdecode.c  GIF LZW Decoder */

/****************************************************************************\
**  Title:       gifdecode.c                                                **
**  Purpose:     Decode a GIF image file scan line.                         **
**  Version:     1.0                                                        **
**  Date:        May 1991                                                   **
**  Author:      James D. Murray, Anaheim, CA  USA                          **
**  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
**                                                                          **
**  Decompress an image scan line using the Lez-Zempel Welch (LZW) encoding **
**  algorithm.  Decoded data is returned in a buffer.  Useful for           **
**  algorithms that need to work on images one scan line at a time.         **
**                                                                          **
**  This module contains the following functions:                           **
**                                                                          **
**      GifDecodeScanLine - Decode an LZW-encoded scan line                 **
**                                                                          **
**  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
\****************************************************************************/
#include "gif.h"


/*
**  Decode (uncompress) a GIF image file scan line.
**
**  The LZW-encoded data stored in a GIF file is arranged as a series
**  of sub-blocks.  Each sub-lock consists of a single count byte followed
**  by 1 to 255 data bytes.  This function reads the sub-blocks, sends
**  the LZW data to the LZWDecode() function, and then returns a parameter
**  pointer to a buffer filled with the decoded image data.
*/
SHORT
GIFDecodeScanLine(
    BYTE *DecodedBuffer,  /* Pointer to buffer to hold decoded data       */
    WORD  BufferSize,     /* Size of buffer to hold decoded data          */
    BYTE  MinCodeSize,    /*  */
    FILE *FpGif)          /* FILE pointer to the open input GIF image file*/
{
#if 0
    if (!(DecodedBuffer = LZWDecoder(buffer, bufferSize, MinCodeSize)))
        return -1;
#endif
    return 0;
}





/* gifencode.c   GIF LZW Encoder */

/****************************************************************************\
**  Title:       GIFENCOD.C                                                 **
**  Purpose:     Encode a GIF image file scan line.                         **
**  Version:     1.0                                                        **
**  Date:        May 1991                                                   **
**  Author:      James D. Murray, Anaheim, CA  USA                          **
**  C Compilers: Borland C++ v2.0, Microsoft C v6.00a                       **
**                                                                          **
**  Compress an image scan line using the Lev-Zempel Welch (LZW) encoding   **
**  algorithm.  Useful for algorithms that need to work on images           **
**  one scan line at a time.                                                **
**                                                                          **
**  This module contains the following functions:                           **
**                                                                          **
**      GifEncodeScanLine - Encode a raw scan line using LZW.               **
**                                                                          **
**  Copyright (C) 1991 by Graphics Software Labs.  All rights reserved.     **
\****************************************************************************/
#include "gif.h"


WORD
GifEncodeScanLine(
  BYTE *DecodedBuffer,    /* Pointer to buffer holding unencoded data      */
  WORD  BufferSize,       /* Size of buffer holding unencoded data         */
  BYTE *EncodedBuffer)    /* Pointer to buffer to hold encodeded scan line */
{
  return 0;
}




