xref: /aosp_15_r20/external/giflib/dgif_lib.c (revision 324bb76b8d05e2a05aa88511fff61cf3f9ca5892)
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