Path: blob/master/src/java.desktop/share/native/libsplashscreen/giflib/dgif_lib.c
41153 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324/******************************************************************************2526dgif_lib.c - GIF decoding2728The functions here and in egif_lib.c are partitioned carefully so that29if you only require one of read and write capability, only one of these30two modules will be linked. Preserve this property!3132SPDX-License-Identifier: MIT3334*****************************************************************************/3536#include <stdlib.h>37#include <limits.h>38#include <stdint.h>39#include <fcntl.h>40#include <stdio.h>41#include <string.h>4243#ifdef _WIN3244#include <io.h>45#else46#include <unistd.h>47#endif /* _WIN32 */4849#include "gif_lib.h"50#include "gif_lib_private.h"5152/* compose unsigned little endian value */53#define UNSIGNED_LITTLE_ENDIAN(lo, hi) ((lo) | ((hi) << 8))5455/* avoid extra function call in case we use fread (TVT) */56static int InternalRead(GifFileType *gif, GifByteType *buf, int len) {57//fprintf(stderr, "### Read: %d\n", len);58return59(((GifFilePrivateType*)gif->Private)->Read ?60((GifFilePrivateType*)gif->Private)->Read(gif,buf,len) :61fread(buf,1,len,((GifFilePrivateType*)gif->Private)->File));62}6364static int DGifGetWord(GifFileType *GifFile, GifWord *Word);65static int DGifSetupDecompress(GifFileType *GifFile);66static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,67int LineLen);68static int DGifGetPrefixChar(GifPrefixType *Prefix, int Code, int ClearCode);69static int DGifDecompressInput(GifFileType *GifFile, int *Code);70static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,71GifByteType *NextByte);7273/******************************************************************************74Open a new GIF file for read, given by its name.75Returns dynamically allocated GifFileType pointer which serves as the GIF76info record.77******************************************************************************/78GifFileType *79DGifOpenFileName(const char *FileName, int *Error)80{81int FileHandle;82GifFileType *GifFile;8384if ((FileHandle = open(FileName, O_RDONLY)) == -1) {85if (Error != NULL)86*Error = D_GIF_ERR_OPEN_FAILED;87return NULL;88}8990GifFile = DGifOpenFileHandle(FileHandle, Error);91return GifFile;92}9394/******************************************************************************95Update a new GIF file, given its file handle.96Returns dynamically allocated GifFileType pointer which serves as the GIF97info record.98******************************************************************************/99GifFileType *100DGifOpenFileHandle(int FileHandle, int *Error)101{102char Buf[GIF_STAMP_LEN + 1];103GifFileType *GifFile;104GifFilePrivateType *Private;105FILE *f;106107GifFile = (GifFileType *)malloc(sizeof(GifFileType));108if (GifFile == NULL) {109if (Error != NULL)110*Error = D_GIF_ERR_NOT_ENOUGH_MEM;111(void)close(FileHandle);112return NULL;113}114115/*@i1@*/memset(GifFile, '\0', sizeof(GifFileType));116117/* Belt and suspenders, in case the null pointer isn't zero */118GifFile->SavedImages = NULL;119GifFile->SColorMap = NULL;120121Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));122if (Private == NULL) {123if (Error != NULL)124*Error = D_GIF_ERR_NOT_ENOUGH_MEM;125(void)close(FileHandle);126free((char *)GifFile);127return NULL;128}129130/*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));131132#ifdef _WIN32133_setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */134#endif /* _WIN32 */135136f = fdopen(FileHandle, "rb"); /* Make it into a stream: */137138/*@-mustfreeonly@*/139GifFile->Private = (void *)Private;140Private->FileHandle = FileHandle;141Private->File = f;142Private->FileState = FILE_STATE_READ;143Private->Read = NULL; /* don't use alternate input method (TVT) */144GifFile->UserData = NULL; /* TVT */145/*@=mustfreeonly@*/146147/* Let's see if this is a GIF file: */148/* coverity[check_return] */149if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {150if (Error != NULL)151*Error = D_GIF_ERR_READ_FAILED;152(void)fclose(f);153free((char *)Private);154free((char *)GifFile);155return NULL;156}157158/* Check for GIF prefix at start of file */159Buf[GIF_STAMP_LEN] = 0;160if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {161if (Error != NULL)162*Error = D_GIF_ERR_NOT_GIF_FILE;163(void)fclose(f);164free((char *)Private);165free((char *)GifFile);166return NULL;167}168169if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {170(void)fclose(f);171free((char *)Private);172free((char *)GifFile);173return NULL;174}175176GifFile->Error = 0;177178/* What version of GIF? */179Private->gif89 = (Buf[GIF_VERSION_POS] == '9');180181return GifFile;182}183184/******************************************************************************185GifFileType constructor with user supplied input function (TVT)186******************************************************************************/187GifFileType *188DGifOpen(void *userData, InputFunc readFunc, int *Error)189{190char Buf[GIF_STAMP_LEN + 1];191GifFileType *GifFile;192GifFilePrivateType *Private;193194GifFile = (GifFileType *)malloc(sizeof(GifFileType));195if (GifFile == NULL) {196if (Error != NULL)197*Error = D_GIF_ERR_NOT_ENOUGH_MEM;198return NULL;199}200201memset(GifFile, '\0', sizeof(GifFileType));202203/* Belt and suspenders, in case the null pointer isn't zero */204GifFile->SavedImages = NULL;205GifFile->SColorMap = NULL;206207Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));208if (!Private) {209if (Error != NULL)210*Error = D_GIF_ERR_NOT_ENOUGH_MEM;211free((char *)GifFile);212return NULL;213}214/*@i1@*/memset(Private, '\0', sizeof(GifFilePrivateType));215216GifFile->Private = (void *)Private;217Private->FileHandle = 0;218Private->File = NULL;219Private->FileState = FILE_STATE_READ;220221Private->Read = readFunc; /* TVT */222GifFile->UserData = userData; /* TVT */223224/* Lets see if this is a GIF file: */225/* coverity[check_return] */226if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {227if (Error != NULL)228*Error = D_GIF_ERR_READ_FAILED;229free((char *)Private);230free((char *)GifFile);231return NULL;232}233234/* Check for GIF prefix at start of file */235Buf[GIF_STAMP_LEN] = '\0';236if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {237if (Error != NULL)238*Error = D_GIF_ERR_NOT_GIF_FILE;239free((char *)Private);240free((char *)GifFile);241return NULL;242}243244if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {245free((char *)Private);246free((char *)GifFile);247if (Error != NULL)248*Error = D_GIF_ERR_NO_SCRN_DSCR;249return NULL;250}251252GifFile->Error = 0;253254/* What version of GIF? */255Private->gif89 = (Buf[GIF_VERSION_POS] == '9');256257return GifFile;258}259260/******************************************************************************261This routine should be called before any other DGif calls. Note that262this routine is called automatically from DGif file open routines.263******************************************************************************/264int265DGifGetScreenDesc(GifFileType *GifFile)266{267int BitsPerPixel;268bool SortFlag;269GifByteType Buf[3];270GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;271272if (!IS_READABLE(Private)) {273/* This file was NOT open for reading: */274GifFile->Error = D_GIF_ERR_NOT_READABLE;275return GIF_ERROR;276}277278/* Put the screen descriptor into the file: */279if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||280DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR)281return GIF_ERROR;282283if (InternalRead(GifFile, Buf, 3) != 3) {284GifFile->Error = D_GIF_ERR_READ_FAILED;285GifFreeMapObject(GifFile->SColorMap);286GifFile->SColorMap = NULL;287return GIF_ERROR;288}289GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;290SortFlag = (Buf[0] & 0x08) != 0;291BitsPerPixel = (Buf[0] & 0x07) + 1;292GifFile->SBackGroundColor = Buf[1];293GifFile->AspectByte = Buf[2];294if (Buf[0] & 0x80) { /* Do we have global color map? */295int i;296297GifFile->SColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);298if (GifFile->SColorMap == NULL) {299GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;300return GIF_ERROR;301}302303/* Get the global color map: */304GifFile->SColorMap->SortFlag = SortFlag;305for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {306/* coverity[check_return] */307if (InternalRead(GifFile, Buf, 3) != 3) {308GifFreeMapObject(GifFile->SColorMap);309GifFile->SColorMap = NULL;310GifFile->Error = D_GIF_ERR_READ_FAILED;311return GIF_ERROR;312}313GifFile->SColorMap->Colors[i].Red = Buf[0];314GifFile->SColorMap->Colors[i].Green = Buf[1];315GifFile->SColorMap->Colors[i].Blue = Buf[2];316}317} else {318GifFile->SColorMap = NULL;319}320321/*322* No check here for whether the background color is in range for the323* screen color map. Possibly there should be.324*/325326return GIF_OK;327}328329const char *330DGifGetGifVersion(GifFileType *GifFile)331{332GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;333334if (Private->gif89)335return GIF89_STAMP;336else337return GIF87_STAMP;338}339340/******************************************************************************341This routine should be called before any attempt to read an image.342******************************************************************************/343int344DGifGetRecordType(GifFileType *GifFile, GifRecordType* Type)345{346GifByteType Buf;347GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;348349if (!IS_READABLE(Private)) {350/* This file was NOT open for reading: */351GifFile->Error = D_GIF_ERR_NOT_READABLE;352return GIF_ERROR;353}354355/* coverity[check_return] */356if (InternalRead(GifFile, &Buf, 1) != 1) {357GifFile->Error = D_GIF_ERR_READ_FAILED;358return GIF_ERROR;359}360361//fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);362switch (Buf) {363case DESCRIPTOR_INTRODUCER:364*Type = IMAGE_DESC_RECORD_TYPE;365break;366case EXTENSION_INTRODUCER:367*Type = EXTENSION_RECORD_TYPE;368break;369case TERMINATOR_INTRODUCER:370*Type = TERMINATE_RECORD_TYPE;371break;372default:373*Type = UNDEFINED_RECORD_TYPE;374GifFile->Error = D_GIF_ERR_WRONG_RECORD;375return GIF_ERROR;376}377378return GIF_OK;379}380381int382DGifGetImageHeader(GifFileType *GifFile)383{384unsigned int BitsPerPixel;385GifByteType Buf[3];386GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;387388if (!IS_READABLE(Private)) {389/* This file was NOT open for reading: */390GifFile->Error = D_GIF_ERR_NOT_READABLE;391return GIF_ERROR;392}393394if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||395DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||396DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||397DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR)398return GIF_ERROR;399if (InternalRead(GifFile, Buf, 1) != 1) {400GifFile->Error = D_GIF_ERR_READ_FAILED;401GifFreeMapObject(GifFile->Image.ColorMap);402GifFile->Image.ColorMap = NULL;403return GIF_ERROR;404}405BitsPerPixel = (Buf[0] & 0x07) + 1;406GifFile->Image.Interlace = (Buf[0] & 0x40) ? true : false;407408/* Setup the colormap */409if (GifFile->Image.ColorMap) {410GifFreeMapObject(GifFile->Image.ColorMap);411GifFile->Image.ColorMap = NULL;412}413/* Does this image have local color map? */414if (Buf[0] & 0x80) {415unsigned int i;416417GifFile->Image.ColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);418if (GifFile->Image.ColorMap == NULL) {419GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;420return GIF_ERROR;421}422423/* Get the image local color map: */424for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {425/* coverity[check_return] */426if (InternalRead(GifFile, Buf, 3) != 3) {427GifFreeMapObject(GifFile->Image.ColorMap);428GifFile->Error = D_GIF_ERR_READ_FAILED;429GifFile->Image.ColorMap = NULL;430return GIF_ERROR;431}432GifFile->Image.ColorMap->Colors[i].Red = Buf[0];433GifFile->Image.ColorMap->Colors[i].Green = Buf[1];434GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];435}436}437438Private->PixelCount = (long)GifFile->Image.Width *439(long)GifFile->Image.Height;440441/* Reset decompress algorithm parameters. */442return DGifSetupDecompress(GifFile);443}444445/******************************************************************************446This routine should be called before any attempt to read an image.447Note it is assumed the Image desc. header has been read.448******************************************************************************/449int450DGifGetImageDesc(GifFileType *GifFile)451{452GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;453SavedImage *sp;454455if (!IS_READABLE(Private)) {456/* This file was NOT open for reading: */457GifFile->Error = D_GIF_ERR_NOT_READABLE;458return GIF_ERROR;459}460461if (DGifGetImageHeader(GifFile) == GIF_ERROR) {462return GIF_ERROR;463}464465if (GifFile->SavedImages) {466SavedImage* new_saved_images =467(SavedImage *)reallocarray(GifFile->SavedImages,468(GifFile->ImageCount + 1), sizeof(SavedImage));469if (new_saved_images == NULL) {470GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;471return GIF_ERROR;472}473GifFile->SavedImages = new_saved_images;474} else {475if ((GifFile->SavedImages =476(SavedImage *) malloc(sizeof(SavedImage))) == NULL) {477GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;478return GIF_ERROR;479}480}481482sp = &GifFile->SavedImages[GifFile->ImageCount];483memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));484if (GifFile->Image.ColorMap != NULL) {485sp->ImageDesc.ColorMap = GifMakeMapObject(486GifFile->Image.ColorMap->ColorCount,487GifFile->Image.ColorMap->Colors);488if (sp->ImageDesc.ColorMap == NULL) {489GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;490return GIF_ERROR;491}492}493sp->RasterBits = (unsigned char *)NULL;494sp->ExtensionBlockCount = 0;495sp->ExtensionBlocks = (ExtensionBlock *) NULL;496497GifFile->ImageCount++;498499return GIF_OK;500}501502/******************************************************************************503Get one full scanned line (Line) of length LineLen from GIF file.504******************************************************************************/505int506DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)507{508GifByteType *Dummy;509GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;510511if (!IS_READABLE(Private)) {512/* This file was NOT open for reading: */513GifFile->Error = D_GIF_ERR_NOT_READABLE;514return GIF_ERROR;515}516517if (!LineLen)518LineLen = GifFile->Image.Width;519520if ((Private->PixelCount -= LineLen) > 0xffff0000UL) {521GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;522return GIF_ERROR;523}524525if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {526if (Private->PixelCount == 0) {527/* We probably won't be called any more, so let's clean up528* everything before we return: need to flush out all the529* rest of image until an empty block (size 0)530* detected. We use GetCodeNext.531*/532do533if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)534return GIF_ERROR;535while (Dummy != NULL) ;536}537return GIF_OK;538} else539return GIF_ERROR;540}541542/******************************************************************************543Put one pixel (Pixel) into GIF file.544******************************************************************************/545int546DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)547{548GifByteType *Dummy;549GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;550551if (!IS_READABLE(Private)) {552/* This file was NOT open for reading: */553GifFile->Error = D_GIF_ERR_NOT_READABLE;554return GIF_ERROR;555}556if (--Private->PixelCount > 0xffff0000UL)557{558GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;559return GIF_ERROR;560}561562if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {563if (Private->PixelCount == 0) {564/* We probably won't be called any more, so let's clean up565* everything before we return: need to flush out all the566* rest of image until an empty block (size 0)567* detected. We use GetCodeNext.568*/569do570if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)571return GIF_ERROR;572while (Dummy != NULL) ;573}574return GIF_OK;575} else576return GIF_ERROR;577}578579/******************************************************************************580Get an extension block (see GIF manual) from GIF file. This routine only581returns the first data block, and DGifGetExtensionNext should be called582after this one until NULL extension is returned.583The Extension should NOT be freed by the user (not dynamically allocated).584Note it is assumed the Extension description header has been read.585******************************************************************************/586int587DGifGetExtension(GifFileType *GifFile, int *ExtCode, GifByteType **Extension)588{589GifByteType Buf;590GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;591592//fprintf(stderr, "### -> DGifGetExtension:\n");593if (!IS_READABLE(Private)) {594/* This file was NOT open for reading: */595GifFile->Error = D_GIF_ERR_NOT_READABLE;596return GIF_ERROR;597}598599/* coverity[check_return] */600if (InternalRead(GifFile, &Buf, 1) != 1) {601GifFile->Error = D_GIF_ERR_READ_FAILED;602return GIF_ERROR;603}604*ExtCode = Buf;605//fprintf(stderr, "### <- DGifGetExtension: %02x, about to call next\n", Buf);606607return DGifGetExtensionNext(GifFile, Extension);608}609610/******************************************************************************611Get a following extension block (see GIF manual) from GIF file. This612routine should be called until NULL Extension is returned.613The Extension should NOT be freed by the user (not dynamically allocated).614******************************************************************************/615int616DGifGetExtensionNext(GifFileType *GifFile, GifByteType ** Extension)617{618GifByteType Buf;619GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;620621//fprintf(stderr, "### -> DGifGetExtensionNext\n");622if (InternalRead(GifFile, &Buf, 1) != 1) {623GifFile->Error = D_GIF_ERR_READ_FAILED;624return GIF_ERROR;625}626//fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);627628if (Buf > 0) {629*Extension = Private->Buf; /* Use private unused buffer. */630(*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */631/* coverity[tainted_data,check_return] */632if (InternalRead(GifFile, &((*Extension)[1]), Buf) != Buf) {633GifFile->Error = D_GIF_ERR_READ_FAILED;634return GIF_ERROR;635}636} else637*Extension = NULL;638//fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);639640return GIF_OK;641}642643/******************************************************************************644Extract a Graphics Control Block from raw extension data645******************************************************************************/646647int DGifExtensionToGCB(const size_t GifExtensionLength,648const GifByteType *GifExtension,649GraphicsControlBlock *GCB)650{651if (GifExtensionLength != 4) {652return GIF_ERROR;653}654655GCB->DisposalMode = (GifExtension[0] >> 2) & 0x07;656GCB->UserInputFlag = (GifExtension[0] & 0x02) != 0;657GCB->DelayTime = UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);658if (GifExtension[0] & 0x01)659GCB->TransparentColor = (int)GifExtension[3];660else661GCB->TransparentColor = NO_TRANSPARENT_COLOR;662663return GIF_OK;664}665666/******************************************************************************667Extract the Graphics Control Block for a saved image, if it exists.668******************************************************************************/669670int DGifSavedExtensionToGCB(GifFileType *GifFile,671int ImageIndex, GraphicsControlBlock *GCB)672{673int i;674675if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1)676return GIF_ERROR;677678GCB->DisposalMode = DISPOSAL_UNSPECIFIED;679GCB->UserInputFlag = false;680GCB->DelayTime = 0;681GCB->TransparentColor = NO_TRANSPARENT_COLOR;682683for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {684ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];685if (ep->Function == GRAPHICS_EXT_FUNC_CODE)686return DGifExtensionToGCB(ep->ByteCount, ep->Bytes, GCB);687}688689return GIF_ERROR;690}691692/******************************************************************************693This routine should be called last, to close the GIF file.694******************************************************************************/695int696DGifCloseFile(GifFileType *GifFile, int *ErrorCode)697{698GifFilePrivateType *Private;699700if (GifFile == NULL || GifFile->Private == NULL)701return GIF_ERROR;702703if (GifFile->Image.ColorMap) {704GifFreeMapObject(GifFile->Image.ColorMap);705GifFile->Image.ColorMap = NULL;706}707708if (GifFile->SColorMap) {709GifFreeMapObject(GifFile->SColorMap);710GifFile->SColorMap = NULL;711}712713if (GifFile->SavedImages) {714GifFreeSavedImages(GifFile);715GifFile->SavedImages = NULL;716}717718GifFreeExtensions(&GifFile->ExtensionBlockCount, &GifFile->ExtensionBlocks);719720Private = (GifFilePrivateType *) GifFile->Private;721722if (!IS_READABLE(Private)) {723/* This file was NOT open for reading: */724if (ErrorCode != NULL)725*ErrorCode = D_GIF_ERR_NOT_READABLE;726free((char *)GifFile->Private);727free(GifFile);728return GIF_ERROR;729}730731if (Private->File && (fclose(Private->File) != 0)) {732if (ErrorCode != NULL)733*ErrorCode = D_GIF_ERR_CLOSE_FAILED;734free((char *)GifFile->Private);735free(GifFile);736return GIF_ERROR;737}738739free((char *)GifFile->Private);740free(GifFile);741if (ErrorCode != NULL)742*ErrorCode = D_GIF_SUCCEEDED;743return GIF_OK;744}745746/******************************************************************************747Get 2 bytes (word) from the given file:748******************************************************************************/749static int750DGifGetWord(GifFileType *GifFile, GifWord *Word)751{752unsigned char c[2];753754/* coverity[check_return] */755if (InternalRead(GifFile, c, 2) != 2) {756GifFile->Error = D_GIF_ERR_READ_FAILED;757return GIF_ERROR;758}759760*Word = (GifWord)UNSIGNED_LITTLE_ENDIAN(c[0], c[1]);761return GIF_OK;762}763764/******************************************************************************765Get the image code in compressed form. This routine can be called if the766information needed to be piped out as is. Obviously this is much faster767than decoding and encoding again. This routine should be followed by calls768to DGifGetCodeNext, until NULL block is returned.769The block should NOT be freed by the user (not dynamically allocated).770******************************************************************************/771int772DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)773{774GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;775776if (!IS_READABLE(Private)) {777/* This file was NOT open for reading: */778GifFile->Error = D_GIF_ERR_NOT_READABLE;779return GIF_ERROR;780}781782*CodeSize = Private->BitsPerPixel;783784return DGifGetCodeNext(GifFile, CodeBlock);785}786787/******************************************************************************788Continue to get the image code in compressed form. This routine should be789called until NULL block is returned.790The block should NOT be freed by the user (not dynamically allocated).791******************************************************************************/792int793DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)794{795GifByteType Buf;796GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;797798/* coverity[tainted_data_argument] */799/* coverity[check_return] */800if (InternalRead(GifFile, &Buf, 1) != 1) {801GifFile->Error = D_GIF_ERR_READ_FAILED;802return GIF_ERROR;803}804805/* coverity[lower_bounds] */806if (Buf > 0) {807*CodeBlock = Private->Buf; /* Use private unused buffer. */808(*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */809/* coverity[tainted_data] */810if (InternalRead(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {811GifFile->Error = D_GIF_ERR_READ_FAILED;812return GIF_ERROR;813}814} else {815*CodeBlock = NULL;816Private->Buf[0] = 0; /* Make sure the buffer is empty! */817Private->PixelCount = 0; /* And local info. indicate image read. */818}819820return GIF_OK;821}822823/******************************************************************************824Setup the LZ decompression for this image:825******************************************************************************/826static int827DGifSetupDecompress(GifFileType *GifFile)828{829int i, BitsPerPixel;830GifByteType CodeSize;831GifPrefixType *Prefix;832GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;833834/* coverity[check_return] */835if (InternalRead(GifFile, &CodeSize, 1) < 1) { /* Read Code size from file. */836return GIF_ERROR; /* Failed to read Code size. */837}838BitsPerPixel = CodeSize;839840/* this can only happen on a severely malformed GIF */841if (BitsPerPixel > 8) {842GifFile->Error = D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */843return GIF_ERROR; /* Failed to read Code size. */844}845846Private->Buf[0] = 0; /* Input Buffer empty. */847Private->BitsPerPixel = BitsPerPixel;848Private->ClearCode = (1 << BitsPerPixel);849Private->EOFCode = Private->ClearCode + 1;850Private->RunningCode = Private->EOFCode + 1;851Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */852Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */853Private->StackPtr = 0; /* No pixels on the pixel stack. */854Private->LastCode = NO_SUCH_CODE;855Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */856Private->CrntShiftDWord = 0;857858Prefix = Private->Prefix;859for (i = 0; i <= LZ_MAX_CODE; i++)860Prefix[i] = NO_SUCH_CODE;861862return GIF_OK;863}864865/******************************************************************************866The LZ decompression routine:867This version decompress the given GIF file into Line of length LineLen.868This routine can be called few times (one per scan line, for example), in869order the complete the whole image.870******************************************************************************/871static int872DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)873{874int i = 0;875int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;876GifByteType *Stack, *Suffix;877GifPrefixType *Prefix;878GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;879880StackPtr = Private->StackPtr;881Prefix = Private->Prefix;882Suffix = Private->Suffix;883Stack = Private->Stack;884EOFCode = Private->EOFCode;885ClearCode = Private->ClearCode;886LastCode = Private->LastCode;887888if (StackPtr > LZ_MAX_CODE) {889return GIF_ERROR;890}891892if (StackPtr != 0) {893/* Let pop the stack off before continueing to read the GIF file: */894while (StackPtr != 0 && i < LineLen)895Line[i++] = Stack[--StackPtr];896}897898while (i < LineLen) { /* Decode LineLen items. */899if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR)900return GIF_ERROR;901902if (CrntCode == EOFCode) {903/* Note however that usually we will not be here as we will stop904* decoding as soon as we got all the pixel, or EOF code will905* not be read at all, and DGifGetLine/Pixel clean everything. */906GifFile->Error = D_GIF_ERR_EOF_TOO_SOON;907return GIF_ERROR;908} else if (CrntCode == ClearCode) {909/* We need to start over again: */910for (j = 0; j <= LZ_MAX_CODE; j++)911Prefix[j] = NO_SUCH_CODE;912Private->RunningCode = Private->EOFCode + 1;913Private->RunningBits = Private->BitsPerPixel + 1;914Private->MaxCode1 = 1 << Private->RunningBits;915LastCode = Private->LastCode = NO_SUCH_CODE;916} else {917/* Its regular code - if in pixel range simply add it to output918* stream, otherwise trace to codes linked list until the prefix919* is in pixel range: */920if (CrntCode < ClearCode) {921/* This is simple - its pixel scalar, so add it to output: */922Line[i++] = CrntCode;923} else {924/* Its a code to needed to be traced: trace the linked list925* until the prefix is a pixel, while pushing the suffix926* pixels on our stack. If we done, pop the stack in reverse927* (thats what stack is good for!) order to output. */928if (Prefix[CrntCode] == NO_SUCH_CODE) {929CrntPrefix = LastCode;930931/* Only allowed if CrntCode is exactly the running code:932* In that case CrntCode = XXXCode, CrntCode or the933* prefix code is last code and the suffix char is934* exactly the prefix of last code! */935if (CrntCode == Private->RunningCode - 2) {936Suffix[Private->RunningCode - 2] =937Stack[StackPtr++] = DGifGetPrefixChar(Prefix,938LastCode,939ClearCode);940} else {941Suffix[Private->RunningCode - 2] =942Stack[StackPtr++] = DGifGetPrefixChar(Prefix,943CrntCode,944ClearCode);945}946} else947CrntPrefix = CrntCode;948949/* Now (if image is O.K.) we should not get a NO_SUCH_CODE950* during the trace. As we might loop forever, in case of951* defective image, we use StackPtr as loop counter and stop952* before overflowing Stack[]. */953while (StackPtr < LZ_MAX_CODE &&954CrntPrefix > ClearCode && CrntPrefix <= LZ_MAX_CODE) {955Stack[StackPtr++] = Suffix[CrntPrefix];956CrntPrefix = Prefix[CrntPrefix];957}958if (StackPtr >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {959GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;960return GIF_ERROR;961}962/* Push the last character on stack: */963Stack[StackPtr++] = CrntPrefix;964965/* Now lets pop all the stack into output: */966while (StackPtr != 0 && i < LineLen)967Line[i++] = Stack[--StackPtr];968}969if (LastCode != NO_SUCH_CODE && Private->RunningCode - 2 < (LZ_MAX_CODE+1) && Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {970Prefix[Private->RunningCode - 2] = LastCode;971972if (CrntCode == Private->RunningCode - 2) {973/* Only allowed if CrntCode is exactly the running code:974* In that case CrntCode = XXXCode, CrntCode or the975* prefix code is last code and the suffix char is976* exactly the prefix of last code! */977Suffix[Private->RunningCode - 2] =978DGifGetPrefixChar(Prefix, LastCode, ClearCode);979} else {980Suffix[Private->RunningCode - 2] =981DGifGetPrefixChar(Prefix, CrntCode, ClearCode);982}983}984LastCode = CrntCode;985}986}987988Private->LastCode = LastCode;989Private->StackPtr = StackPtr;990991return GIF_OK;992}993994/******************************************************************************995Routine to trace the Prefixes linked list until we get a prefix which is996not code, but a pixel value (less than ClearCode). Returns that pixel value.997If image is defective, we might loop here forever, so we limit the loops to998the maximum possible if image O.k. - LZ_MAX_CODE times.999******************************************************************************/1000static int1001DGifGetPrefixChar(GifPrefixType *Prefix, int Code, int ClearCode)1002{1003int i = 0;10041005while (Code > ClearCode && i++ <= LZ_MAX_CODE) {1006if (Code > LZ_MAX_CODE) {1007return NO_SUCH_CODE;1008}1009Code = Prefix[Code];1010}1011return Code;1012}10131014/******************************************************************************1015Interface for accessing the LZ codes directly. Set Code to the real code1016(12bits), or to -1 if EOF code is returned.1017******************************************************************************/1018int1019DGifGetLZCodes(GifFileType *GifFile, int *Code)1020{1021GifByteType *CodeBlock;1022GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;10231024if (!IS_READABLE(Private)) {1025/* This file was NOT open for reading: */1026GifFile->Error = D_GIF_ERR_NOT_READABLE;1027return GIF_ERROR;1028}10291030if (DGifDecompressInput(GifFile, Code) == GIF_ERROR)1031return GIF_ERROR;10321033if (*Code == Private->EOFCode) {1034/* Skip rest of codes (hopefully only NULL terminating block): */1035do {1036if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR)1037return GIF_ERROR;1038} while (CodeBlock != NULL) ;10391040*Code = -1;1041} else if (*Code == Private->ClearCode) {1042/* We need to start over again: */1043Private->RunningCode = Private->EOFCode + 1;1044Private->RunningBits = Private->BitsPerPixel + 1;1045Private->MaxCode1 = 1 << Private->RunningBits;1046}10471048return GIF_OK;1049}10501051/******************************************************************************1052The LZ decompression input routine:1053This routine is responsable for the decompression of the bit stream from10548 bits (bytes) packets, into the real codes.1055Returns GIF_OK if read successfully.1056******************************************************************************/1057static int1058DGifDecompressInput(GifFileType *GifFile, int *Code)1059{1060static const unsigned short CodeMasks[] = {10610x0000, 0x0001, 0x0003, 0x0007,10620x000f, 0x001f, 0x003f, 0x007f,10630x00ff, 0x01ff, 0x03ff, 0x07ff,10640x0fff1065};10661067GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;10681069GifByteType NextByte;10701071/* The image can't contain more than LZ_BITS per code. */1072if (Private->RunningBits > LZ_BITS) {1073GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;1074return GIF_ERROR;1075}10761077while (Private->CrntShiftState < Private->RunningBits) {1078/* Needs to get more bytes from input stream for next code: */1079if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) == GIF_ERROR) {1080return GIF_ERROR;1081}1082Private->CrntShiftDWord |=1083((unsigned long)NextByte) << Private->CrntShiftState;1084Private->CrntShiftState += 8;1085}1086*Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];10871088Private->CrntShiftDWord >>= Private->RunningBits;1089Private->CrntShiftState -= Private->RunningBits;10901091/* If code cannot fit into RunningBits bits, must raise its size. Note1092* however that codes above 4095 are used for special signaling.1093* If we're using LZ_BITS bits already and we're at the max code, just1094* keep using the table as it is, don't increment Private->RunningCode.1095*/1096if (Private->RunningCode < LZ_MAX_CODE + 2 &&1097++Private->RunningCode > Private->MaxCode1 &&1098Private->RunningBits < LZ_BITS) {1099Private->MaxCode1 <<= 1;1100Private->RunningBits++;1101}1102return GIF_OK;1103}11041105/******************************************************************************1106This routines read one GIF data block at a time and buffers it internally1107so that the decompression routine could access it.1108The routine returns the next byte from its internal buffer (or read next1109block in if buffer empty) and returns GIF_OK if succesful.1110******************************************************************************/1111static int1112DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf, GifByteType *NextByte)1113{1114if (Buf[0] == 0) {1115/* Needs to read the next buffer - this one is empty: */1116/* coverity[check_return] */1117if (InternalRead(GifFile, Buf, 1) != 1) {1118GifFile->Error = D_GIF_ERR_READ_FAILED;1119return GIF_ERROR;1120}1121/* There shouldn't be any empty data blocks here as the LZW spec1122* says the LZW termination code should come first. Therefore we1123* shouldn't be inside this routine at that point.1124*/1125if (Buf[0] == 0) {1126GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;1127return GIF_ERROR;1128}1129if (InternalRead(GifFile, &Buf[1], Buf[0]) != Buf[0]) {1130GifFile->Error = D_GIF_ERR_READ_FAILED;1131return GIF_ERROR;1132}1133*NextByte = Buf[1];1134Buf[1] = 2; /* We use now the second place as last char read! */1135Buf[0]--;1136} else {1137*NextByte = Buf[Buf[1]++];1138Buf[0]--;1139}11401141return GIF_OK;1142}11431144/******************************************************************************1145This routine reads an entire GIF into core, hanging all its state info off1146the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle()1147first to initialize I/O. Its inverse is EGifSpew().1148*******************************************************************************/1149int1150DGifSlurp(GifFileType *GifFile)1151{1152size_t ImageSize;1153GifRecordType RecordType;1154SavedImage *sp;1155GifByteType *ExtData;1156int ExtFunction;11571158GifFile->ExtensionBlocks = NULL;1159GifFile->ExtensionBlockCount = 0;11601161do {1162if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)1163return (GIF_ERROR);11641165switch (RecordType) {1166case IMAGE_DESC_RECORD_TYPE:1167if (DGifGetImageDesc(GifFile) == GIF_ERROR)1168return (GIF_ERROR);11691170sp = &GifFile->SavedImages[GifFile->ImageCount - 1];1171/* Allocate memory for the image */1172if (sp->ImageDesc.Width <= 0 || sp->ImageDesc.Height <= 0 ||1173sp->ImageDesc.Width > (INT_MAX / sp->ImageDesc.Height)) {1174return GIF_ERROR;1175}1176ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;11771178if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {1179return GIF_ERROR;1180}1181sp->RasterBits = (unsigned char *)reallocarray(NULL, ImageSize,1182sizeof(GifPixelType));11831184if (sp->RasterBits == NULL) {1185return GIF_ERROR;1186}11871188if (sp->ImageDesc.Interlace) {1189int i, j;1190/*1191* The way an interlaced image should be read -1192* offsets and jumps...1193*/1194int InterlacedOffset[] = { 0, 4, 2, 1 };1195int InterlacedJumps[] = { 8, 8, 4, 2 };1196/* Need to perform 4 passes on the image */1197for (i = 0; i < 4; i++)1198for (j = InterlacedOffset[i];1199j < sp->ImageDesc.Height;1200j += InterlacedJumps[i]) {1201if (DGifGetLine(GifFile,1202sp->RasterBits+j*sp->ImageDesc.Width,1203sp->ImageDesc.Width) == GIF_ERROR)1204return GIF_ERROR;1205}1206}1207else {1208if (DGifGetLine(GifFile,sp->RasterBits,ImageSize)==GIF_ERROR)1209return (GIF_ERROR);1210}12111212if (GifFile->ExtensionBlocks) {1213sp->ExtensionBlocks = GifFile->ExtensionBlocks;1214sp->ExtensionBlockCount = GifFile->ExtensionBlockCount;12151216GifFile->ExtensionBlocks = NULL;1217GifFile->ExtensionBlockCount = 0;1218}1219break;12201221case EXTENSION_RECORD_TYPE:1222if (DGifGetExtension(GifFile,&ExtFunction,&ExtData) == GIF_ERROR)1223return (GIF_ERROR);1224/* Create an extension block with our data */1225if (ExtData != NULL) {1226if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,1227&GifFile->ExtensionBlocks,1228ExtFunction, ExtData[0], &ExtData[1])1229== GIF_ERROR)1230return (GIF_ERROR);1231}1232for (;;) {1233if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)1234return (GIF_ERROR);1235if (ExtData == NULL)1236break;1237/* Continue the extension block */1238if (ExtData != NULL)1239if (GifAddExtensionBlock(&GifFile->ExtensionBlockCount,1240&GifFile->ExtensionBlocks,1241CONTINUE_EXT_FUNC_CODE,1242ExtData[0], &ExtData[1]) == GIF_ERROR)1243return (GIF_ERROR);1244}1245break;12461247case TERMINATE_RECORD_TYPE:1248break;12491250default: /* Should be trapped by DGifGetRecordType */1251break;1252}1253} while (RecordType != TERMINATE_RECORD_TYPE);12541255/* Sanity check for corrupted file */1256if (GifFile->ImageCount == 0) {1257GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;1258return(GIF_ERROR);1259}12601261return (GIF_OK);1262}12631264/* end */126512661267