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