/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * Copyright by the Board of Trustees of the University of Illinois.         *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF.  The full HDF copyright notice, including       *
 * terms governing use, modification, and redistribution, is contained in    *
 * the COPYING file, which can be found at the root of the source code       *
 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF/releases/.  *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

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

#define NEXTBYTE      (*ptr++)
#define IMAGESEP      0x2c
#define INTERLACEMASK 0x40
#define COLORMAPMASK  0x80
#define False         0
#define True          1

WORD          iWIDE, iHIGH, eWIDE, eHIGH, expand, numcols, strip, nostrip;
unsigned long cols[256];
char         *cmd;

FILE *fp;

static int BitOffset = 0, /* Bit Offset of next code */
    XC = 0, YC = 0,       /* Output X and Y coords of current pixel */
    Pass     = 0,         /* Used by output routine if WORDerlaced pic */
    OutCount = 0,         /* Decompressor output 'stack count' */
#ifdef UNUSED
    RWidth, RHeight,          /* screen dimensions */
    LeftOfs, TopOfs,          /* image offset */
    BitsPerPixel,             /* Bits per pixel, read from GIF header */
    ColorMapSize,             /* number of colors */
    Background,               /* background color */
#endif                        /* UNUSED */
    IWidth, IHeight,          /* image dimensions */
    BytesPerScanline,         /* Bytes per scanline in output raster */
    CodeSize,                 /* Code size, read from GIF header */
    InitCodeSize,             /* Starting code size, used during Clear */
    Code,                     /* Value returned by ReadCode */
    MaxCode,                  /* limiting value for current code size */
    ClearCode,                /* GIF clear code */
    EOFCode,                  /* GIF end-of-information code */
    CurCode, OldCode, InCode, /* Decompressor variables */
    FirstFree,                /* First free code, generated per GIF spec */
    FreeCode,                 /* Decompressor, next free slot in hash table */
    FinChar,                  /* Decompressor variable */
    DataMask,                 /* AND mask for data size */
    ReadMask;                 /* Code AND mask for current code size */

/*MODIFICATIONS*/
BYTE  tempbyte[10];
BYTE *tempBYTEptr[10];
WORD  tempint[10];
WORD  ImageCount = 0;
/*END MODIFICATION*/

boolean Interlace, HasColormap;

BYTE *Image;  /* The result array */
BYTE *RawGIF; /* The heap array to hold it, raw */
BYTE *Raster; /* The raster data stream, unblocked */

/* The hash table used by the decompressor */

int Prefix[4096];
int Suffix[4096];

/* An output array used by the decompressor */

int OutCode[1025];

/* The color map, read from the GIF header */

int numused;

/* Fetch the next code from the raster data stream.  The codes can be
 * any length from 3 to 12 bits, packed WORDo 8-bit BYTEs, so we have to
 * maWORDain our location in the Raster array as a BIT Offset.  We compute
 * the BYTE Offset WORDo the raster array by dividing this by 8, pick up
 * three BYTEs, compute the bit Offset WORDo our 24-bit chunk, shift to
 * bring the desired code to the bottom, then mask it off and return it.
 */
int
ReadCode(void)
{
    int RawCode, ByteOffset;

    ByteOffset = BitOffset / 8;
    RawCode    = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
    if (CodeSize >= 8)
        RawCode += (0x10000 * Raster[ByteOffset + 2]);
    RawCode >>= (BitOffset % 8);
    BitOffset += CodeSize;
    return (RawCode & ReadMask);
}

void
AddToPixel(BYTE Index)
{
    if (YC < IHeight)
        *(Image + YC * BytesPerScanline + XC) = Index;

    /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
    if (++XC == IWidth) {

        /* If a non-WORDerlaced picture, just increment YC to the next scan line.
         * If it's WORDerlaced, deal with the WORDerlace as described in the GIF
         * spec.  Put the decoded scan line out to the screen if we haven't gone
         * past the bottom of it.
         */

        XC = 0;
        if (!Interlace)
            YC++;
        else {
            switch (Pass) {
                case 0:
                    YC += 8;
                    if (YC >= IHeight) {
                        Pass++;
                        YC = 4;
                    }
                    break;
                case 1:
                    YC += 8;
                    if (YC >= IHeight) {
                        Pass++;
                        YC = 2;
                    }
                    break;

                case 2:
                    YC += 4;
                    if (YC >= IHeight) {
                        Pass++;
                        YC = 1;
                    }
                    break;
                case 3:
                    YC += 2;
                    break;
                default:
                    break;
            }
        }
    }
}

