/***************************************************************************** * "Gif-Lib" - Yet another gif library. * * * * Written by: Gershon Elber IBM PC Ver 0.1, Jun. 1989 * ****************************************************************************** * The kernel of the GIF Decoding process can be found here. * ****************************************************************************** * History: * * 16 Jun 89 - Version 1.0 by Gershon Elber. * *****************************************************************************/ #include #include #include #include #include #include #include #include "gif_lib.h" #include "gif_hash.h" #define PROGRAM_NAME "GIF_LIBRARY" #define VERSION "á Version 1.0, " #define COMMENT_EXT_FUNC_CODE 'C' /* Extension function code for comment */ #define GIF_STAMP "GIF87a" /* First chars in file - GIF stamp */ #define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1 #define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */ #define LZ_BITS 12 #define FILE_STATE_READ 0x01/* 1 write, 0 read - EGIF_LIB compatible */ #define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush */ #define FIRST_CODE 4097 /* Impossible code, to signal first */ #define NO_SUCH_CODE 4098 /* Impossible code, to signal empty */ #define IS_READABLE(Private) (!(Private -> FileState & FILE_STATE_READ)) typedef struct GifFilePrivateType { int FileState, FileHandle, /* Where all this data goes to! */ BitsPerPixel, /* Bits per pixel (Codes uses at list this + 1) */ ClearCode, /* The CLEAR LZ code */ EOFCode, /* The EOF LZ code */ RunningCode, /* The next code algorithm can generate */ RunningBits, /* The number of bits required to represent RunningCode */ MaxCode1,/* 1 bigger than maximum possible code, in RunningBits bits */ LastCode, /* The code before the current code */ CrntCode, /* Current algorithm code */ StackPtr, /* For character stack (see below) */ CrntShiftState; /* Number of bits in CrntShiftDWord */ unsigned long CrntShiftDWord, /* For bytes decomposition into codes */ PixelCount; /* Number of pixels in image */ FILE *File; /* File as stream */ ByteType Buf[256]; /* Compressed input is buffered here */ ByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here */ ByteType Suffix[LZ_MAX_CODE+1]; /* So we can trace the codes */ unsigned int Prefix[LZ_MAX_CODE+1]; } GifFilePrivateType; extern int _GifError; static char *VersionStr = PROGRAM_NAME " IBMPC " VERSION " Gershon Elber, " __DATE__ ", " __TIME__ "\n" "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n"; static int DGifGetWord(FILE *File, int *Word); static int DGifSetupDecompress(GifFileType *GifFile); static int DGifDecompressLine(GifFileType *GifFile, PixelType *Line, int LineLen); static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode); static int DGifDecompressInput(GifFilePrivateType *Private, int *Code); static int DGifBufferedInput(FILE *File, ByteType *Buf, ByteType *NextByte); /****************************************************************************** * Open a new gif file for read, given by its name. * * Returns GifFileType pointer dynamically allocated which serves as the gif * * info record. _GifError is cleared if succesfull. * ******************************************************************************/ GifFileType *DGifOpenFileName(char *FileName) { int FileHandle; if ((FileHandle = open(FileName, O_RDONLY | O_BINARY)) == -1) { _GifError = D_GIF_ERR_OpenFailed; return NULL; } return DGifOpenFileHandle(FileHandle); } /****************************************************************************** * Update a new gif file, given its file handle. * * Returns GifFileType pointer dynamically allocated which serves as the gif * * info record. _GifError is cleared if succesfull. * ******************************************************************************/ GifFileType *DGifOpenFileHandle(int FileHandle) { char Buf[GIF_STAMP_LEN+1]; GifFileType *GifFile; GifFilePrivateType *Private; FILE *f; setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode */ f = fdopen(FileHandle, "rb"); /* Make it into a stream: */ setvbuf(f, NULL, _IOFBF, FILE_BUFFER_SIZE);/* And increase stream buffer */ if ((GifFile = (GifFileType *) malloc(sizeof(GifFileType))) == NULL) { _GifError = D_GIF_ERR_NotEnoughMem; return NULL; } if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType))) == NULL) { _GifError = D_GIF_ERR_NotEnoughMem; free((char *) GifFile); return NULL; } GifFile -> Private = (void *) Private; GifFile -> SColorMap = GifFile -> IColorMap = NULL; Private -> FileHandle = FileHandle; Private -> File = f; Private -> FileState = 0; /* Make sure bit 0 = 0 (File opened for read) */ /* Lets see if this is GIF file: */ if (fread(Buf, 1, GIF_STAMP_LEN, Private -> File) != GIF_STAMP_LEN) { _GifError = D_GIF_ERR_ReadFailed; free((char *) Private); free((char *) GifFile); return NULL; } Buf[GIF_STAMP_LEN] = 0; if (strcmp(GIF_STAMP, Buf) != 0) { _GifError = D_GIF_ERR_NotGifFile; free((char *) Private); free((char *) GifFile); return NULL; } if (DGifGetScreenDesc(GifFile) == ERROR) { free((char *) Private); free((char *) GifFile); return NULL; } _GifError = 0; return GifFile; } /****************************************************************************** * This routine should be called before any other DGif calls. Note that * * this routine is called automatically from DGif file open routines. * ******************************************************************************/ int DGifGetScreenDesc(GifFileType *GifFile) { int Size, i; ByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } /* Put the screen descriptor into the file: */ if (DGifGetWord(Private -> File, &GifFile -> SWidth) == ERROR || DGifGetWord(Private -> File, &GifFile -> SHeight) == ERROR) return ERROR; if (fread(Buf, 1, 3, Private -> File) != 3) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } GifFile -> SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1; GifFile -> SBitsPerPixel = (Buf[0] & 0x07) + 1; GifFile -> SBackGroundColor = Buf[1]; if (Buf[0] & 0x80) { /* Do we have global color map? */ Size = (1 << GifFile -> SBitsPerPixel); GifFile -> SColorMap = (GifColorType *) malloc(sizeof(GifColorType) * Size); for (i=0; i File) != 3) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } GifFile -> SColorMap[i].Red = Buf[0]; GifFile -> SColorMap[i].Green = Buf[1]; GifFile -> SColorMap[i].Blue = Buf[2]; } } return OK; } /****************************************************************************** * This routine should be called before any attemp to read an image. * ******************************************************************************/ int DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type) { ByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (fread(&Buf, 1, 1, Private -> File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } switch (Buf) { case ',': *Type = IMAGE_DESC_RECORD_TYPE; break; case '!': *Type = EXTENSION_RECORD_TYPE; break; case ';': *Type = TERMINATE_RECORD_TYPE; break; default: *Type = UNDEFINED_RECORD_TYPE; _GifError = D_GIF_ERR_WrongRecord; return ERROR; } return OK; } /****************************************************************************** * This routine should be called before any attemp to read an image. * * Note it is assumed the Image desc. header (',') has been read. * ******************************************************************************/ int DGifGetImageDesc(GifFileType *GifFile) { int Size, i; ByteType Buf[3]; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (DGifGetWord(Private -> File, &GifFile -> ILeft) == ERROR || DGifGetWord(Private -> File, &GifFile -> ITop) == ERROR || DGifGetWord(Private -> File, &GifFile -> IWidth) == ERROR || DGifGetWord(Private -> File, &GifFile -> IHeight) == ERROR) return ERROR; if (fread(Buf, 1, 1, Private -> File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } GifFile -> IBitsPerPixel = (Buf[0] & 0x07) + 1; GifFile -> IInterlace = (Buf[0] & 0x40); if (Buf[0] & 0x80) { /* Does this image have local color map? */ Size = (1 << GifFile -> IBitsPerPixel); if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap); GifFile -> IColorMap = (GifColorType *) malloc(sizeof(GifColorType) * Size); for (i=0; i File) != 3) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } GifFile -> IColorMap[i].Red = Buf[0]; GifFile -> IColorMap[i].Green = Buf[1]; GifFile -> IColorMap[i].Blue = Buf[2]; } } Private -> PixelCount = (long) GifFile -> IWidth * (long) GifFile -> IHeight; DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters */ return OK; } /****************************************************************************** * Get one full scanned line (Line) of length LineLen from GIF file. * ******************************************************************************/ int DGifGetLine(GifFileType *GifFile, PixelType *Line, int LineLen) { ByteType *Dummy; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (!LineLen) LineLen = GifFile -> IWidth; if ((Private -> PixelCount -= LineLen) < 0) { _GifError = D_GIF_ERR_DataTooBig; return ERROR; } if (DGifDecompressLine(GifFile, Line, LineLen) == OK) { if (Private -> PixelCount == 0) { /* We probably would not be called any more, so lets clean */ /* everything before we return: need to flush out all rest of */ /* image until empty block (size 0) detected. We use GetCodeNext */ do if (DGifGetCodeNext(GifFile, &Dummy) == ERROR) return ERROR; while (Dummy != NULL); } return OK; } else return ERROR; } /****************************************************************************** * Put one pixel (Pixel) into GIF file. * ******************************************************************************/ int DGifGetPixel(GifFileType *GifFile, PixelType Pixel) { ByteType *Dummy; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (--Private -> PixelCount < 0) { _GifError = D_GIF_ERR_DataTooBig; return ERROR; } if (DGifDecompressLine(GifFile, &Pixel, 1) == OK) { if (Private -> PixelCount == 0) { /* We probably would not be called any more, so lets clean */ /* everything before we return: need to flush out all rest of */ /* image until empty block (size 0) detected. We use GetCodeNext */ do if (DGifGetCodeNext(GifFile, &Dummy) == ERROR) return ERROR; while (Dummy != NULL); } return OK; } else return ERROR; } /****************************************************************************** * Get an extension block (see GIF manual) from gif file. This routine only * * returns the first data block, and DGifGetExtensionNext shouldbe called * * after this one until NULL extension is returned. * * The Extension should NOT be freed by the user (not dynamically allocated).* * Note it is assumed the Extension desc. header ('!') has been read. * ******************************************************************************/ int DGifGetExtension(GifFileType *GifFile, int *ExtCode, ByteType **Extension) { ByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (fread(&Buf, 1, 1, Private -> File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } *ExtCode = Buf; return DGifGetExtensionNext(GifFile, Extension); } /****************************************************************************** * Get a following extension block (see GIF manual) from gif file. This * * routine sould be called until NULL Extension is returned. * * The Extension should NOT be freed by the user (not dynamically allocated).* ******************************************************************************/ int DGifGetExtensionNext(GifFileType *GifFile, ByteType **Extension) { ByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (fread(&Buf, 1, 1, Private -> File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } if (Buf > 0) { *Extension = Private -> Buf; /* Use private unused buffer */ (*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is length) */ if (fread(&((*Extension)[1]), 1, Buf, Private -> File) != Buf) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } } else *Extension = NULL; return OK; } /****************************************************************************** * This routine should be called last, to close GIF file. * ******************************************************************************/ int DGifCloseFile(GifFileType *GifFile) { GifFilePrivateType *Private; FILE *File; if (GifFile == NULL) return ERROR; Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } File = Private -> File; if (GifFile -> IColorMap) free((char *) GifFile -> IColorMap); if (GifFile -> SColorMap) free((char *) GifFile -> SColorMap); if (Private) free((char *) Private); free(GifFile); if (fclose(File) != 0) { _GifError = D_GIF_ERR_CloseFailed; return ERROR; } return OK; } /****************************************************************************** * Get 2 bytes (word) from the given file: * ******************************************************************************/ static int DGifGetWord(FILE *File, int *Word) { unsigned char c[2]; if (fread(c, 1, 2, File) != 2) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } *Word = (((unsigned int) c[1]) << 8) + c[0]; return OK; } /****************************************************************************** * Get the image code in compressed form. his routine can be called if the * * information needed to be piped out as is. Obviously this is much faster * * than decoding and encoding again. This routine should be followed by calls * * to DGifGetCodeNext, until NULL block is returned. * * The block should NOT be freed by the user (not dynamically allocated). * ******************************************************************************/ int DGifGetCode(GifFileType *GifFile, int *CodeSize, ByteType **CodeBlock) { GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } *CodeSize = Private -> BitsPerPixel; return DGifGetCodeNext(GifFile, CodeBlock); } /****************************************************************************** * Continue to get the image code in compressed form. This routine should be * * called until NULL block is returned. * * The block should NOT be freed by the user (not dynamically allocated). * ******************************************************************************/ int DGifGetCodeNext(GifFileType *GifFile, ByteType **CodeBlock) { ByteType Buf; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (fread(&Buf, 1, 1, Private -> File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } if (Buf > 0) { *CodeBlock = Private -> Buf; /* Use private unused buffer */ (*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is length) */ if (fread(&((*CodeBlock)[1]), 1, Buf, Private -> File) != Buf) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } } else { *CodeBlock = NULL; Private -> Buf[0] = 0; /* Make sure the buffer is empty! */ Private -> PixelCount = 0; /* And local info. indicate image read */ } return OK; } /****************************************************************************** * Setup the LZ decompression for this image: * ******************************************************************************/ static int DGifSetupDecompress(GifFileType *GifFile) { int i, BitsPerPixel; ByteType CodeSize; unsigned int *Prefix; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; fread(&CodeSize, 1, 1, Private -> File); /* Read Code size from file */ BitsPerPixel = CodeSize; Private -> Buf[0] = 0; /* Input Buffer empty */ Private -> BitsPerPixel = BitsPerPixel; Private -> ClearCode = (1 << BitsPerPixel); Private -> EOFCode = Private -> ClearCode + 1; Private -> RunningCode = Private -> EOFCode + 1; Private -> RunningBits = BitsPerPixel + 1; /* Number of bits per code */ Private -> MaxCode1 = 1 << Private -> RunningBits; /* Max. code + 1 */ Private -> StackPtr = 0; /* No pixels on the pixel stack */ Private -> LastCode = NO_SUCH_CODE; Private -> CrntShiftState = 0; /* No information in CrntShiftDWord */ Private -> CrntShiftDWord = 0; Prefix = Private -> Prefix; for (i=0; i Private; StackPtr = Private -> StackPtr; Prefix = Private -> Prefix; Suffix = Private -> Suffix; Stack = Private -> Stack; EOFCode = Private -> EOFCode; ClearCode = Private -> ClearCode; LastCode = Private -> LastCode; if (StackPtr != 0) { /* Let pop the stack off before continueing to read the gif file: */ while (StackPtr != 0 && i < LineLen) Line[i++] = Stack[--StackPtr]; } while (i < LineLen) { /* Decode LineLen items. */ if (DGifDecompressInput(Private, &CrntCode) == ERROR) return ERROR; if (CrntCode == EOFCode) { /* Note however that usually we will not be here as we will stop */ /* decoding as soon as we got all the pixel, or EOF code will */ /* not be read at all, and DGifGetLine/Pixel clean everything. */ if (i != LineLen - 1 || Private -> PixelCount != 0) { _GifError = D_GIF_ERR_EOFTooSoon; return ERROR; } i++; } else if (CrntCode == ClearCode) { /* We need to start over again: */ for (j=0; j RunningCode = Private -> EOFCode + 1; Private -> RunningBits = Private -> BitsPerPixel + 1; Private -> MaxCode1 = 1 << Private -> RunningBits; LastCode = Private -> LastCode = NO_SUCH_CODE; } else { /* Its regular code - if in pixel range simply add it to output */ /* stream, otherwise trace to codes linked list until the prefix */ /* is in pixel range: */ if (CrntCode < ClearCode) { /* This is simple - its pixel scalar, so add it to output: */ Line[i++] = CrntCode; } else { /* Its a code to needed to be traced: trace the linked list */ /* until the prefix is a pixel, while pushing the suffix */ /* pixels on our stack. If we done, pop the stack in reverse */ /* (thats what stack is good for!) order to output. */ if (Prefix[CrntCode] == NO_SUCH_CODE) { /* Only allowed if CrntCode is exactly the running code: */ /* In that case CrntCode = XXXCode, CrntCode or the */ /* prefix code is last code and the suffix char is */ /* exactly the prefix of last code! */ if (CrntCode == Private -> RunningCode - 2) { CrntPrefix = LastCode; Suffix[Private -> RunningCode - 2] = Stack[StackPtr++] = DGifGetPrefixChar(Prefix, LastCode, ClearCode); } else { _GifError = D_GIF_ERR_ImageDefect; return ERROR; } } else CrntPrefix = CrntCode; /* Now (if image is O.K.) we should not get and NO_SUCH_CODE */ /* During the trace. As we might loop forever, in case of */ /* defective image, we count the number of loops we trace */ /* and stop if we got LZ_MAX_CODE. obviously we can not */ /* loop more than that. */ j = 0; while (j++ <= LZ_MAX_CODE && CrntPrefix > ClearCode && CrntPrefix <= LZ_MAX_CODE) { Stack[StackPtr++] = Suffix[CrntPrefix]; CrntPrefix = Prefix[CrntPrefix]; } if (j >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) { _GifError = D_GIF_ERR_ImageDefect; return ERROR; } /* Push the last character on stack: */ Stack[StackPtr++] = CrntPrefix; /* Now lets pop all the stack into output: */ while (StackPtr != 0 && i < LineLen) Line[i++] = Stack[--StackPtr]; } if (LastCode != NO_SUCH_CODE) { Prefix[Private -> RunningCode - 2] = LastCode; if (CrntCode == Private -> RunningCode - 2) { /* Only allowed if CrntCode is exactly the running code: */ /* In that case CrntCode = XXXCode, CrntCode or the */ /* prefix code is last code and the suffix char is */ /* exactly the prefix of last code! */ Suffix[Private -> RunningCode - 2] = DGifGetPrefixChar(Prefix, LastCode, ClearCode); } else { Suffix[Private -> RunningCode - 2] = DGifGetPrefixChar(Prefix, CrntCode, ClearCode); } } LastCode = CrntCode; } } Private -> LastCode = LastCode; Private -> StackPtr = StackPtr; return OK; } /****************************************************************************** * Routine to trace the Prefixes linked list until we get a prefix which is * * not code, but a pixel value (less than ClearCode). Returns that pixel value.* * If image is defective, we might loop here forever, so we limit the loops to * * the maximum possible if image O.k. - LZ_MAX_CODE times. * ******************************************************************************/ static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode) { int i = 0; while (Code > ClearCode && i++ <= LZ_MAX_CODE) Code = Prefix[Code]; return Code; } /****************************************************************************** * Interface for accessing the LZ codes directly. Set Code to the real code * * (12bits), or to -1 if EOF code is returned. * ******************************************************************************/ int DGifGetLZCodes(GifFileType *GifFile, int *Code) { ByteType *CodeBlock; GifFilePrivateType *Private = (GifFilePrivateType *) GifFile -> Private; if (!IS_READABLE(Private)) { /* This file was NOT open for reading: */ _GifError = D_GIF_ERR_NotReadable; return ERROR; } if (DGifDecompressInput(Private, Code) == ERROR) return ERROR; if (*Code == Private -> EOFCode) { /* Skip rest of codes (hopefully only NULL terminating block): */ do if (DGifGetCodeNext(GifFile, &CodeBlock) == ERROR) return ERROR; while (CodeBlock != NULL); *Code = -1; } else if (*Code == Private -> ClearCode) { /* We need to start over again: */ Private -> RunningCode = Private -> EOFCode + 1; Private -> RunningBits = Private -> BitsPerPixel + 1; Private -> MaxCode1 = 1 << Private -> RunningBits; } return OK; } /****************************************************************************** * The LZ decompression input routine: * * This routine is responsable for the decompression of the bit stream from * * 8 bits (bytes) packets, into the real codes. * * Returns OK if read succesfully. * ******************************************************************************/ static int DGifDecompressInput(GifFilePrivateType *Private, int *Code) { ByteType NextByte; static unsigned int CodeMasks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff }; while (Private -> CrntShiftState < Private -> RunningBits) { /* Needs to get more bytes from input stream for next code: */ if (DGifBufferedInput(Private -> File, Private -> Buf, &NextByte) == ERROR) { return ERROR; } Private -> CrntShiftDWord |= ((unsigned long) NextByte) << Private -> CrntShiftState; Private -> CrntShiftState += 8; } *Code = Private -> CrntShiftDWord & CodeMasks[Private -> RunningBits]; Private -> CrntShiftDWord >>= Private -> RunningBits; Private -> CrntShiftState -= Private -> RunningBits; /* If code cannt fit into RunningBits bits, must raise its size. Note */ /* however that codes above 4095 are used for special signaling. */ if (++Private -> RunningCode > Private -> MaxCode1 && Private -> RunningBits < LZ_BITS) { Private -> MaxCode1 <<= 1; Private -> RunningBits++; } return OK; } /****************************************************************************** * This routines read one gif data block at a time and buffers it internally * * so that the decompression routine could access it. * * The routine returns the next byte from its internal buffer (or read next * * block in if buffer empty) and returns OK if succesful. * ******************************************************************************/ static int DGifBufferedInput(FILE *File, ByteType *Buf, ByteType *NextByte) { if (Buf[0] == 0) { /* Needs to read the next buffer - this one is empty: */ if (fread(Buf, 1, 1, File) != 1) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } if (fread(&Buf[1], 1, Buf[0], File) != Buf[0]) { _GifError = D_GIF_ERR_ReadFailed; return ERROR; } *NextByte = Buf[1]; Buf[1] = 2; /* We use now the second place as last char read! */ Buf[0]--; } else { *NextByte = Buf[Buf[1]++]; Buf[0]--; } return OK; }