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