/* Main routine.  Convert a GIF image to an HDF image */

BYTE *
Decompress(GIFIMAGEDESC *GifImageDesc, GIFHEAD *GifHead)
{
    int i;

    XC        = 0;
    YC        = 0;
    Pass      = 0;
    OutCount  = 0;
    BitOffset = 0;

    DataMask = (WORD)((1L << ((GifHead->PackedField & 0x07) + 1)) - 1);
    Raster   = GifImageDesc->GIFImage;

    /* Check for image separator */

    /* Now read in values from the image descriptor */
    IWidth    = GifImageDesc->ImageWidth;
    IHeight   = GifImageDesc->ImageHeight;
    Interlace = GifImageDesc->PackedField & 0x20;

    /* Note that I ignore the possible existence of a local color map.
     * I'm told there aren't many files around that use them, and the spec
     * says it's defined for future use.  This could lead to an error
     * reading some files.
     */

    /* Start reading the raster data. First we get the WORDial code size
     * and compute decompressor constant values, based on this code size.
     */

    CodeSize  = GifImageDesc->CodeSize;
    ClearCode = (1 << CodeSize);
    EOFCode   = ClearCode + 1;
    FreeCode = FirstFree = ClearCode + 2;

    /* The GIF spec has it that the code size is the code size used to
     * compute the above values is the code size given in the file, but the
     * code size used in compression/decompression is the code size given in
     * the file plus one. (thus the ++).
     */

    CodeSize++;
    InitCodeSize = CodeSize;
    MaxCode      = (1 << CodeSize);
    ReadMask     = MaxCode - 1;

    /* Read the raster data.  Here we just transpose it from the GIF array
     * to the Raster array, turning it from a series of blocks WORDo one long
     * data stream, which makes life much easier for ReadCode().
     */

    /*    free(RawGIF);		 We're not done just yet - change made */

    /* Allocate the Image */

    if (!(Image = (BYTE *)malloc(IWidth * IHeight))) {
        printf("Out of memory");
        exit(-1);
    }

    BytesPerScanline = IWidth;

    /* Decompress the file, continuing until you see the GIF EOF code.
     * One obvious enhancement is to add checking for corrupt files here.
     */

    Code = ReadCode();
    while (Code != EOFCode) {

        /* Clear code sets everything back to its initial value, then reads the
         * immediately subsequent code as uncompressed data.
         */

        if (Code == ClearCode) {
            CodeSize = InitCodeSize;
            MaxCode  = (1 << CodeSize);
            ReadMask = MaxCode - 1;
            FreeCode = FirstFree;
            CurCode = OldCode = Code = ReadCode();
            FinChar                  = CurCode & DataMask;
            AddToPixel(FinChar);
        }
        else {

            /* If not a clear code, then must be data: save same as CurCode and InCode */

            CurCode = InCode = Code;

            /* If greater or equal to FreeCode, not in the hash table yet;
             * repeat the last character decoded
             */

            if (CurCode >= FreeCode) {
                CurCode             = OldCode;
                OutCode[OutCount++] = FinChar;
            }

            /* Unless this code is raw data, pursue the chain poWORDed to by CurCode
             * through the hash table to its end; each code in the chain puts its
             * associated output code on the output queue.
             */

            while (CurCode > DataMask) {
                if (OutCount > 1024) {
                    /*return error message*/
                }
                OutCode[OutCount++] = Suffix[CurCode];
                CurCode             = Prefix[CurCode];
            }

            /* The last code in the chain is treated as raw data. */

            FinChar             = CurCode & DataMask;
            OutCode[OutCount++] = FinChar;

            /* Now we put the data out to the Output routine.
             * It's been stacked LIFO, so deal with it that way...
             */

            for (i = OutCount - 1; i >= 0; i--)
                AddToPixel(OutCode[i]);
            OutCount = 0;

            /* Build the hash table on-the-fly. No table is stored in the file. */

            Prefix[FreeCode] = OldCode;
            Suffix[FreeCode] = FinChar;
            OldCode          = InCode;

            /* PoWORD to the next slot in the table.  If we exceed the current
             * MaxCode value, increment the code size unless it's already 12.  If it
             * is, do nothing: the next code decompressed better be CLEAR
             */

            FreeCode++;
            if (FreeCode >= MaxCode) {
                if (CodeSize < 12) {
                    CodeSize++;
                    MaxCode *= 2;
                    ReadMask = (1 << CodeSize) - 1;
                }
            }
        }
        Code = ReadCode();
    }

    return Image;
}
