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