1*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
2*324bb76bSAndroid Build Coastguard Worker
3*324bb76bSAndroid Build Coastguard Worker dgif_lib.c - GIF decoding
4*324bb76bSAndroid Build Coastguard Worker
5*324bb76bSAndroid Build Coastguard Worker The functions here and in egif_lib.c are partitioned carefully so that
6*324bb76bSAndroid Build Coastguard Worker if you only require one of read and write capability, only one of these
7*324bb76bSAndroid Build Coastguard Worker two modules will be linked. Preserve this property!
8*324bb76bSAndroid Build Coastguard Worker
9*324bb76bSAndroid Build Coastguard Worker SPDX-License-Identifier: MIT
10*324bb76bSAndroid Build Coastguard Worker
11*324bb76bSAndroid Build Coastguard Worker *****************************************************************************/
12*324bb76bSAndroid Build Coastguard Worker
13*324bb76bSAndroid Build Coastguard Worker #include <fcntl.h>
14*324bb76bSAndroid Build Coastguard Worker #include <limits.h>
15*324bb76bSAndroid Build Coastguard Worker #include <stdint.h>
16*324bb76bSAndroid Build Coastguard Worker #include <stdio.h>
17*324bb76bSAndroid Build Coastguard Worker #include <stdlib.h>
18*324bb76bSAndroid Build Coastguard Worker #include <string.h>
19*324bb76bSAndroid Build Coastguard Worker
20*324bb76bSAndroid Build Coastguard Worker #ifdef _WIN32
21*324bb76bSAndroid Build Coastguard Worker #include <io.h>
22*324bb76bSAndroid Build Coastguard Worker #else
23*324bb76bSAndroid Build Coastguard Worker #include <unistd.h>
24*324bb76bSAndroid Build Coastguard Worker #endif /* _WIN32 */
25*324bb76bSAndroid Build Coastguard Worker
26*324bb76bSAndroid Build Coastguard Worker #include "gif_lib.h"
27*324bb76bSAndroid Build Coastguard Worker #include "gif_lib_private.h"
28*324bb76bSAndroid Build Coastguard Worker
29*324bb76bSAndroid Build Coastguard Worker /* compose unsigned little endian value */
30*324bb76bSAndroid Build Coastguard Worker #define UNSIGNED_LITTLE_ENDIAN(lo, hi) ((lo) | ((hi) << 8))
31*324bb76bSAndroid Build Coastguard Worker
32*324bb76bSAndroid Build Coastguard Worker /* avoid extra function call in case we use fread (TVT) */
InternalRead(GifFileType * gif,GifByteType * buf,int len)33*324bb76bSAndroid Build Coastguard Worker static int InternalRead(GifFileType *gif, GifByteType *buf, int len) {
34*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### Read: %d\n", len);
35*324bb76bSAndroid Build Coastguard Worker return (((GifFilePrivateType *)gif->Private)->Read
36*324bb76bSAndroid Build Coastguard Worker ? ((GifFilePrivateType *)gif->Private)->Read(gif, buf, len)
37*324bb76bSAndroid Build Coastguard Worker : fread(buf, 1, len,
38*324bb76bSAndroid Build Coastguard Worker ((GifFilePrivateType *)gif->Private)->File));
39*324bb76bSAndroid Build Coastguard Worker }
40*324bb76bSAndroid Build Coastguard Worker
41*324bb76bSAndroid Build Coastguard Worker static int DGifGetWord(GifFileType *GifFile, GifWord *Word);
42*324bb76bSAndroid Build Coastguard Worker static int DGifSetupDecompress(GifFileType *GifFile);
43*324bb76bSAndroid Build Coastguard Worker static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
44*324bb76bSAndroid Build Coastguard Worker int LineLen);
45*324bb76bSAndroid Build Coastguard Worker static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
46*324bb76bSAndroid Build Coastguard Worker int ClearCode);
47*324bb76bSAndroid Build Coastguard Worker static int DGifDecompressInput(GifFileType *GifFile, int *Code);
48*324bb76bSAndroid Build Coastguard Worker static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
49*324bb76bSAndroid Build Coastguard Worker GifByteType *NextByte);
50*324bb76bSAndroid Build Coastguard Worker
51*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
52*324bb76bSAndroid Build Coastguard Worker Open a new GIF file for read, given by its name.
53*324bb76bSAndroid Build Coastguard Worker Returns dynamically allocated GifFileType pointer which serves as the GIF
54*324bb76bSAndroid Build Coastguard Worker info record.
55*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifOpenFileName(const char * FileName,int * Error)56*324bb76bSAndroid Build Coastguard Worker GifFileType *DGifOpenFileName(const char *FileName, int *Error) {
57*324bb76bSAndroid Build Coastguard Worker int FileHandle;
58*324bb76bSAndroid Build Coastguard Worker GifFileType *GifFile;
59*324bb76bSAndroid Build Coastguard Worker
60*324bb76bSAndroid Build Coastguard Worker if ((FileHandle = open(FileName, O_RDONLY)) == -1) {
61*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
62*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_OPEN_FAILED;
63*324bb76bSAndroid Build Coastguard Worker }
64*324bb76bSAndroid Build Coastguard Worker return NULL;
65*324bb76bSAndroid Build Coastguard Worker }
66*324bb76bSAndroid Build Coastguard Worker
67*324bb76bSAndroid Build Coastguard Worker GifFile = DGifOpenFileHandle(FileHandle, Error);
68*324bb76bSAndroid Build Coastguard Worker return GifFile;
69*324bb76bSAndroid Build Coastguard Worker }
70*324bb76bSAndroid Build Coastguard Worker
71*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
72*324bb76bSAndroid Build Coastguard Worker Update a new GIF file, given its file handle.
73*324bb76bSAndroid Build Coastguard Worker Returns dynamically allocated GifFileType pointer which serves as the GIF
74*324bb76bSAndroid Build Coastguard Worker info record.
75*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifOpenFileHandle(int FileHandle,int * Error)76*324bb76bSAndroid Build Coastguard Worker GifFileType *DGifOpenFileHandle(int FileHandle, int *Error) {
77*324bb76bSAndroid Build Coastguard Worker char Buf[GIF_STAMP_LEN + 1];
78*324bb76bSAndroid Build Coastguard Worker GifFileType *GifFile;
79*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private;
80*324bb76bSAndroid Build Coastguard Worker FILE *f;
81*324bb76bSAndroid Build Coastguard Worker
82*324bb76bSAndroid Build Coastguard Worker GifFile = (GifFileType *)malloc(sizeof(GifFileType));
83*324bb76bSAndroid Build Coastguard Worker if (GifFile == NULL) {
84*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
85*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
86*324bb76bSAndroid Build Coastguard Worker }
87*324bb76bSAndroid Build Coastguard Worker (void)close(FileHandle);
88*324bb76bSAndroid Build Coastguard Worker return NULL;
89*324bb76bSAndroid Build Coastguard Worker }
90*324bb76bSAndroid Build Coastguard Worker
91*324bb76bSAndroid Build Coastguard Worker /*@i1@*/ memset(GifFile, '\0', sizeof(GifFileType));
92*324bb76bSAndroid Build Coastguard Worker
93*324bb76bSAndroid Build Coastguard Worker /* Belt and suspenders, in case the null pointer isn't zero */
94*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages = NULL;
95*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
96*324bb76bSAndroid Build Coastguard Worker
97*324bb76bSAndroid Build Coastguard Worker Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
98*324bb76bSAndroid Build Coastguard Worker if (Private == NULL) {
99*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
100*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
101*324bb76bSAndroid Build Coastguard Worker }
102*324bb76bSAndroid Build Coastguard Worker (void)close(FileHandle);
103*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
104*324bb76bSAndroid Build Coastguard Worker return NULL;
105*324bb76bSAndroid Build Coastguard Worker }
106*324bb76bSAndroid Build Coastguard Worker
107*324bb76bSAndroid Build Coastguard Worker /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
108*324bb76bSAndroid Build Coastguard Worker
109*324bb76bSAndroid Build Coastguard Worker #ifdef _WIN32
110*324bb76bSAndroid Build Coastguard Worker _setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
111*324bb76bSAndroid Build Coastguard Worker #endif /* _WIN32 */
112*324bb76bSAndroid Build Coastguard Worker
113*324bb76bSAndroid Build Coastguard Worker f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
114*324bb76bSAndroid Build Coastguard Worker
115*324bb76bSAndroid Build Coastguard Worker /*@-mustfreeonly@*/
116*324bb76bSAndroid Build Coastguard Worker GifFile->Private = (void *)Private;
117*324bb76bSAndroid Build Coastguard Worker Private->FileHandle = FileHandle;
118*324bb76bSAndroid Build Coastguard Worker Private->File = f;
119*324bb76bSAndroid Build Coastguard Worker Private->FileState = FILE_STATE_READ;
120*324bb76bSAndroid Build Coastguard Worker Private->Read = NULL; /* don't use alternate input method (TVT) */
121*324bb76bSAndroid Build Coastguard Worker GifFile->UserData = NULL; /* TVT */
122*324bb76bSAndroid Build Coastguard Worker /*@=mustfreeonly@*/
123*324bb76bSAndroid Build Coastguard Worker
124*324bb76bSAndroid Build Coastguard Worker /* Let's see if this is a GIF file: */
125*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
126*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
127*324bb76bSAndroid Build Coastguard Worker GIF_STAMP_LEN) {
128*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
129*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_READ_FAILED;
130*324bb76bSAndroid Build Coastguard Worker }
131*324bb76bSAndroid Build Coastguard Worker (void)fclose(f);
132*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
133*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
134*324bb76bSAndroid Build Coastguard Worker return NULL;
135*324bb76bSAndroid Build Coastguard Worker }
136*324bb76bSAndroid Build Coastguard Worker
137*324bb76bSAndroid Build Coastguard Worker /* Check for GIF prefix at start of file */
138*324bb76bSAndroid Build Coastguard Worker Buf[GIF_STAMP_LEN] = 0;
139*324bb76bSAndroid Build Coastguard Worker if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
140*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
141*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_GIF_FILE;
142*324bb76bSAndroid Build Coastguard Worker }
143*324bb76bSAndroid Build Coastguard Worker (void)fclose(f);
144*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
145*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
146*324bb76bSAndroid Build Coastguard Worker return NULL;
147*324bb76bSAndroid Build Coastguard Worker }
148*324bb76bSAndroid Build Coastguard Worker
149*324bb76bSAndroid Build Coastguard Worker if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
150*324bb76bSAndroid Build Coastguard Worker (void)fclose(f);
151*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
152*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
153*324bb76bSAndroid Build Coastguard Worker return NULL;
154*324bb76bSAndroid Build Coastguard Worker }
155*324bb76bSAndroid Build Coastguard Worker
156*324bb76bSAndroid Build Coastguard Worker GifFile->Error = 0;
157*324bb76bSAndroid Build Coastguard Worker
158*324bb76bSAndroid Build Coastguard Worker /* What version of GIF? */
159*324bb76bSAndroid Build Coastguard Worker Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
160*324bb76bSAndroid Build Coastguard Worker
161*324bb76bSAndroid Build Coastguard Worker return GifFile;
162*324bb76bSAndroid Build Coastguard Worker }
163*324bb76bSAndroid Build Coastguard Worker
164*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
165*324bb76bSAndroid Build Coastguard Worker GifFileType constructor with user supplied input function (TVT)
166*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifOpen(void * userData,InputFunc readFunc,int * Error)167*324bb76bSAndroid Build Coastguard Worker GifFileType *DGifOpen(void *userData, InputFunc readFunc, int *Error) {
168*324bb76bSAndroid Build Coastguard Worker char Buf[GIF_STAMP_LEN + 1];
169*324bb76bSAndroid Build Coastguard Worker GifFileType *GifFile;
170*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private;
171*324bb76bSAndroid Build Coastguard Worker
172*324bb76bSAndroid Build Coastguard Worker GifFile = (GifFileType *)malloc(sizeof(GifFileType));
173*324bb76bSAndroid Build Coastguard Worker if (GifFile == NULL) {
174*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
175*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
176*324bb76bSAndroid Build Coastguard Worker }
177*324bb76bSAndroid Build Coastguard Worker return NULL;
178*324bb76bSAndroid Build Coastguard Worker }
179*324bb76bSAndroid Build Coastguard Worker
180*324bb76bSAndroid Build Coastguard Worker memset(GifFile, '\0', sizeof(GifFileType));
181*324bb76bSAndroid Build Coastguard Worker
182*324bb76bSAndroid Build Coastguard Worker /* Belt and suspenders, in case the null pointer isn't zero */
183*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages = NULL;
184*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
185*324bb76bSAndroid Build Coastguard Worker
186*324bb76bSAndroid Build Coastguard Worker Private = (GifFilePrivateType *)calloc(1, sizeof(GifFilePrivateType));
187*324bb76bSAndroid Build Coastguard Worker if (!Private) {
188*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
189*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_ENOUGH_MEM;
190*324bb76bSAndroid Build Coastguard Worker }
191*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
192*324bb76bSAndroid Build Coastguard Worker return NULL;
193*324bb76bSAndroid Build Coastguard Worker }
194*324bb76bSAndroid Build Coastguard Worker /*@i1@*/ memset(Private, '\0', sizeof(GifFilePrivateType));
195*324bb76bSAndroid Build Coastguard Worker
196*324bb76bSAndroid Build Coastguard Worker GifFile->Private = (void *)Private;
197*324bb76bSAndroid Build Coastguard Worker Private->FileHandle = 0;
198*324bb76bSAndroid Build Coastguard Worker Private->File = NULL;
199*324bb76bSAndroid Build Coastguard Worker Private->FileState = FILE_STATE_READ;
200*324bb76bSAndroid Build Coastguard Worker
201*324bb76bSAndroid Build Coastguard Worker Private->Read = readFunc; /* TVT */
202*324bb76bSAndroid Build Coastguard Worker GifFile->UserData = userData; /* TVT */
203*324bb76bSAndroid Build Coastguard Worker
204*324bb76bSAndroid Build Coastguard Worker /* Lets see if this is a GIF file: */
205*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
206*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, (unsigned char *)Buf, GIF_STAMP_LEN) !=
207*324bb76bSAndroid Build Coastguard Worker GIF_STAMP_LEN) {
208*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
209*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_READ_FAILED;
210*324bb76bSAndroid Build Coastguard Worker }
211*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
212*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
213*324bb76bSAndroid Build Coastguard Worker return NULL;
214*324bb76bSAndroid Build Coastguard Worker }
215*324bb76bSAndroid Build Coastguard Worker
216*324bb76bSAndroid Build Coastguard Worker /* Check for GIF prefix at start of file */
217*324bb76bSAndroid Build Coastguard Worker Buf[GIF_STAMP_LEN] = '\0';
218*324bb76bSAndroid Build Coastguard Worker if (strncmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
219*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
220*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NOT_GIF_FILE;
221*324bb76bSAndroid Build Coastguard Worker }
222*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
223*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
224*324bb76bSAndroid Build Coastguard Worker return NULL;
225*324bb76bSAndroid Build Coastguard Worker }
226*324bb76bSAndroid Build Coastguard Worker
227*324bb76bSAndroid Build Coastguard Worker if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
228*324bb76bSAndroid Build Coastguard Worker free((char *)Private);
229*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile);
230*324bb76bSAndroid Build Coastguard Worker if (Error != NULL) {
231*324bb76bSAndroid Build Coastguard Worker *Error = D_GIF_ERR_NO_SCRN_DSCR;
232*324bb76bSAndroid Build Coastguard Worker }
233*324bb76bSAndroid Build Coastguard Worker return NULL;
234*324bb76bSAndroid Build Coastguard Worker }
235*324bb76bSAndroid Build Coastguard Worker
236*324bb76bSAndroid Build Coastguard Worker GifFile->Error = 0;
237*324bb76bSAndroid Build Coastguard Worker
238*324bb76bSAndroid Build Coastguard Worker /* What version of GIF? */
239*324bb76bSAndroid Build Coastguard Worker Private->gif89 = (Buf[GIF_VERSION_POS + 1] == '9');
240*324bb76bSAndroid Build Coastguard Worker
241*324bb76bSAndroid Build Coastguard Worker return GifFile;
242*324bb76bSAndroid Build Coastguard Worker }
243*324bb76bSAndroid Build Coastguard Worker
244*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
245*324bb76bSAndroid Build Coastguard Worker This routine should be called before any other DGif calls. Note that
246*324bb76bSAndroid Build Coastguard Worker this routine is called automatically from DGif file open routines.
247*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetScreenDesc(GifFileType * GifFile)248*324bb76bSAndroid Build Coastguard Worker int DGifGetScreenDesc(GifFileType *GifFile) {
249*324bb76bSAndroid Build Coastguard Worker int BitsPerPixel;
250*324bb76bSAndroid Build Coastguard Worker bool SortFlag;
251*324bb76bSAndroid Build Coastguard Worker GifByteType Buf[3];
252*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
253*324bb76bSAndroid Build Coastguard Worker
254*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
255*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
256*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
257*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
258*324bb76bSAndroid Build Coastguard Worker }
259*324bb76bSAndroid Build Coastguard Worker
260*324bb76bSAndroid Build Coastguard Worker /* Put the screen descriptor into the file: */
261*324bb76bSAndroid Build Coastguard Worker if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||
262*324bb76bSAndroid Build Coastguard Worker DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR) {
263*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
264*324bb76bSAndroid Build Coastguard Worker }
265*324bb76bSAndroid Build Coastguard Worker
266*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, Buf, 3) != 3) {
267*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
268*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->SColorMap);
269*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
270*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
271*324bb76bSAndroid Build Coastguard Worker }
272*324bb76bSAndroid Build Coastguard Worker GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
273*324bb76bSAndroid Build Coastguard Worker SortFlag = (Buf[0] & 0x08) != 0;
274*324bb76bSAndroid Build Coastguard Worker BitsPerPixel = (Buf[0] & 0x07) + 1;
275*324bb76bSAndroid Build Coastguard Worker GifFile->SBackGroundColor = Buf[1];
276*324bb76bSAndroid Build Coastguard Worker GifFile->AspectByte = Buf[2];
277*324bb76bSAndroid Build Coastguard Worker if (Buf[0] & 0x80) { /* Do we have global color map? */
278*324bb76bSAndroid Build Coastguard Worker int i;
279*324bb76bSAndroid Build Coastguard Worker
280*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = GifMakeMapObject(1 << BitsPerPixel, NULL);
281*324bb76bSAndroid Build Coastguard Worker if (GifFile->SColorMap == NULL) {
282*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
283*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
284*324bb76bSAndroid Build Coastguard Worker }
285*324bb76bSAndroid Build Coastguard Worker
286*324bb76bSAndroid Build Coastguard Worker /* Get the global color map: */
287*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap->SortFlag = SortFlag;
288*324bb76bSAndroid Build Coastguard Worker for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
289*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
290*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, Buf, 3) != 3) {
291*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->SColorMap);
292*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
293*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
294*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
295*324bb76bSAndroid Build Coastguard Worker }
296*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap->Colors[i].Red = Buf[0];
297*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap->Colors[i].Green = Buf[1];
298*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap->Colors[i].Blue = Buf[2];
299*324bb76bSAndroid Build Coastguard Worker }
300*324bb76bSAndroid Build Coastguard Worker } else {
301*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
302*324bb76bSAndroid Build Coastguard Worker }
303*324bb76bSAndroid Build Coastguard Worker
304*324bb76bSAndroid Build Coastguard Worker /*
305*324bb76bSAndroid Build Coastguard Worker * No check here for whether the background color is in range for the
306*324bb76bSAndroid Build Coastguard Worker * screen color map. Possibly there should be.
307*324bb76bSAndroid Build Coastguard Worker */
308*324bb76bSAndroid Build Coastguard Worker
309*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
310*324bb76bSAndroid Build Coastguard Worker }
311*324bb76bSAndroid Build Coastguard Worker
DGifGetGifVersion(GifFileType * GifFile)312*324bb76bSAndroid Build Coastguard Worker const char *DGifGetGifVersion(GifFileType *GifFile) {
313*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
314*324bb76bSAndroid Build Coastguard Worker
315*324bb76bSAndroid Build Coastguard Worker if (Private->gif89) {
316*324bb76bSAndroid Build Coastguard Worker return GIF89_STAMP;
317*324bb76bSAndroid Build Coastguard Worker } else {
318*324bb76bSAndroid Build Coastguard Worker return GIF87_STAMP;
319*324bb76bSAndroid Build Coastguard Worker }
320*324bb76bSAndroid Build Coastguard Worker }
321*324bb76bSAndroid Build Coastguard Worker
322*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
323*324bb76bSAndroid Build Coastguard Worker This routine should be called before any attempt to read an image.
324*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetRecordType(GifFileType * GifFile,GifRecordType * Type)325*324bb76bSAndroid Build Coastguard Worker int DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type) {
326*324bb76bSAndroid Build Coastguard Worker GifByteType Buf;
327*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
328*324bb76bSAndroid Build Coastguard Worker
329*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
330*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
331*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
332*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
333*324bb76bSAndroid Build Coastguard Worker }
334*324bb76bSAndroid Build Coastguard Worker
335*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
336*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &Buf, 1) != 1) {
337*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
338*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
339*324bb76bSAndroid Build Coastguard Worker }
340*324bb76bSAndroid Build Coastguard Worker
341*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### DGifGetRecordType: %02x\n", Buf);
342*324bb76bSAndroid Build Coastguard Worker switch (Buf) {
343*324bb76bSAndroid Build Coastguard Worker case DESCRIPTOR_INTRODUCER:
344*324bb76bSAndroid Build Coastguard Worker *Type = IMAGE_DESC_RECORD_TYPE;
345*324bb76bSAndroid Build Coastguard Worker break;
346*324bb76bSAndroid Build Coastguard Worker case EXTENSION_INTRODUCER:
347*324bb76bSAndroid Build Coastguard Worker *Type = EXTENSION_RECORD_TYPE;
348*324bb76bSAndroid Build Coastguard Worker break;
349*324bb76bSAndroid Build Coastguard Worker case TERMINATOR_INTRODUCER:
350*324bb76bSAndroid Build Coastguard Worker *Type = TERMINATE_RECORD_TYPE;
351*324bb76bSAndroid Build Coastguard Worker break;
352*324bb76bSAndroid Build Coastguard Worker default:
353*324bb76bSAndroid Build Coastguard Worker *Type = UNDEFINED_RECORD_TYPE;
354*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_WRONG_RECORD;
355*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
356*324bb76bSAndroid Build Coastguard Worker }
357*324bb76bSAndroid Build Coastguard Worker
358*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
359*324bb76bSAndroid Build Coastguard Worker }
360*324bb76bSAndroid Build Coastguard Worker
DGifGetImageHeader(GifFileType * GifFile)361*324bb76bSAndroid Build Coastguard Worker int DGifGetImageHeader(GifFileType *GifFile) {
362*324bb76bSAndroid Build Coastguard Worker unsigned int BitsPerPixel;
363*324bb76bSAndroid Build Coastguard Worker GifByteType Buf[3];
364*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
365*324bb76bSAndroid Build Coastguard Worker
366*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
367*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
368*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
369*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
370*324bb76bSAndroid Build Coastguard Worker }
371*324bb76bSAndroid Build Coastguard Worker
372*324bb76bSAndroid Build Coastguard Worker if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||
373*324bb76bSAndroid Build Coastguard Worker DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||
374*324bb76bSAndroid Build Coastguard Worker DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||
375*324bb76bSAndroid Build Coastguard Worker DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR) {
376*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
377*324bb76bSAndroid Build Coastguard Worker }
378*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, Buf, 1) != 1) {
379*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
380*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->Image.ColorMap);
381*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap = NULL;
382*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
383*324bb76bSAndroid Build Coastguard Worker }
384*324bb76bSAndroid Build Coastguard Worker BitsPerPixel = (Buf[0] & 0x07) + 1;
385*324bb76bSAndroid Build Coastguard Worker GifFile->Image.Interlace = (Buf[0] & 0x40) ? true : false;
386*324bb76bSAndroid Build Coastguard Worker
387*324bb76bSAndroid Build Coastguard Worker /* Setup the colormap */
388*324bb76bSAndroid Build Coastguard Worker if (GifFile->Image.ColorMap) {
389*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->Image.ColorMap);
390*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap = NULL;
391*324bb76bSAndroid Build Coastguard Worker }
392*324bb76bSAndroid Build Coastguard Worker /* Does this image have local color map? */
393*324bb76bSAndroid Build Coastguard Worker if (Buf[0] & 0x80) {
394*324bb76bSAndroid Build Coastguard Worker unsigned int i;
395*324bb76bSAndroid Build Coastguard Worker
396*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap =
397*324bb76bSAndroid Build Coastguard Worker GifMakeMapObject(1 << BitsPerPixel, NULL);
398*324bb76bSAndroid Build Coastguard Worker if (GifFile->Image.ColorMap == NULL) {
399*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
400*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
401*324bb76bSAndroid Build Coastguard Worker }
402*324bb76bSAndroid Build Coastguard Worker
403*324bb76bSAndroid Build Coastguard Worker /* Get the image local color map: */
404*324bb76bSAndroid Build Coastguard Worker for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
405*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
406*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, Buf, 3) != 3) {
407*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->Image.ColorMap);
408*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
409*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap = NULL;
410*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
411*324bb76bSAndroid Build Coastguard Worker }
412*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
413*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
414*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
415*324bb76bSAndroid Build Coastguard Worker }
416*324bb76bSAndroid Build Coastguard Worker }
417*324bb76bSAndroid Build Coastguard Worker
418*324bb76bSAndroid Build Coastguard Worker Private->PixelCount =
419*324bb76bSAndroid Build Coastguard Worker (long)GifFile->Image.Width * (long)GifFile->Image.Height;
420*324bb76bSAndroid Build Coastguard Worker
421*324bb76bSAndroid Build Coastguard Worker /* Reset decompress algorithm parameters. */
422*324bb76bSAndroid Build Coastguard Worker return DGifSetupDecompress(GifFile);
423*324bb76bSAndroid Build Coastguard Worker }
424*324bb76bSAndroid Build Coastguard Worker
425*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
426*324bb76bSAndroid Build Coastguard Worker This routine should be called before any attempt to read an image.
427*324bb76bSAndroid Build Coastguard Worker Note it is assumed the Image desc. header has been read.
428*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetImageDesc(GifFileType * GifFile)429*324bb76bSAndroid Build Coastguard Worker int DGifGetImageDesc(GifFileType *GifFile) {
430*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
431*324bb76bSAndroid Build Coastguard Worker SavedImage *sp;
432*324bb76bSAndroid Build Coastguard Worker
433*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
434*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
435*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
436*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
437*324bb76bSAndroid Build Coastguard Worker }
438*324bb76bSAndroid Build Coastguard Worker
439*324bb76bSAndroid Build Coastguard Worker if (DGifGetImageHeader(GifFile) == GIF_ERROR) {
440*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
441*324bb76bSAndroid Build Coastguard Worker }
442*324bb76bSAndroid Build Coastguard Worker
443*324bb76bSAndroid Build Coastguard Worker if (GifFile->SavedImages) {
444*324bb76bSAndroid Build Coastguard Worker SavedImage *new_saved_images = (SavedImage *)reallocarray(
445*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages, (GifFile->ImageCount + 1),
446*324bb76bSAndroid Build Coastguard Worker sizeof(SavedImage));
447*324bb76bSAndroid Build Coastguard Worker if (new_saved_images == NULL) {
448*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
449*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
450*324bb76bSAndroid Build Coastguard Worker }
451*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages = new_saved_images;
452*324bb76bSAndroid Build Coastguard Worker } else {
453*324bb76bSAndroid Build Coastguard Worker if ((GifFile->SavedImages =
454*324bb76bSAndroid Build Coastguard Worker (SavedImage *)malloc(sizeof(SavedImage))) == NULL) {
455*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
456*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
457*324bb76bSAndroid Build Coastguard Worker }
458*324bb76bSAndroid Build Coastguard Worker }
459*324bb76bSAndroid Build Coastguard Worker
460*324bb76bSAndroid Build Coastguard Worker sp = &GifFile->SavedImages[GifFile->ImageCount];
461*324bb76bSAndroid Build Coastguard Worker memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
462*324bb76bSAndroid Build Coastguard Worker if (GifFile->Image.ColorMap != NULL) {
463*324bb76bSAndroid Build Coastguard Worker sp->ImageDesc.ColorMap =
464*324bb76bSAndroid Build Coastguard Worker GifMakeMapObject(GifFile->Image.ColorMap->ColorCount,
465*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap->Colors);
466*324bb76bSAndroid Build Coastguard Worker if (sp->ImageDesc.ColorMap == NULL) {
467*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_ENOUGH_MEM;
468*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
469*324bb76bSAndroid Build Coastguard Worker }
470*324bb76bSAndroid Build Coastguard Worker }
471*324bb76bSAndroid Build Coastguard Worker sp->RasterBits = (unsigned char *)NULL;
472*324bb76bSAndroid Build Coastguard Worker sp->ExtensionBlockCount = 0;
473*324bb76bSAndroid Build Coastguard Worker sp->ExtensionBlocks = (ExtensionBlock *)NULL;
474*324bb76bSAndroid Build Coastguard Worker
475*324bb76bSAndroid Build Coastguard Worker GifFile->ImageCount++;
476*324bb76bSAndroid Build Coastguard Worker
477*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
478*324bb76bSAndroid Build Coastguard Worker }
479*324bb76bSAndroid Build Coastguard Worker
480*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
481*324bb76bSAndroid Build Coastguard Worker Get one full scanned line (Line) of length LineLen from GIF file.
482*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetLine(GifFileType * GifFile,GifPixelType * Line,int LineLen)483*324bb76bSAndroid Build Coastguard Worker int DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen) {
484*324bb76bSAndroid Build Coastguard Worker GifByteType *Dummy;
485*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
486*324bb76bSAndroid Build Coastguard Worker
487*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
488*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
489*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
490*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
491*324bb76bSAndroid Build Coastguard Worker }
492*324bb76bSAndroid Build Coastguard Worker
493*324bb76bSAndroid Build Coastguard Worker if (!LineLen) {
494*324bb76bSAndroid Build Coastguard Worker LineLen = GifFile->Image.Width;
495*324bb76bSAndroid Build Coastguard Worker }
496*324bb76bSAndroid Build Coastguard Worker
497*324bb76bSAndroid Build Coastguard Worker if ((Private->PixelCount -= LineLen) > 0xffff0000UL) {
498*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
499*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
500*324bb76bSAndroid Build Coastguard Worker }
501*324bb76bSAndroid Build Coastguard Worker
502*324bb76bSAndroid Build Coastguard Worker if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
503*324bb76bSAndroid Build Coastguard Worker if (Private->PixelCount == 0) {
504*324bb76bSAndroid Build Coastguard Worker /* We probably won't be called any more, so let's clean
505*324bb76bSAndroid Build Coastguard Worker * up everything before we return: need to flush out all
506*324bb76bSAndroid Build Coastguard Worker * the rest of image until an empty block (size 0)
507*324bb76bSAndroid Build Coastguard Worker * detected. We use GetCodeNext.
508*324bb76bSAndroid Build Coastguard Worker */
509*324bb76bSAndroid Build Coastguard Worker do {
510*324bb76bSAndroid Build Coastguard Worker if (DGifGetCodeNext(GifFile, &Dummy) ==
511*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
512*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
513*324bb76bSAndroid Build Coastguard Worker }
514*324bb76bSAndroid Build Coastguard Worker } while (Dummy != NULL);
515*324bb76bSAndroid Build Coastguard Worker }
516*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
517*324bb76bSAndroid Build Coastguard Worker } else {
518*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
519*324bb76bSAndroid Build Coastguard Worker }
520*324bb76bSAndroid Build Coastguard Worker }
521*324bb76bSAndroid Build Coastguard Worker
522*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
523*324bb76bSAndroid Build Coastguard Worker Put one pixel (Pixel) into GIF file.
524*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetPixel(GifFileType * GifFile,GifPixelType Pixel)525*324bb76bSAndroid Build Coastguard Worker int DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel) {
526*324bb76bSAndroid Build Coastguard Worker GifByteType *Dummy;
527*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
528*324bb76bSAndroid Build Coastguard Worker
529*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
530*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
531*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
532*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
533*324bb76bSAndroid Build Coastguard Worker }
534*324bb76bSAndroid Build Coastguard Worker if (--Private->PixelCount > 0xffff0000UL) {
535*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_DATA_TOO_BIG;
536*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
537*324bb76bSAndroid Build Coastguard Worker }
538*324bb76bSAndroid Build Coastguard Worker
539*324bb76bSAndroid Build Coastguard Worker if (DGifDecompressLine(GifFile, &Pixel, 1) == GIF_OK) {
540*324bb76bSAndroid Build Coastguard Worker if (Private->PixelCount == 0) {
541*324bb76bSAndroid Build Coastguard Worker /* We probably won't be called any more, so let's clean
542*324bb76bSAndroid Build Coastguard Worker * up everything before we return: need to flush out all
543*324bb76bSAndroid Build Coastguard Worker * the rest of image until an empty block (size 0)
544*324bb76bSAndroid Build Coastguard Worker * detected. We use GetCodeNext.
545*324bb76bSAndroid Build Coastguard Worker */
546*324bb76bSAndroid Build Coastguard Worker do {
547*324bb76bSAndroid Build Coastguard Worker if (DGifGetCodeNext(GifFile, &Dummy) ==
548*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
549*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
550*324bb76bSAndroid Build Coastguard Worker }
551*324bb76bSAndroid Build Coastguard Worker } while (Dummy != NULL);
552*324bb76bSAndroid Build Coastguard Worker }
553*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
554*324bb76bSAndroid Build Coastguard Worker } else {
555*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
556*324bb76bSAndroid Build Coastguard Worker }
557*324bb76bSAndroid Build Coastguard Worker }
558*324bb76bSAndroid Build Coastguard Worker
559*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
560*324bb76bSAndroid Build Coastguard Worker Get an extension block (see GIF manual) from GIF file. This routine only
561*324bb76bSAndroid Build Coastguard Worker returns the first data block, and DGifGetExtensionNext should be called
562*324bb76bSAndroid Build Coastguard Worker after this one until NULL extension is returned.
563*324bb76bSAndroid Build Coastguard Worker The Extension should NOT be freed by the user (not dynamically allocated).
564*324bb76bSAndroid Build Coastguard Worker Note it is assumed the Extension description header has been read.
565*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetExtension(GifFileType * GifFile,int * ExtCode,GifByteType ** Extension)566*324bb76bSAndroid Build Coastguard Worker int DGifGetExtension(GifFileType *GifFile, int *ExtCode,
567*324bb76bSAndroid Build Coastguard Worker GifByteType **Extension) {
568*324bb76bSAndroid Build Coastguard Worker GifByteType Buf;
569*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
570*324bb76bSAndroid Build Coastguard Worker
571*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### -> DGifGetExtension:\n");
572*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
573*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
574*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
575*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
576*324bb76bSAndroid Build Coastguard Worker }
577*324bb76bSAndroid Build Coastguard Worker
578*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
579*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &Buf, 1) != 1) {
580*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
581*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
582*324bb76bSAndroid Build Coastguard Worker }
583*324bb76bSAndroid Build Coastguard Worker *ExtCode = Buf;
584*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### <- DGifGetExtension: %02x, about to call
585*324bb76bSAndroid Build Coastguard Worker // next\n", Buf);
586*324bb76bSAndroid Build Coastguard Worker
587*324bb76bSAndroid Build Coastguard Worker return DGifGetExtensionNext(GifFile, Extension);
588*324bb76bSAndroid Build Coastguard Worker }
589*324bb76bSAndroid Build Coastguard Worker
590*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
591*324bb76bSAndroid Build Coastguard Worker Get a following extension block (see GIF manual) from GIF file. This
592*324bb76bSAndroid Build Coastguard Worker routine should be called until NULL Extension is returned.
593*324bb76bSAndroid Build Coastguard Worker The Extension should NOT be freed by the user (not dynamically allocated).
594*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetExtensionNext(GifFileType * GifFile,GifByteType ** Extension)595*324bb76bSAndroid Build Coastguard Worker int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension) {
596*324bb76bSAndroid Build Coastguard Worker GifByteType Buf;
597*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
598*324bb76bSAndroid Build Coastguard Worker
599*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### -> DGifGetExtensionNext\n");
600*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &Buf, 1) != 1) {
601*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
602*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
603*324bb76bSAndroid Build Coastguard Worker }
604*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### DGifGetExtensionNext sees %d\n", Buf);
605*324bb76bSAndroid Build Coastguard Worker
606*324bb76bSAndroid Build Coastguard Worker if (Buf > 0) {
607*324bb76bSAndroid Build Coastguard Worker *Extension = Private->Buf; /* Use private unused buffer. */
608*324bb76bSAndroid Build Coastguard Worker (*Extension)[0] =
609*324bb76bSAndroid Build Coastguard Worker Buf; /* Pascal strings notation (pos. 0 is len.). */
610*324bb76bSAndroid Build Coastguard Worker /* coverity[tainted_data,check_return] */
611*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &((*Extension)[1]), Buf) != Buf) {
612*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
613*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
614*324bb76bSAndroid Build Coastguard Worker }
615*324bb76bSAndroid Build Coastguard Worker } else {
616*324bb76bSAndroid Build Coastguard Worker *Extension = NULL;
617*324bb76bSAndroid Build Coastguard Worker }
618*324bb76bSAndroid Build Coastguard Worker // fprintf(stderr, "### <- DGifGetExtensionNext: %p\n", Extension);
619*324bb76bSAndroid Build Coastguard Worker
620*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
621*324bb76bSAndroid Build Coastguard Worker }
622*324bb76bSAndroid Build Coastguard Worker
623*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
624*324bb76bSAndroid Build Coastguard Worker Extract a Graphics Control Block from raw extension data
625*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
626*324bb76bSAndroid Build Coastguard Worker
DGifExtensionToGCB(const size_t GifExtensionLength,const GifByteType * GifExtension,GraphicsControlBlock * GCB)627*324bb76bSAndroid Build Coastguard Worker int DGifExtensionToGCB(const size_t GifExtensionLength,
628*324bb76bSAndroid Build Coastguard Worker const GifByteType *GifExtension,
629*324bb76bSAndroid Build Coastguard Worker GraphicsControlBlock *GCB) {
630*324bb76bSAndroid Build Coastguard Worker if (GifExtensionLength != 4) {
631*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
632*324bb76bSAndroid Build Coastguard Worker }
633*324bb76bSAndroid Build Coastguard Worker
634*324bb76bSAndroid Build Coastguard Worker GCB->DisposalMode = (GifExtension[0] >> 2) & 0x07;
635*324bb76bSAndroid Build Coastguard Worker GCB->UserInputFlag = (GifExtension[0] & 0x02) != 0;
636*324bb76bSAndroid Build Coastguard Worker GCB->DelayTime =
637*324bb76bSAndroid Build Coastguard Worker UNSIGNED_LITTLE_ENDIAN(GifExtension[1], GifExtension[2]);
638*324bb76bSAndroid Build Coastguard Worker if (GifExtension[0] & 0x01) {
639*324bb76bSAndroid Build Coastguard Worker GCB->TransparentColor = (int)GifExtension[3];
640*324bb76bSAndroid Build Coastguard Worker } else {
641*324bb76bSAndroid Build Coastguard Worker GCB->TransparentColor = NO_TRANSPARENT_COLOR;
642*324bb76bSAndroid Build Coastguard Worker }
643*324bb76bSAndroid Build Coastguard Worker
644*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
645*324bb76bSAndroid Build Coastguard Worker }
646*324bb76bSAndroid Build Coastguard Worker
647*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
648*324bb76bSAndroid Build Coastguard Worker Extract the Graphics Control Block for a saved image, if it exists.
649*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
650*324bb76bSAndroid Build Coastguard Worker
DGifSavedExtensionToGCB(GifFileType * GifFile,int ImageIndex,GraphicsControlBlock * GCB)651*324bb76bSAndroid Build Coastguard Worker int DGifSavedExtensionToGCB(GifFileType *GifFile, int ImageIndex,
652*324bb76bSAndroid Build Coastguard Worker GraphicsControlBlock *GCB) {
653*324bb76bSAndroid Build Coastguard Worker int i;
654*324bb76bSAndroid Build Coastguard Worker
655*324bb76bSAndroid Build Coastguard Worker if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1) {
656*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
657*324bb76bSAndroid Build Coastguard Worker }
658*324bb76bSAndroid Build Coastguard Worker
659*324bb76bSAndroid Build Coastguard Worker GCB->DisposalMode = DISPOSAL_UNSPECIFIED;
660*324bb76bSAndroid Build Coastguard Worker GCB->UserInputFlag = false;
661*324bb76bSAndroid Build Coastguard Worker GCB->DelayTime = 0;
662*324bb76bSAndroid Build Coastguard Worker GCB->TransparentColor = NO_TRANSPARENT_COLOR;
663*324bb76bSAndroid Build Coastguard Worker
664*324bb76bSAndroid Build Coastguard Worker for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount;
665*324bb76bSAndroid Build Coastguard Worker i++) {
666*324bb76bSAndroid Build Coastguard Worker ExtensionBlock *ep =
667*324bb76bSAndroid Build Coastguard Worker &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
668*324bb76bSAndroid Build Coastguard Worker if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
669*324bb76bSAndroid Build Coastguard Worker return DGifExtensionToGCB(ep->ByteCount, ep->Bytes,
670*324bb76bSAndroid Build Coastguard Worker GCB);
671*324bb76bSAndroid Build Coastguard Worker }
672*324bb76bSAndroid Build Coastguard Worker }
673*324bb76bSAndroid Build Coastguard Worker
674*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
675*324bb76bSAndroid Build Coastguard Worker }
676*324bb76bSAndroid Build Coastguard Worker
677*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
678*324bb76bSAndroid Build Coastguard Worker This routine should be called last, to close the GIF file.
679*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifCloseFile(GifFileType * GifFile,int * ErrorCode)680*324bb76bSAndroid Build Coastguard Worker int DGifCloseFile(GifFileType *GifFile, int *ErrorCode) {
681*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private;
682*324bb76bSAndroid Build Coastguard Worker
683*324bb76bSAndroid Build Coastguard Worker if (GifFile == NULL || GifFile->Private == NULL) {
684*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
685*324bb76bSAndroid Build Coastguard Worker }
686*324bb76bSAndroid Build Coastguard Worker
687*324bb76bSAndroid Build Coastguard Worker if (GifFile->Image.ColorMap) {
688*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->Image.ColorMap);
689*324bb76bSAndroid Build Coastguard Worker GifFile->Image.ColorMap = NULL;
690*324bb76bSAndroid Build Coastguard Worker }
691*324bb76bSAndroid Build Coastguard Worker
692*324bb76bSAndroid Build Coastguard Worker if (GifFile->SColorMap) {
693*324bb76bSAndroid Build Coastguard Worker GifFreeMapObject(GifFile->SColorMap);
694*324bb76bSAndroid Build Coastguard Worker GifFile->SColorMap = NULL;
695*324bb76bSAndroid Build Coastguard Worker }
696*324bb76bSAndroid Build Coastguard Worker
697*324bb76bSAndroid Build Coastguard Worker if (GifFile->SavedImages) {
698*324bb76bSAndroid Build Coastguard Worker GifFreeSavedImages(GifFile);
699*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages = NULL;
700*324bb76bSAndroid Build Coastguard Worker }
701*324bb76bSAndroid Build Coastguard Worker
702*324bb76bSAndroid Build Coastguard Worker GifFreeExtensions(&GifFile->ExtensionBlockCount,
703*324bb76bSAndroid Build Coastguard Worker &GifFile->ExtensionBlocks);
704*324bb76bSAndroid Build Coastguard Worker
705*324bb76bSAndroid Build Coastguard Worker Private = (GifFilePrivateType *)GifFile->Private;
706*324bb76bSAndroid Build Coastguard Worker
707*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
708*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
709*324bb76bSAndroid Build Coastguard Worker if (ErrorCode != NULL) {
710*324bb76bSAndroid Build Coastguard Worker *ErrorCode = D_GIF_ERR_NOT_READABLE;
711*324bb76bSAndroid Build Coastguard Worker }
712*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile->Private);
713*324bb76bSAndroid Build Coastguard Worker free(GifFile);
714*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
715*324bb76bSAndroid Build Coastguard Worker }
716*324bb76bSAndroid Build Coastguard Worker
717*324bb76bSAndroid Build Coastguard Worker if (Private->File && (fclose(Private->File) != 0)) {
718*324bb76bSAndroid Build Coastguard Worker if (ErrorCode != NULL) {
719*324bb76bSAndroid Build Coastguard Worker *ErrorCode = D_GIF_ERR_CLOSE_FAILED;
720*324bb76bSAndroid Build Coastguard Worker }
721*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile->Private);
722*324bb76bSAndroid Build Coastguard Worker free(GifFile);
723*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
724*324bb76bSAndroid Build Coastguard Worker }
725*324bb76bSAndroid Build Coastguard Worker
726*324bb76bSAndroid Build Coastguard Worker free((char *)GifFile->Private);
727*324bb76bSAndroid Build Coastguard Worker free(GifFile);
728*324bb76bSAndroid Build Coastguard Worker if (ErrorCode != NULL) {
729*324bb76bSAndroid Build Coastguard Worker *ErrorCode = D_GIF_SUCCEEDED;
730*324bb76bSAndroid Build Coastguard Worker }
731*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
732*324bb76bSAndroid Build Coastguard Worker }
733*324bb76bSAndroid Build Coastguard Worker
734*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
735*324bb76bSAndroid Build Coastguard Worker Get 2 bytes (word) from the given file:
736*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetWord(GifFileType * GifFile,GifWord * Word)737*324bb76bSAndroid Build Coastguard Worker static int DGifGetWord(GifFileType *GifFile, GifWord *Word) {
738*324bb76bSAndroid Build Coastguard Worker unsigned char c[2];
739*324bb76bSAndroid Build Coastguard Worker
740*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
741*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, c, 2) != 2) {
742*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
743*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
744*324bb76bSAndroid Build Coastguard Worker }
745*324bb76bSAndroid Build Coastguard Worker
746*324bb76bSAndroid Build Coastguard Worker *Word = (GifWord)UNSIGNED_LITTLE_ENDIAN(c[0], c[1]);
747*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
748*324bb76bSAndroid Build Coastguard Worker }
749*324bb76bSAndroid Build Coastguard Worker
750*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
751*324bb76bSAndroid Build Coastguard Worker Get the image code in compressed form. This routine can be called if the
752*324bb76bSAndroid Build Coastguard Worker information needed to be piped out as is. Obviously this is much faster
753*324bb76bSAndroid Build Coastguard Worker than decoding and encoding again. This routine should be followed by calls
754*324bb76bSAndroid Build Coastguard Worker to DGifGetCodeNext, until NULL block is returned.
755*324bb76bSAndroid Build Coastguard Worker The block should NOT be freed by the user (not dynamically allocated).
756*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetCode(GifFileType * GifFile,int * CodeSize,GifByteType ** CodeBlock)757*324bb76bSAndroid Build Coastguard Worker int DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock) {
758*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
759*324bb76bSAndroid Build Coastguard Worker
760*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
761*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
762*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
763*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
764*324bb76bSAndroid Build Coastguard Worker }
765*324bb76bSAndroid Build Coastguard Worker
766*324bb76bSAndroid Build Coastguard Worker *CodeSize = Private->BitsPerPixel;
767*324bb76bSAndroid Build Coastguard Worker
768*324bb76bSAndroid Build Coastguard Worker return DGifGetCodeNext(GifFile, CodeBlock);
769*324bb76bSAndroid Build Coastguard Worker }
770*324bb76bSAndroid Build Coastguard Worker
771*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
772*324bb76bSAndroid Build Coastguard Worker Continue to get the image code in compressed form. This routine should be
773*324bb76bSAndroid Build Coastguard Worker called until NULL block is returned.
774*324bb76bSAndroid Build Coastguard Worker The block should NOT be freed by the user (not dynamically allocated).
775*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetCodeNext(GifFileType * GifFile,GifByteType ** CodeBlock)776*324bb76bSAndroid Build Coastguard Worker int DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock) {
777*324bb76bSAndroid Build Coastguard Worker GifByteType Buf;
778*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
779*324bb76bSAndroid Build Coastguard Worker
780*324bb76bSAndroid Build Coastguard Worker /* coverity[tainted_data_argument] */
781*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
782*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &Buf, 1) != 1) {
783*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
784*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
785*324bb76bSAndroid Build Coastguard Worker }
786*324bb76bSAndroid Build Coastguard Worker
787*324bb76bSAndroid Build Coastguard Worker /* coverity[lower_bounds] */
788*324bb76bSAndroid Build Coastguard Worker if (Buf > 0) {
789*324bb76bSAndroid Build Coastguard Worker *CodeBlock = Private->Buf; /* Use private unused buffer. */
790*324bb76bSAndroid Build Coastguard Worker (*CodeBlock)[0] =
791*324bb76bSAndroid Build Coastguard Worker Buf; /* Pascal strings notation (pos. 0 is len.). */
792*324bb76bSAndroid Build Coastguard Worker /* coverity[tainted_data] */
793*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {
794*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
795*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
796*324bb76bSAndroid Build Coastguard Worker }
797*324bb76bSAndroid Build Coastguard Worker } else {
798*324bb76bSAndroid Build Coastguard Worker *CodeBlock = NULL;
799*324bb76bSAndroid Build Coastguard Worker Private->Buf[0] = 0; /* Make sure the buffer is empty! */
800*324bb76bSAndroid Build Coastguard Worker Private->PixelCount =
801*324bb76bSAndroid Build Coastguard Worker 0; /* And local info. indicate image read. */
802*324bb76bSAndroid Build Coastguard Worker }
803*324bb76bSAndroid Build Coastguard Worker
804*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
805*324bb76bSAndroid Build Coastguard Worker }
806*324bb76bSAndroid Build Coastguard Worker
807*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
808*324bb76bSAndroid Build Coastguard Worker Setup the LZ decompression for this image:
809*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifSetupDecompress(GifFileType * GifFile)810*324bb76bSAndroid Build Coastguard Worker static int DGifSetupDecompress(GifFileType *GifFile) {
811*324bb76bSAndroid Build Coastguard Worker int i, BitsPerPixel;
812*324bb76bSAndroid Build Coastguard Worker GifByteType CodeSize;
813*324bb76bSAndroid Build Coastguard Worker GifPrefixType *Prefix;
814*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
815*324bb76bSAndroid Build Coastguard Worker
816*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
817*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &CodeSize, 1) <
818*324bb76bSAndroid Build Coastguard Worker 1) { /* Read Code size from file. */
819*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
820*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR; /* Failed to read Code size. */
821*324bb76bSAndroid Build Coastguard Worker }
822*324bb76bSAndroid Build Coastguard Worker BitsPerPixel = CodeSize;
823*324bb76bSAndroid Build Coastguard Worker
824*324bb76bSAndroid Build Coastguard Worker /* this can only happen on a severely malformed GIF */
825*324bb76bSAndroid Build Coastguard Worker if (BitsPerPixel > 8) {
826*324bb76bSAndroid Build Coastguard Worker GifFile->Error =
827*324bb76bSAndroid Build Coastguard Worker D_GIF_ERR_READ_FAILED; /* somewhat bogus error code */
828*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR; /* Failed to read Code size. */
829*324bb76bSAndroid Build Coastguard Worker }
830*324bb76bSAndroid Build Coastguard Worker
831*324bb76bSAndroid Build Coastguard Worker Private->Buf[0] = 0; /* Input Buffer empty. */
832*324bb76bSAndroid Build Coastguard Worker Private->BitsPerPixel = BitsPerPixel;
833*324bb76bSAndroid Build Coastguard Worker Private->ClearCode = (1 << BitsPerPixel);
834*324bb76bSAndroid Build Coastguard Worker Private->EOFCode = Private->ClearCode + 1;
835*324bb76bSAndroid Build Coastguard Worker Private->RunningCode = Private->EOFCode + 1;
836*324bb76bSAndroid Build Coastguard Worker Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
837*324bb76bSAndroid Build Coastguard Worker Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
838*324bb76bSAndroid Build Coastguard Worker Private->StackPtr = 0; /* No pixels on the pixel stack. */
839*324bb76bSAndroid Build Coastguard Worker Private->LastCode = NO_SUCH_CODE;
840*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
841*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftDWord = 0;
842*324bb76bSAndroid Build Coastguard Worker
843*324bb76bSAndroid Build Coastguard Worker Prefix = Private->Prefix;
844*324bb76bSAndroid Build Coastguard Worker for (i = 0; i <= LZ_MAX_CODE; i++) {
845*324bb76bSAndroid Build Coastguard Worker Prefix[i] = NO_SUCH_CODE;
846*324bb76bSAndroid Build Coastguard Worker }
847*324bb76bSAndroid Build Coastguard Worker
848*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
849*324bb76bSAndroid Build Coastguard Worker }
850*324bb76bSAndroid Build Coastguard Worker
851*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
852*324bb76bSAndroid Build Coastguard Worker The LZ decompression routine:
853*324bb76bSAndroid Build Coastguard Worker This version decompress the given GIF file into Line of length LineLen.
854*324bb76bSAndroid Build Coastguard Worker This routine can be called few times (one per scan line, for example), in
855*324bb76bSAndroid Build Coastguard Worker order the complete the whole image.
856*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifDecompressLine(GifFileType * GifFile,GifPixelType * Line,int LineLen)857*324bb76bSAndroid Build Coastguard Worker static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
858*324bb76bSAndroid Build Coastguard Worker int LineLen) {
859*324bb76bSAndroid Build Coastguard Worker int i = 0;
860*324bb76bSAndroid Build Coastguard Worker int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
861*324bb76bSAndroid Build Coastguard Worker GifByteType *Stack, *Suffix;
862*324bb76bSAndroid Build Coastguard Worker GifPrefixType *Prefix;
863*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
864*324bb76bSAndroid Build Coastguard Worker
865*324bb76bSAndroid Build Coastguard Worker StackPtr = Private->StackPtr;
866*324bb76bSAndroid Build Coastguard Worker Prefix = Private->Prefix;
867*324bb76bSAndroid Build Coastguard Worker Suffix = Private->Suffix;
868*324bb76bSAndroid Build Coastguard Worker Stack = Private->Stack;
869*324bb76bSAndroid Build Coastguard Worker EOFCode = Private->EOFCode;
870*324bb76bSAndroid Build Coastguard Worker ClearCode = Private->ClearCode;
871*324bb76bSAndroid Build Coastguard Worker LastCode = Private->LastCode;
872*324bb76bSAndroid Build Coastguard Worker
873*324bb76bSAndroid Build Coastguard Worker if (StackPtr > LZ_MAX_CODE) {
874*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
875*324bb76bSAndroid Build Coastguard Worker }
876*324bb76bSAndroid Build Coastguard Worker
877*324bb76bSAndroid Build Coastguard Worker if (StackPtr != 0) {
878*324bb76bSAndroid Build Coastguard Worker /* Let pop the stack off before continueing to read the GIF
879*324bb76bSAndroid Build Coastguard Worker * file: */
880*324bb76bSAndroid Build Coastguard Worker while (StackPtr != 0 && i < LineLen) {
881*324bb76bSAndroid Build Coastguard Worker Line[i++] = Stack[--StackPtr];
882*324bb76bSAndroid Build Coastguard Worker }
883*324bb76bSAndroid Build Coastguard Worker }
884*324bb76bSAndroid Build Coastguard Worker
885*324bb76bSAndroid Build Coastguard Worker while (i < LineLen) { /* Decode LineLen items. */
886*324bb76bSAndroid Build Coastguard Worker if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR) {
887*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
888*324bb76bSAndroid Build Coastguard Worker }
889*324bb76bSAndroid Build Coastguard Worker
890*324bb76bSAndroid Build Coastguard Worker if (CrntCode == EOFCode) {
891*324bb76bSAndroid Build Coastguard Worker /* Note however that usually we will not be here as we
892*324bb76bSAndroid Build Coastguard Worker * will stop decoding as soon as we got all the pixel,
893*324bb76bSAndroid Build Coastguard Worker * or EOF code will not be read at all, and
894*324bb76bSAndroid Build Coastguard Worker * DGifGetLine/Pixel clean everything. */
895*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_EOF_TOO_SOON;
896*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
897*324bb76bSAndroid Build Coastguard Worker } else if (CrntCode == ClearCode) {
898*324bb76bSAndroid Build Coastguard Worker /* We need to start over again: */
899*324bb76bSAndroid Build Coastguard Worker for (j = 0; j <= LZ_MAX_CODE; j++) {
900*324bb76bSAndroid Build Coastguard Worker Prefix[j] = NO_SUCH_CODE;
901*324bb76bSAndroid Build Coastguard Worker }
902*324bb76bSAndroid Build Coastguard Worker Private->RunningCode = Private->EOFCode + 1;
903*324bb76bSAndroid Build Coastguard Worker Private->RunningBits = Private->BitsPerPixel + 1;
904*324bb76bSAndroid Build Coastguard Worker Private->MaxCode1 = 1 << Private->RunningBits;
905*324bb76bSAndroid Build Coastguard Worker LastCode = Private->LastCode = NO_SUCH_CODE;
906*324bb76bSAndroid Build Coastguard Worker } else {
907*324bb76bSAndroid Build Coastguard Worker /* Its regular code - if in pixel range simply add it to
908*324bb76bSAndroid Build Coastguard Worker * output stream, otherwise trace to codes linked list
909*324bb76bSAndroid Build Coastguard Worker * until the prefix is in pixel range: */
910*324bb76bSAndroid Build Coastguard Worker if (CrntCode < ClearCode) {
911*324bb76bSAndroid Build Coastguard Worker /* This is simple - its pixel scalar, so add it
912*324bb76bSAndroid Build Coastguard Worker * to output: */
913*324bb76bSAndroid Build Coastguard Worker Line[i++] = CrntCode;
914*324bb76bSAndroid Build Coastguard Worker } else {
915*324bb76bSAndroid Build Coastguard Worker /* Its a code to needed to be traced: trace the
916*324bb76bSAndroid Build Coastguard Worker * linked list until the prefix is a pixel,
917*324bb76bSAndroid Build Coastguard Worker * while pushing the suffix pixels on our stack.
918*324bb76bSAndroid Build Coastguard Worker * If we done, pop the stack in reverse (thats
919*324bb76bSAndroid Build Coastguard Worker * what stack is good for!) order to output. */
920*324bb76bSAndroid Build Coastguard Worker if (Prefix[CrntCode] == NO_SUCH_CODE) {
921*324bb76bSAndroid Build Coastguard Worker CrntPrefix = LastCode;
922*324bb76bSAndroid Build Coastguard Worker
923*324bb76bSAndroid Build Coastguard Worker /* Only allowed if CrntCode is exactly
924*324bb76bSAndroid Build Coastguard Worker * the running code: In that case
925*324bb76bSAndroid Build Coastguard Worker * CrntCode = XXXCode, CrntCode or the
926*324bb76bSAndroid Build Coastguard Worker * prefix code is last code and the
927*324bb76bSAndroid Build Coastguard Worker * suffix char is exactly the prefix of
928*324bb76bSAndroid Build Coastguard Worker * last code! */
929*324bb76bSAndroid Build Coastguard Worker if (CrntCode ==
930*324bb76bSAndroid Build Coastguard Worker Private->RunningCode - 2) {
931*324bb76bSAndroid Build Coastguard Worker Suffix[Private->RunningCode -
932*324bb76bSAndroid Build Coastguard Worker 2] = Stack[StackPtr++] =
933*324bb76bSAndroid Build Coastguard Worker DGifGetPrefixChar(
934*324bb76bSAndroid Build Coastguard Worker Prefix, LastCode,
935*324bb76bSAndroid Build Coastguard Worker ClearCode);
936*324bb76bSAndroid Build Coastguard Worker } else {
937*324bb76bSAndroid Build Coastguard Worker Suffix[Private->RunningCode -
938*324bb76bSAndroid Build Coastguard Worker 2] = Stack[StackPtr++] =
939*324bb76bSAndroid Build Coastguard Worker DGifGetPrefixChar(
940*324bb76bSAndroid Build Coastguard Worker Prefix, CrntCode,
941*324bb76bSAndroid Build Coastguard Worker ClearCode);
942*324bb76bSAndroid Build Coastguard Worker }
943*324bb76bSAndroid Build Coastguard Worker } else {
944*324bb76bSAndroid Build Coastguard Worker CrntPrefix = CrntCode;
945*324bb76bSAndroid Build Coastguard Worker }
946*324bb76bSAndroid Build Coastguard Worker
947*324bb76bSAndroid Build Coastguard Worker /* Now (if image is O.K.) we should not get a
948*324bb76bSAndroid Build Coastguard Worker * NO_SUCH_CODE during the trace. As we might
949*324bb76bSAndroid Build Coastguard Worker * loop forever, in case of defective image, we
950*324bb76bSAndroid Build Coastguard Worker * use StackPtr as loop counter and stop before
951*324bb76bSAndroid Build Coastguard Worker * overflowing Stack[]. */
952*324bb76bSAndroid Build Coastguard Worker while (StackPtr < LZ_MAX_CODE &&
953*324bb76bSAndroid Build Coastguard Worker CrntPrefix > ClearCode &&
954*324bb76bSAndroid Build Coastguard Worker CrntPrefix <= LZ_MAX_CODE) {
955*324bb76bSAndroid Build Coastguard Worker Stack[StackPtr++] = Suffix[CrntPrefix];
956*324bb76bSAndroid Build Coastguard Worker CrntPrefix = Prefix[CrntPrefix];
957*324bb76bSAndroid Build Coastguard Worker }
958*324bb76bSAndroid Build Coastguard Worker if (StackPtr >= LZ_MAX_CODE ||
959*324bb76bSAndroid Build Coastguard Worker CrntPrefix > LZ_MAX_CODE) {
960*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
961*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
962*324bb76bSAndroid Build Coastguard Worker }
963*324bb76bSAndroid Build Coastguard Worker /* Push the last character on stack: */
964*324bb76bSAndroid Build Coastguard Worker Stack[StackPtr++] = CrntPrefix;
965*324bb76bSAndroid Build Coastguard Worker
966*324bb76bSAndroid Build Coastguard Worker /* Now lets pop all the stack into output: */
967*324bb76bSAndroid Build Coastguard Worker while (StackPtr != 0 && i < LineLen) {
968*324bb76bSAndroid Build Coastguard Worker Line[i++] = Stack[--StackPtr];
969*324bb76bSAndroid Build Coastguard Worker }
970*324bb76bSAndroid Build Coastguard Worker }
971*324bb76bSAndroid Build Coastguard Worker if (LastCode != NO_SUCH_CODE &&
972*324bb76bSAndroid Build Coastguard Worker Private->RunningCode - 2 < (LZ_MAX_CODE + 1) &&
973*324bb76bSAndroid Build Coastguard Worker Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
974*324bb76bSAndroid Build Coastguard Worker Prefix[Private->RunningCode - 2] = LastCode;
975*324bb76bSAndroid Build Coastguard Worker
976*324bb76bSAndroid Build Coastguard Worker if (CrntCode == Private->RunningCode - 2) {
977*324bb76bSAndroid Build Coastguard Worker /* Only allowed if CrntCode is exactly
978*324bb76bSAndroid Build Coastguard Worker * the running code: In that case
979*324bb76bSAndroid Build Coastguard Worker * CrntCode = XXXCode, CrntCode or the
980*324bb76bSAndroid Build Coastguard Worker * prefix code is last code and the
981*324bb76bSAndroid Build Coastguard Worker * suffix char is exactly the prefix of
982*324bb76bSAndroid Build Coastguard Worker * last code! */
983*324bb76bSAndroid Build Coastguard Worker Suffix[Private->RunningCode - 2] =
984*324bb76bSAndroid Build Coastguard Worker DGifGetPrefixChar(Prefix, LastCode,
985*324bb76bSAndroid Build Coastguard Worker ClearCode);
986*324bb76bSAndroid Build Coastguard Worker } else {
987*324bb76bSAndroid Build Coastguard Worker Suffix[Private->RunningCode - 2] =
988*324bb76bSAndroid Build Coastguard Worker DGifGetPrefixChar(Prefix, CrntCode,
989*324bb76bSAndroid Build Coastguard Worker ClearCode);
990*324bb76bSAndroid Build Coastguard Worker }
991*324bb76bSAndroid Build Coastguard Worker }
992*324bb76bSAndroid Build Coastguard Worker LastCode = CrntCode;
993*324bb76bSAndroid Build Coastguard Worker }
994*324bb76bSAndroid Build Coastguard Worker }
995*324bb76bSAndroid Build Coastguard Worker
996*324bb76bSAndroid Build Coastguard Worker Private->LastCode = LastCode;
997*324bb76bSAndroid Build Coastguard Worker Private->StackPtr = StackPtr;
998*324bb76bSAndroid Build Coastguard Worker
999*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
1000*324bb76bSAndroid Build Coastguard Worker }
1001*324bb76bSAndroid Build Coastguard Worker
1002*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1003*324bb76bSAndroid Build Coastguard Worker Routine to trace the Prefixes linked list until we get a prefix which is
1004*324bb76bSAndroid Build Coastguard Worker not code, but a pixel value (less than ClearCode). Returns that pixel value.
1005*324bb76bSAndroid Build Coastguard Worker If image is defective, we might loop here forever, so we limit the loops to
1006*324bb76bSAndroid Build Coastguard Worker the maximum possible if image O.k. - LZ_MAX_CODE times.
1007*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetPrefixChar(const GifPrefixType * Prefix,int Code,int ClearCode)1008*324bb76bSAndroid Build Coastguard Worker static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code,
1009*324bb76bSAndroid Build Coastguard Worker int ClearCode) {
1010*324bb76bSAndroid Build Coastguard Worker int i = 0;
1011*324bb76bSAndroid Build Coastguard Worker
1012*324bb76bSAndroid Build Coastguard Worker while (Code > ClearCode && i++ <= LZ_MAX_CODE) {
1013*324bb76bSAndroid Build Coastguard Worker if (Code > LZ_MAX_CODE) {
1014*324bb76bSAndroid Build Coastguard Worker return NO_SUCH_CODE;
1015*324bb76bSAndroid Build Coastguard Worker }
1016*324bb76bSAndroid Build Coastguard Worker Code = Prefix[Code];
1017*324bb76bSAndroid Build Coastguard Worker }
1018*324bb76bSAndroid Build Coastguard Worker return Code;
1019*324bb76bSAndroid Build Coastguard Worker }
1020*324bb76bSAndroid Build Coastguard Worker
1021*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1022*324bb76bSAndroid Build Coastguard Worker Interface for accessing the LZ codes directly. Set Code to the real code
1023*324bb76bSAndroid Build Coastguard Worker (12bits), or to -1 if EOF code is returned.
1024*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifGetLZCodes(GifFileType * GifFile,int * Code)1025*324bb76bSAndroid Build Coastguard Worker int DGifGetLZCodes(GifFileType *GifFile, int *Code) {
1026*324bb76bSAndroid Build Coastguard Worker GifByteType *CodeBlock;
1027*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
1028*324bb76bSAndroid Build Coastguard Worker
1029*324bb76bSAndroid Build Coastguard Worker if (!IS_READABLE(Private)) {
1030*324bb76bSAndroid Build Coastguard Worker /* This file was NOT open for reading: */
1031*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NOT_READABLE;
1032*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1033*324bb76bSAndroid Build Coastguard Worker }
1034*324bb76bSAndroid Build Coastguard Worker
1035*324bb76bSAndroid Build Coastguard Worker if (DGifDecompressInput(GifFile, Code) == GIF_ERROR) {
1036*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1037*324bb76bSAndroid Build Coastguard Worker }
1038*324bb76bSAndroid Build Coastguard Worker
1039*324bb76bSAndroid Build Coastguard Worker if (*Code == Private->EOFCode) {
1040*324bb76bSAndroid Build Coastguard Worker /* Skip rest of codes (hopefully only NULL terminating block):
1041*324bb76bSAndroid Build Coastguard Worker */
1042*324bb76bSAndroid Build Coastguard Worker do {
1043*324bb76bSAndroid Build Coastguard Worker if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
1044*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1045*324bb76bSAndroid Build Coastguard Worker }
1046*324bb76bSAndroid Build Coastguard Worker } while (CodeBlock != NULL);
1047*324bb76bSAndroid Build Coastguard Worker
1048*324bb76bSAndroid Build Coastguard Worker *Code = -1;
1049*324bb76bSAndroid Build Coastguard Worker } else if (*Code == Private->ClearCode) {
1050*324bb76bSAndroid Build Coastguard Worker /* We need to start over again: */
1051*324bb76bSAndroid Build Coastguard Worker Private->RunningCode = Private->EOFCode + 1;
1052*324bb76bSAndroid Build Coastguard Worker Private->RunningBits = Private->BitsPerPixel + 1;
1053*324bb76bSAndroid Build Coastguard Worker Private->MaxCode1 = 1 << Private->RunningBits;
1054*324bb76bSAndroid Build Coastguard Worker }
1055*324bb76bSAndroid Build Coastguard Worker
1056*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
1057*324bb76bSAndroid Build Coastguard Worker }
1058*324bb76bSAndroid Build Coastguard Worker
1059*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1060*324bb76bSAndroid Build Coastguard Worker The LZ decompression input routine:
1061*324bb76bSAndroid Build Coastguard Worker This routine is responsable for the decompression of the bit stream from
1062*324bb76bSAndroid Build Coastguard Worker 8 bits (bytes) packets, into the real codes.
1063*324bb76bSAndroid Build Coastguard Worker Returns GIF_OK if read successfully.
1064*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifDecompressInput(GifFileType * GifFile,int * Code)1065*324bb76bSAndroid Build Coastguard Worker static int DGifDecompressInput(GifFileType *GifFile, int *Code) {
1066*324bb76bSAndroid Build Coastguard Worker static const unsigned short CodeMasks[] = {
1067*324bb76bSAndroid Build Coastguard Worker 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f,
1068*324bb76bSAndroid Build Coastguard Worker 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff};
1069*324bb76bSAndroid Build Coastguard Worker
1070*324bb76bSAndroid Build Coastguard Worker GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
1071*324bb76bSAndroid Build Coastguard Worker
1072*324bb76bSAndroid Build Coastguard Worker GifByteType NextByte;
1073*324bb76bSAndroid Build Coastguard Worker
1074*324bb76bSAndroid Build Coastguard Worker /* The image can't contain more than LZ_BITS per code. */
1075*324bb76bSAndroid Build Coastguard Worker if (Private->RunningBits > LZ_BITS) {
1076*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
1077*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1078*324bb76bSAndroid Build Coastguard Worker }
1079*324bb76bSAndroid Build Coastguard Worker
1080*324bb76bSAndroid Build Coastguard Worker while (Private->CrntShiftState < Private->RunningBits) {
1081*324bb76bSAndroid Build Coastguard Worker /* Needs to get more bytes from input stream for next code: */
1082*324bb76bSAndroid Build Coastguard Worker if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) ==
1083*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
1084*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1085*324bb76bSAndroid Build Coastguard Worker }
1086*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftDWord |= ((unsigned long)NextByte)
1087*324bb76bSAndroid Build Coastguard Worker << Private->CrntShiftState;
1088*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftState += 8;
1089*324bb76bSAndroid Build Coastguard Worker }
1090*324bb76bSAndroid Build Coastguard Worker *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
1091*324bb76bSAndroid Build Coastguard Worker
1092*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftDWord >>= Private->RunningBits;
1093*324bb76bSAndroid Build Coastguard Worker Private->CrntShiftState -= Private->RunningBits;
1094*324bb76bSAndroid Build Coastguard Worker
1095*324bb76bSAndroid Build Coastguard Worker /* If code cannot fit into RunningBits bits, must raise its size. Note
1096*324bb76bSAndroid Build Coastguard Worker * however that codes above 4095 are used for special signaling.
1097*324bb76bSAndroid Build Coastguard Worker * If we're using LZ_BITS bits already and we're at the max code, just
1098*324bb76bSAndroid Build Coastguard Worker * keep using the table as it is, don't increment Private->RunningCode.
1099*324bb76bSAndroid Build Coastguard Worker */
1100*324bb76bSAndroid Build Coastguard Worker if (Private->RunningCode < LZ_MAX_CODE + 2 &&
1101*324bb76bSAndroid Build Coastguard Worker ++Private->RunningCode > Private->MaxCode1 &&
1102*324bb76bSAndroid Build Coastguard Worker Private->RunningBits < LZ_BITS) {
1103*324bb76bSAndroid Build Coastguard Worker Private->MaxCode1 <<= 1;
1104*324bb76bSAndroid Build Coastguard Worker Private->RunningBits++;
1105*324bb76bSAndroid Build Coastguard Worker }
1106*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
1107*324bb76bSAndroid Build Coastguard Worker }
1108*324bb76bSAndroid Build Coastguard Worker
1109*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1110*324bb76bSAndroid Build Coastguard Worker This routines read one GIF data block at a time and buffers it internally
1111*324bb76bSAndroid Build Coastguard Worker so that the decompression routine could access it.
1112*324bb76bSAndroid Build Coastguard Worker The routine returns the next byte from its internal buffer (or read next
1113*324bb76bSAndroid Build Coastguard Worker block in if buffer empty) and returns GIF_OK if succesful.
1114*324bb76bSAndroid Build Coastguard Worker ******************************************************************************/
DGifBufferedInput(GifFileType * GifFile,GifByteType * Buf,GifByteType * NextByte)1115*324bb76bSAndroid Build Coastguard Worker static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
1116*324bb76bSAndroid Build Coastguard Worker GifByteType *NextByte) {
1117*324bb76bSAndroid Build Coastguard Worker if (Buf[0] == 0) {
1118*324bb76bSAndroid Build Coastguard Worker /* Needs to read the next buffer - this one is empty: */
1119*324bb76bSAndroid Build Coastguard Worker /* coverity[check_return] */
1120*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, Buf, 1) != 1) {
1121*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
1122*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1123*324bb76bSAndroid Build Coastguard Worker }
1124*324bb76bSAndroid Build Coastguard Worker /* There shouldn't be any empty data blocks here as the LZW spec
1125*324bb76bSAndroid Build Coastguard Worker * says the LZW termination code should come first. Therefore
1126*324bb76bSAndroid Build Coastguard Worker * we shouldn't be inside this routine at that point.
1127*324bb76bSAndroid Build Coastguard Worker */
1128*324bb76bSAndroid Build Coastguard Worker if (Buf[0] == 0) {
1129*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
1130*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1131*324bb76bSAndroid Build Coastguard Worker }
1132*324bb76bSAndroid Build Coastguard Worker if (InternalRead(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
1133*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_READ_FAILED;
1134*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1135*324bb76bSAndroid Build Coastguard Worker }
1136*324bb76bSAndroid Build Coastguard Worker *NextByte = Buf[1];
1137*324bb76bSAndroid Build Coastguard Worker Buf[1] = 2; /* We use now the second place as last char read! */
1138*324bb76bSAndroid Build Coastguard Worker Buf[0]--;
1139*324bb76bSAndroid Build Coastguard Worker } else {
1140*324bb76bSAndroid Build Coastguard Worker *NextByte = Buf[Buf[1]++];
1141*324bb76bSAndroid Build Coastguard Worker Buf[0]--;
1142*324bb76bSAndroid Build Coastguard Worker }
1143*324bb76bSAndroid Build Coastguard Worker
1144*324bb76bSAndroid Build Coastguard Worker return GIF_OK;
1145*324bb76bSAndroid Build Coastguard Worker }
1146*324bb76bSAndroid Build Coastguard Worker
1147*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1148*324bb76bSAndroid Build Coastguard Worker This routine is called in case of error during parsing image. We need to
1149*324bb76bSAndroid Build Coastguard Worker decrease image counter and reallocate memory for saved images. Not decreasing
1150*324bb76bSAndroid Build Coastguard Worker ImageCount may lead to null pointer dereference, because the last element in
1151*324bb76bSAndroid Build Coastguard Worker SavedImages may point to the spoilt image and null pointer buffers.
1152*324bb76bSAndroid Build Coastguard Worker *******************************************************************************/
DGifDecreaseImageCounter(GifFileType * GifFile)1153*324bb76bSAndroid Build Coastguard Worker void DGifDecreaseImageCounter(GifFileType *GifFile) {
1154*324bb76bSAndroid Build Coastguard Worker GifFile->ImageCount--;
1155*324bb76bSAndroid Build Coastguard Worker if (GifFile->SavedImages[GifFile->ImageCount].RasterBits != NULL) {
1156*324bb76bSAndroid Build Coastguard Worker free(GifFile->SavedImages[GifFile->ImageCount].RasterBits);
1157*324bb76bSAndroid Build Coastguard Worker }
1158*324bb76bSAndroid Build Coastguard Worker
1159*324bb76bSAndroid Build Coastguard Worker // Realloc array according to the new image counter.
1160*324bb76bSAndroid Build Coastguard Worker SavedImage *correct_saved_images = (SavedImage *)reallocarray(
1161*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages, GifFile->ImageCount, sizeof(SavedImage));
1162*324bb76bSAndroid Build Coastguard Worker if (correct_saved_images != NULL) {
1163*324bb76bSAndroid Build Coastguard Worker GifFile->SavedImages = correct_saved_images;
1164*324bb76bSAndroid Build Coastguard Worker }
1165*324bb76bSAndroid Build Coastguard Worker }
1166*324bb76bSAndroid Build Coastguard Worker
1167*324bb76bSAndroid Build Coastguard Worker /******************************************************************************
1168*324bb76bSAndroid Build Coastguard Worker This routine reads an entire GIF into core, hanging all its state info off
1169*324bb76bSAndroid Build Coastguard Worker the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle()
1170*324bb76bSAndroid Build Coastguard Worker first to initialize I/O. Its inverse is EGifSpew().
1171*324bb76bSAndroid Build Coastguard Worker *******************************************************************************/
DGifSlurp(GifFileType * GifFile)1172*324bb76bSAndroid Build Coastguard Worker int DGifSlurp(GifFileType *GifFile) {
1173*324bb76bSAndroid Build Coastguard Worker size_t ImageSize;
1174*324bb76bSAndroid Build Coastguard Worker GifRecordType RecordType;
1175*324bb76bSAndroid Build Coastguard Worker SavedImage *sp;
1176*324bb76bSAndroid Build Coastguard Worker GifByteType *ExtData;
1177*324bb76bSAndroid Build Coastguard Worker int ExtFunction;
1178*324bb76bSAndroid Build Coastguard Worker
1179*324bb76bSAndroid Build Coastguard Worker GifFile->ExtensionBlocks = NULL;
1180*324bb76bSAndroid Build Coastguard Worker GifFile->ExtensionBlockCount = 0;
1181*324bb76bSAndroid Build Coastguard Worker
1182*324bb76bSAndroid Build Coastguard Worker do {
1183*324bb76bSAndroid Build Coastguard Worker if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
1184*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1185*324bb76bSAndroid Build Coastguard Worker }
1186*324bb76bSAndroid Build Coastguard Worker
1187*324bb76bSAndroid Build Coastguard Worker switch (RecordType) {
1188*324bb76bSAndroid Build Coastguard Worker case IMAGE_DESC_RECORD_TYPE:
1189*324bb76bSAndroid Build Coastguard Worker if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
1190*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1191*324bb76bSAndroid Build Coastguard Worker }
1192*324bb76bSAndroid Build Coastguard Worker
1193*324bb76bSAndroid Build Coastguard Worker sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
1194*324bb76bSAndroid Build Coastguard Worker /* Allocate memory for the image */
1195*324bb76bSAndroid Build Coastguard Worker if (sp->ImageDesc.Width <= 0 ||
1196*324bb76bSAndroid Build Coastguard Worker sp->ImageDesc.Height <= 0 ||
1197*324bb76bSAndroid Build Coastguard Worker sp->ImageDesc.Width >
1198*324bb76bSAndroid Build Coastguard Worker (INT_MAX / sp->ImageDesc.Height)) {
1199*324bb76bSAndroid Build Coastguard Worker DGifDecreaseImageCounter(GifFile);
1200*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1201*324bb76bSAndroid Build Coastguard Worker }
1202*324bb76bSAndroid Build Coastguard Worker ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
1203*324bb76bSAndroid Build Coastguard Worker
1204*324bb76bSAndroid Build Coastguard Worker if (ImageSize > (SIZE_MAX / sizeof(GifPixelType))) {
1205*324bb76bSAndroid Build Coastguard Worker DGifDecreaseImageCounter(GifFile);
1206*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1207*324bb76bSAndroid Build Coastguard Worker }
1208*324bb76bSAndroid Build Coastguard Worker sp->RasterBits = (unsigned char *)reallocarray(
1209*324bb76bSAndroid Build Coastguard Worker NULL, ImageSize, sizeof(GifPixelType));
1210*324bb76bSAndroid Build Coastguard Worker
1211*324bb76bSAndroid Build Coastguard Worker if (sp->RasterBits == NULL) {
1212*324bb76bSAndroid Build Coastguard Worker DGifDecreaseImageCounter(GifFile);
1213*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1214*324bb76bSAndroid Build Coastguard Worker }
1215*324bb76bSAndroid Build Coastguard Worker
1216*324bb76bSAndroid Build Coastguard Worker if (sp->ImageDesc.Interlace) {
1217*324bb76bSAndroid Build Coastguard Worker int i, j;
1218*324bb76bSAndroid Build Coastguard Worker /*
1219*324bb76bSAndroid Build Coastguard Worker * The way an interlaced image should be read -
1220*324bb76bSAndroid Build Coastguard Worker * offsets and jumps...
1221*324bb76bSAndroid Build Coastguard Worker */
1222*324bb76bSAndroid Build Coastguard Worker static const int InterlacedOffset[] = {0, 4, 2,
1223*324bb76bSAndroid Build Coastguard Worker 1};
1224*324bb76bSAndroid Build Coastguard Worker static const int InterlacedJumps[] = {8, 8, 4,
1225*324bb76bSAndroid Build Coastguard Worker 2};
1226*324bb76bSAndroid Build Coastguard Worker /* Need to perform 4 passes on the image */
1227*324bb76bSAndroid Build Coastguard Worker for (i = 0; i < 4; i++) {
1228*324bb76bSAndroid Build Coastguard Worker for (j = InterlacedOffset[i];
1229*324bb76bSAndroid Build Coastguard Worker j < sp->ImageDesc.Height;
1230*324bb76bSAndroid Build Coastguard Worker j += InterlacedJumps[i]) {
1231*324bb76bSAndroid Build Coastguard Worker if (DGifGetLine(
1232*324bb76bSAndroid Build Coastguard Worker GifFile,
1233*324bb76bSAndroid Build Coastguard Worker sp->RasterBits +
1234*324bb76bSAndroid Build Coastguard Worker j * sp->ImageDesc
1235*324bb76bSAndroid Build Coastguard Worker .Width,
1236*324bb76bSAndroid Build Coastguard Worker sp->ImageDesc.Width) ==
1237*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
1238*324bb76bSAndroid Build Coastguard Worker DGifDecreaseImageCounter(
1239*324bb76bSAndroid Build Coastguard Worker GifFile);
1240*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1241*324bb76bSAndroid Build Coastguard Worker }
1242*324bb76bSAndroid Build Coastguard Worker }
1243*324bb76bSAndroid Build Coastguard Worker }
1244*324bb76bSAndroid Build Coastguard Worker } else {
1245*324bb76bSAndroid Build Coastguard Worker if (DGifGetLine(GifFile, sp->RasterBits,
1246*324bb76bSAndroid Build Coastguard Worker ImageSize) == GIF_ERROR) {
1247*324bb76bSAndroid Build Coastguard Worker DGifDecreaseImageCounter(GifFile);
1248*324bb76bSAndroid Build Coastguard Worker return GIF_ERROR;
1249*324bb76bSAndroid Build Coastguard Worker }
1250*324bb76bSAndroid Build Coastguard Worker }
1251*324bb76bSAndroid Build Coastguard Worker
1252*324bb76bSAndroid Build Coastguard Worker if (GifFile->ExtensionBlocks) {
1253*324bb76bSAndroid Build Coastguard Worker sp->ExtensionBlocks = GifFile->ExtensionBlocks;
1254*324bb76bSAndroid Build Coastguard Worker sp->ExtensionBlockCount =
1255*324bb76bSAndroid Build Coastguard Worker GifFile->ExtensionBlockCount;
1256*324bb76bSAndroid Build Coastguard Worker
1257*324bb76bSAndroid Build Coastguard Worker GifFile->ExtensionBlocks = NULL;
1258*324bb76bSAndroid Build Coastguard Worker GifFile->ExtensionBlockCount = 0;
1259*324bb76bSAndroid Build Coastguard Worker }
1260*324bb76bSAndroid Build Coastguard Worker break;
1261*324bb76bSAndroid Build Coastguard Worker
1262*324bb76bSAndroid Build Coastguard Worker case EXTENSION_RECORD_TYPE:
1263*324bb76bSAndroid Build Coastguard Worker if (DGifGetExtension(GifFile, &ExtFunction, &ExtData) ==
1264*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
1265*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1266*324bb76bSAndroid Build Coastguard Worker }
1267*324bb76bSAndroid Build Coastguard Worker /* Create an extension block with our data */
1268*324bb76bSAndroid Build Coastguard Worker if (ExtData != NULL) {
1269*324bb76bSAndroid Build Coastguard Worker if (GifAddExtensionBlock(
1270*324bb76bSAndroid Build Coastguard Worker &GifFile->ExtensionBlockCount,
1271*324bb76bSAndroid Build Coastguard Worker &GifFile->ExtensionBlocks, ExtFunction,
1272*324bb76bSAndroid Build Coastguard Worker ExtData[0], &ExtData[1]) == GIF_ERROR) {
1273*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1274*324bb76bSAndroid Build Coastguard Worker }
1275*324bb76bSAndroid Build Coastguard Worker }
1276*324bb76bSAndroid Build Coastguard Worker for (;;) {
1277*324bb76bSAndroid Build Coastguard Worker if (DGifGetExtensionNext(GifFile, &ExtData) ==
1278*324bb76bSAndroid Build Coastguard Worker GIF_ERROR) {
1279*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1280*324bb76bSAndroid Build Coastguard Worker }
1281*324bb76bSAndroid Build Coastguard Worker if (ExtData == NULL) {
1282*324bb76bSAndroid Build Coastguard Worker break;
1283*324bb76bSAndroid Build Coastguard Worker }
1284*324bb76bSAndroid Build Coastguard Worker /* Continue the extension block */
1285*324bb76bSAndroid Build Coastguard Worker if (GifAddExtensionBlock(
1286*324bb76bSAndroid Build Coastguard Worker &GifFile->ExtensionBlockCount,
1287*324bb76bSAndroid Build Coastguard Worker &GifFile->ExtensionBlocks,
1288*324bb76bSAndroid Build Coastguard Worker CONTINUE_EXT_FUNC_CODE, ExtData[0],
1289*324bb76bSAndroid Build Coastguard Worker &ExtData[1]) == GIF_ERROR) {
1290*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1291*324bb76bSAndroid Build Coastguard Worker }
1292*324bb76bSAndroid Build Coastguard Worker }
1293*324bb76bSAndroid Build Coastguard Worker break;
1294*324bb76bSAndroid Build Coastguard Worker
1295*324bb76bSAndroid Build Coastguard Worker case TERMINATE_RECORD_TYPE:
1296*324bb76bSAndroid Build Coastguard Worker break;
1297*324bb76bSAndroid Build Coastguard Worker
1298*324bb76bSAndroid Build Coastguard Worker default: /* Should be trapped by DGifGetRecordType */
1299*324bb76bSAndroid Build Coastguard Worker break;
1300*324bb76bSAndroid Build Coastguard Worker }
1301*324bb76bSAndroid Build Coastguard Worker } while (RecordType != TERMINATE_RECORD_TYPE);
1302*324bb76bSAndroid Build Coastguard Worker
1303*324bb76bSAndroid Build Coastguard Worker /* Sanity check for corrupted file */
1304*324bb76bSAndroid Build Coastguard Worker if (GifFile->ImageCount == 0) {
1305*324bb76bSAndroid Build Coastguard Worker GifFile->Error = D_GIF_ERR_NO_IMAG_DSCR;
1306*324bb76bSAndroid Build Coastguard Worker return (GIF_ERROR);
1307*324bb76bSAndroid Build Coastguard Worker }
1308*324bb76bSAndroid Build Coastguard Worker
1309*324bb76bSAndroid Build Coastguard Worker return (GIF_OK);
1310*324bb76bSAndroid Build Coastguard Worker }
1311*324bb76bSAndroid Build Coastguard Worker
1312*324bb76bSAndroid Build Coastguard Worker /* end */
1313