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