428
|
1 /******************************************************************************
|
|
2 * "Gif-Lib" - Yet another gif library. *
|
|
3 * *
|
|
4 * Written by: Gershon Elber IBM PC Ver 1.1, Aug. 1990 *
|
|
5 *******************************************************************************
|
|
6 * The kernel of the GIF Decoding process can be found here. *
|
|
7 *******************************************************************************
|
|
8 * History: *
|
|
9 * 16 Jun 89 - Version 1.0 by Gershon Elber. *
|
|
10 * 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *
|
|
11 * 19 Feb 98 - Version 1.2 by Jareth Hein (Support for user specified I/O) *
|
|
12 ******************************************************************************/
|
|
13
|
442
|
14 #include <config.h>
|
|
15 #include "lisp.h"
|
428
|
16
|
442
|
17 #include "sysfile.h"
|
428
|
18
|
|
19 #include "gifrlib.h"
|
|
20
|
|
21 #define PROGRAM_NAME "GIFLIB"
|
|
22
|
|
23
|
|
24 static void DGifGetWord(GifFileType *GifFile, int *Word);
|
|
25 static void DGifSetupDecompress(GifFileType *GifFile);
|
|
26 static void DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
|
|
27 int LineLen);
|
|
28 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode);
|
|
29 static void DGifDecompressInput(GifFileType *GifFile, int *Code);
|
|
30 static void DGifBufferedInput(GifFileType *GifFile, GifByteType *NextByte);
|
|
31
|
|
32 /******************************************************************************
|
|
33 * Open a new gif file for read, given by its name. *
|
|
34 * Returns GifFileType pointer dynamically allocated which serves as the gif *
|
|
35 * info record. *
|
|
36 ******************************************************************************/
|
|
37 void DGifOpenFileName(GifFileType *GifFile, const char *FileName)
|
|
38 {
|
|
39 FILE *f;
|
|
40
|
|
41 if ((f = fopen(FileName,
|
442
|
42 #ifdef WIN32_NATIVE
|
428
|
43 "rb"
|
|
44 #else
|
|
45 "r"
|
442
|
46 #endif /* WIN32_NATIVE */
|
428
|
47 )) == NULL)
|
|
48 GifInternError(GifFile, D_GIF_ERR_OPEN_FAILED);
|
|
49
|
|
50 GifStdIOInit(GifFile, f, -1);
|
|
51 DGifInitRead(GifFile);
|
|
52 }
|
|
53
|
|
54 /******************************************************************************
|
|
55 * Update a new gif file, given its file handle. *
|
|
56 * Returns GifFileType pointer dynamically allocated which serves as the gif *
|
|
57 * info record. *
|
|
58 ******************************************************************************/
|
|
59 void DGifOpenFileHandle(GifFileType *GifFile, int FileHandle)
|
|
60 {
|
|
61 FILE *f;
|
|
62
|
442
|
63 #ifdef WIN32_NATIVE
|
428
|
64 setmode(FileHandle, O_BINARY); /* Make sure it is in binary mode. */
|
|
65 f = fdopen(FileHandle, "rb"); /* Make it into a stream: */
|
|
66 setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);/* And inc. stream buffer.*/
|
|
67 #else
|
|
68 f = fdopen(FileHandle, "r"); /* Make it into a stream: */
|
442
|
69 #endif /* WIN32_NATIVE */
|
428
|
70
|
|
71 GifStdIOInit(GifFile, f, -1);
|
|
72 DGifInitRead(GifFile);
|
|
73 }
|
|
74
|
|
75 /******************************************************************************
|
|
76 * Update a new gif file, given its file handle. *
|
|
77 * Returns GifFileType pointer dynamically allocated which serves as the gif *
|
|
78 * info record. _GifError is cleared if succesfull. *
|
|
79 ******************************************************************************/
|
|
80 void DGifInitRead(GifFileType *GifFile)
|
|
81 {
|
|
82 GifByteType Buf[GIF_STAMP_LEN+1];
|
|
83 GifFilePrivateType *Private;
|
|
84
|
|
85 if ((Private = (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
|
|
86 == NULL) {
|
|
87 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
|
|
88 }
|
|
89 memset(Private, '\0', sizeof(GifFilePrivateType));
|
|
90 GifFile->Private = (VoidPtr) Private;
|
|
91
|
|
92 Private->FileState = 0; /* Make sure bit 0 = 0 (File open for read). */
|
|
93
|
|
94 /* Lets see if this is a GIF file: */
|
|
95 GifRead(Buf, GIF_STAMP_LEN, GifFile);
|
|
96
|
|
97 /* The GIF Version number is ignored at this time. Maybe we should do */
|
|
98 /* something more useful with it. */
|
|
99 Buf[GIF_STAMP_LEN] = 0;
|
|
100 if (strncmp(GIF_STAMP, (const char *) Buf, GIF_VERSION_POS) != 0) {
|
|
101 GifInternError(GifFile, D_GIF_ERR_NOT_GIF_FILE);
|
|
102 }
|
|
103
|
|
104 DGifGetScreenDesc(GifFile);
|
|
105 }
|
|
106
|
|
107 /******************************************************************************
|
|
108 * This routine should be called before any other DGif calls. Note that *
|
|
109 * this routine is called automatically from DGif file open routines. *
|
|
110 ******************************************************************************/
|
|
111 void DGifGetScreenDesc(GifFileType *GifFile)
|
|
112 {
|
|
113 int i, BitsPerPixel;
|
|
114 GifByteType Buf[3];
|
|
115 GifFilePrivateType *Private = (GifFilePrivateType*) GifFile->Private;
|
|
116
|
|
117 if (!IS_READABLE(Private)) {
|
|
118 /* This file was NOT open for reading: */
|
|
119 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
120 }
|
|
121
|
|
122 /* Put the screen descriptor into the file: */
|
|
123 DGifGetWord(GifFile, &GifFile->SWidth);
|
|
124 DGifGetWord(GifFile, &GifFile->SHeight);
|
|
125
|
|
126 GifRead(Buf, 3, GifFile);
|
|
127 GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
|
|
128 BitsPerPixel = (Buf[0] & 0x07) + 1;
|
|
129 GifFile->SBackGroundColor = Buf[1];
|
|
130 if (Buf[0] & 0x80) { /* Do we have global color map? */
|
|
131
|
|
132 GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
|
|
133
|
|
134 /* Get the global color map: */
|
|
135 for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
|
|
136 GifRead(Buf, 3, GifFile);
|
|
137 GifFile->SColorMap->Colors[i].Red = Buf[0];
|
|
138 GifFile->SColorMap->Colors[i].Green = Buf[1];
|
|
139 GifFile->SColorMap->Colors[i].Blue = Buf[2];
|
|
140 }
|
|
141 } else {
|
|
142 /* We should always have a colormap */
|
|
143 GifFile->SColorMap = MakeMapObject(2, NULL);
|
|
144 GifFile->SColorMap->Colors[0].Red = 0;
|
|
145 GifFile->SColorMap->Colors[0].Green = 0;
|
|
146 GifFile->SColorMap->Colors[0].Blue = 0;
|
|
147 GifFile->SColorMap->Colors[1].Red = 0xff;
|
|
148 GifFile->SColorMap->Colors[1].Green = 0xff;
|
|
149 GifFile->SColorMap->Colors[1].Blue = 0xff;
|
|
150 }
|
|
151 }
|
|
152
|
|
153 /******************************************************************************
|
|
154 * This routine should be called before any attemp to read an image. *
|
|
155 ******************************************************************************/
|
|
156 void DGifGetRecordType(GifFileType *GifFile, GifRecordType *Type)
|
|
157 {
|
|
158 GifByteType Buf;
|
|
159 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
160
|
|
161 if (!IS_READABLE(Private)) {
|
|
162 /* This file was NOT open for reading: */
|
|
163 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
164 }
|
|
165
|
|
166 GifRead(&Buf, 1, GifFile);
|
|
167
|
|
168 switch (Buf) {
|
|
169 case ',':
|
|
170 *Type = IMAGE_DESC_RECORD_TYPE;
|
|
171 break;
|
|
172 case '!':
|
|
173 *Type = EXTENSION_RECORD_TYPE;
|
|
174 break;
|
|
175 case ';':
|
|
176 *Type = TERMINATE_RECORD_TYPE;
|
|
177 break;
|
|
178 default:
|
|
179 *Type = UNDEFINED_RECORD_TYPE;
|
|
180 GifInternError(GifFile, D_GIF_ERR_WRONG_RECORD);
|
|
181 }
|
|
182 }
|
|
183
|
|
184 /******************************************************************************
|
|
185 * This routine should be called before any attemp to read an image. *
|
|
186 * Note it is assumed the Image desc. header (',') has been read. *
|
|
187 ******************************************************************************/
|
|
188 void DGifGetImageDesc(GifFileType *GifFile)
|
|
189 {
|
|
190 int i, BitsPerPixel;
|
|
191 GifByteType Buf[3];
|
|
192 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
193
|
|
194 if (!IS_READABLE(Private)) {
|
|
195 /* This file was NOT open for reading: */
|
|
196 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
197 }
|
|
198
|
|
199 DGifGetWord(GifFile, &GifFile->Image.Left);
|
|
200 DGifGetWord(GifFile, &GifFile->Image.Top);
|
|
201 DGifGetWord(GifFile, &GifFile->Image.Width);
|
|
202 DGifGetWord(GifFile, &GifFile->Image.Height);
|
|
203
|
|
204 GifRead(Buf, 1, GifFile);
|
|
205 BitsPerPixel = (Buf[0] & 0x07) + 1;
|
|
206 GifFile->Image.Interlace = (Buf[0] & 0x40);
|
|
207 if (Buf[0] & 0x80) { /* Does this image have local color map? */
|
|
208
|
|
209 if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL)
|
|
210 FreeMapObject(GifFile->Image.ColorMap);
|
|
211
|
|
212 GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
|
|
213
|
|
214 /* Get the image local color map: */
|
|
215 for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
|
|
216 GifRead(Buf, 3, GifFile);
|
|
217 GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
|
|
218 GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
|
|
219 GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
|
|
220 }
|
|
221 }
|
|
222
|
|
223 if (GifFile->SavedImages) {
|
|
224 SavedImage *sp;
|
|
225
|
|
226 if ((GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
|
|
227 sizeof(SavedImage) * (GifFile->ImageCount + 1))) == NULL) {
|
|
228 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
|
|
229 }
|
|
230
|
|
231 sp = &GifFile->SavedImages[GifFile->ImageCount];
|
|
232 memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
|
|
233 if (GifFile->Image.ColorMap)
|
|
234 {
|
|
235 sp->ImageDesc.ColorMap =
|
|
236 MakeMapObject (GifFile->Image.ColorMap->ColorCount,
|
|
237 GifFile->Image.ColorMap->Colors);
|
|
238 }
|
|
239 sp->RasterBits = NULL;
|
|
240 sp->ExtensionBlockCount = 0;
|
|
241 sp->ExtensionBlocks = (ExtensionBlock *)NULL;
|
|
242 }
|
|
243
|
|
244 GifFile->ImageCount++;
|
|
245
|
|
246 Private->PixelCount = (long) GifFile->Image.Width *
|
|
247 (long) GifFile->Image.Height;
|
|
248
|
|
249 DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */
|
|
250 }
|
|
251
|
|
252 /******************************************************************************
|
|
253 * Get one full scanned line (Line) of length LineLen from GIF file. *
|
|
254 ******************************************************************************/
|
|
255 void DGifGetLine(GifFileType *GifFile, GifPixelType *Line, int LineLen)
|
|
256 {
|
|
257 GifByteType *Dummy;
|
|
258 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
259
|
|
260 if (!IS_READABLE(Private)) {
|
|
261 /* This file was NOT open for reading: */
|
|
262 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
263 }
|
|
264
|
|
265 if (!LineLen) LineLen = GifFile->Image.Width;
|
|
266
|
442
|
267 #if defined(WIN32_NATIVE) || defined(__GNUC__)
|
428
|
268 if ((Private->PixelCount -= LineLen) > 0xffff0000UL)
|
|
269 #else
|
|
270 if ((Private->PixelCount -= LineLen) > 0xffff0000)
|
442
|
271 #endif /* WIN32_NATIVE */
|
428
|
272 {
|
|
273 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
|
|
274 }
|
|
275
|
|
276 DGifDecompressLine(GifFile, Line, LineLen);
|
|
277 if (Private->PixelCount == 0) {
|
|
278 /* We probably would not be called any more, so lets clean */
|
|
279 /* everything before we return: need to flush out all rest of */
|
|
280 /* image until empty block (size 0) detected. We use GetCodeNext.*/
|
|
281 do
|
|
282 DGifGetCodeNext(GifFile, &Dummy);
|
|
283 while (Dummy != NULL);
|
|
284 }
|
|
285 }
|
|
286
|
|
287 /******************************************************************************
|
|
288 * Put one pixel (Pixel) into GIF file. *
|
|
289 ******************************************************************************/
|
|
290 void DGifGetPixel(GifFileType *GifFile, GifPixelType Pixel)
|
|
291 {
|
|
292 GifByteType *Dummy;
|
|
293 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
294
|
|
295 if (!IS_READABLE(Private)) {
|
|
296 /* This file was NOT open for reading: */
|
|
297 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
298 }
|
|
299
|
442
|
300 #if defined(WIN32_NATIVE) || defined(__GNUC__)
|
428
|
301 if (--Private->PixelCount > 0xffff0000UL)
|
|
302 #else
|
|
303 if (--Private->PixelCount > 0xffff0000)
|
442
|
304 #endif /* WIN32_NATIVE */
|
428
|
305 {
|
|
306 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
|
|
307 }
|
|
308
|
|
309 DGifDecompressLine(GifFile, &Pixel, 1);
|
|
310 if (Private->PixelCount == 0) {
|
|
311 /* We probably would not be called any more, so lets clean */
|
|
312 /* everything before we return: need to flush out all rest of */
|
|
313 /* image until empty block (size 0) detected. We use GetCodeNext.*/
|
|
314 do
|
|
315 DGifGetCodeNext(GifFile, &Dummy);
|
|
316 while (Dummy != NULL);
|
|
317 }
|
|
318 }
|
|
319
|
|
320 /******************************************************************************
|
|
321 * Get an extension block (see GIF manual) from gif file. This routine only *
|
|
322 * returns the first data block, and DGifGetExtensionNext shouldbe called *
|
|
323 * after this one until NULL extension is returned. *
|
|
324 * The Extension should NOT be freed by the user (not dynamically allocated).*
|
|
325 * Note it is assumed the Extension desc. header ('!') has been read. *
|
|
326 ******************************************************************************/
|
|
327 void DGifGetExtension(GifFileType *GifFile, int *ExtCode,
|
|
328 GifByteType **Extension)
|
|
329 {
|
|
330 GifByteType Buf;
|
|
331 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
332
|
|
333 if (!IS_READABLE(Private)) {
|
|
334 /* This file was NOT open for reading: */
|
|
335 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
336 }
|
|
337
|
|
338 GifRead(&Buf, 1, GifFile);
|
|
339 *ExtCode = Buf;
|
|
340
|
|
341 DGifGetExtensionNext(GifFile, Extension);
|
|
342 }
|
|
343
|
|
344 /******************************************************************************
|
|
345 * Get a following extension block (see GIF manual) from gif file. This *
|
|
346 * routine sould be called until NULL Extension is returned. *
|
|
347 * The Extension should NOT be freed by the user (not dynamically allocated).*
|
|
348 ******************************************************************************/
|
|
349 void DGifGetExtensionNext(GifFileType *GifFile, GifByteType **Extension)
|
|
350 {
|
|
351 GifByteType Buf;
|
|
352 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
353
|
|
354 GifRead(&Buf, 1, GifFile);
|
|
355 if (Buf > 0) {
|
|
356 *Extension = Private->Buf; /* Use private unused buffer. */
|
|
357 (*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
|
|
358 GifRead(&((*Extension)[1]), Buf, GifFile);
|
|
359 }
|
|
360 else
|
|
361 *Extension = NULL;
|
|
362 }
|
|
363
|
|
364 /******************************************************************************
|
|
365 * This routine should be called second to last, to close the GIF file. *
|
|
366 ******************************************************************************/
|
|
367 int DGifCloseFile(GifFileType *GifFile)
|
|
368 {
|
3462
|
369 GifFilePrivateType *Private;
|
428
|
370
|
|
371 if (GifFile == NULL) return -1;
|
|
372
|
3462
|
373 Private = (GifFilePrivateType *)GifFile->Private;
|
428
|
374 if (!IS_READABLE(Private))
|
|
375 {
|
|
376 /* This file was NOT open for reading: */
|
|
377 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
378 }
|
|
379
|
|
380 if (GifClose (GifFile))
|
|
381 {
|
|
382 GifInternError(GifFile, D_GIF_ERR_CLOSE_FAILED);
|
|
383 }
|
|
384 return 0;
|
|
385 }
|
|
386
|
|
387 /******************************************************************************
|
|
388 * Get 2 bytes (word) from the given file: *
|
|
389 ******************************************************************************/
|
|
390 static void DGifGetWord(GifFileType *GifFile, int *Word)
|
|
391 {
|
|
392 unsigned char c[2];
|
|
393
|
|
394 GifRead(c, 2, GifFile);
|
|
395
|
|
396 *Word = (((unsigned int) c[1]) << 8) + c[0];
|
|
397 }
|
|
398
|
|
399 /******************************************************************************
|
|
400 * Get the image code in compressed form. his routine can be called if the *
|
|
401 * information needed to be piped out as is. Obviously this is much faster *
|
|
402 * than decoding and encoding again. This routine should be followed by calls *
|
|
403 * to DGifGetCodeNext, until NULL block is returned. *
|
|
404 * The block should NOT be freed by the user (not dynamically allocated). *
|
|
405 ******************************************************************************/
|
|
406 void DGifGetCode(GifFileType *GifFile, int *CodeSize, GifByteType **CodeBlock)
|
|
407 {
|
|
408 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
409
|
|
410 if (!IS_READABLE(Private)) {
|
|
411 /* This file was NOT open for reading: */
|
|
412 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
413 }
|
|
414
|
|
415 *CodeSize = Private->BitsPerPixel;
|
|
416
|
|
417 DGifGetCodeNext(GifFile, CodeBlock);
|
|
418 }
|
|
419
|
|
420 /******************************************************************************
|
|
421 * Continue to get the image code in compressed form. This routine should be *
|
|
422 * called until NULL block is returned. *
|
|
423 * The block should NOT be freed by the user (not dynamically allocated). *
|
|
424 ******************************************************************************/
|
|
425 void DGifGetCodeNext(GifFileType *GifFile, GifByteType **CodeBlock)
|
|
426 {
|
|
427 GifByteType Buf;
|
|
428 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
429
|
|
430 GifRead(&Buf, 1, GifFile);
|
|
431
|
|
432 if (Buf > 0) {
|
|
433 *CodeBlock = Private->Buf; /* Use private unused buffer. */
|
|
434 (*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
|
|
435 GifRead(&((*CodeBlock)[1]), Buf, GifFile);
|
|
436 }
|
|
437 else {
|
|
438 *CodeBlock = NULL;
|
|
439 Private->Buf[0] = 0; /* Make sure the buffer is empty! */
|
|
440 Private->PixelCount = 0; /* And local info. indicate image read. */
|
|
441 }
|
|
442
|
|
443 }
|
|
444
|
|
445 /******************************************************************************
|
|
446 * Setup the LZ decompression for this image: *
|
|
447 ******************************************************************************/
|
|
448 static void DGifSetupDecompress(GifFileType *GifFile)
|
|
449 {
|
|
450 int i, BitsPerPixel;
|
|
451 GifByteType CodeSize;
|
|
452 unsigned int *Prefix;
|
|
453 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
454
|
|
455 GifRead(&CodeSize, 1, GifFile); /* Read Code size from file. */
|
|
456 BitsPerPixel = CodeSize;
|
|
457
|
|
458 Private->Buf[0] = 0; /* Input Buffer empty. */
|
|
459 Private->BitsPerPixel = BitsPerPixel;
|
|
460 Private->ClearCode = (1 << BitsPerPixel);
|
|
461 Private->EOFCode = Private->ClearCode + 1;
|
|
462 Private->RunningCode = Private->EOFCode + 1;
|
|
463 Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
|
|
464 Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
|
|
465 Private->StackPtr = 0; /* No pixels on the pixel stack. */
|
|
466 Private->LastCode = NO_SUCH_CODE;
|
|
467 Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
|
|
468 Private->CrntShiftDWord = 0;
|
|
469
|
|
470 Prefix = Private->Prefix;
|
|
471 for (i = 0; i <= LZ_MAX_CODE; i++) Prefix[i] = NO_SUCH_CODE;
|
|
472 }
|
|
473
|
|
474 /******************************************************************************
|
|
475 * The LZ decompression routine: *
|
|
476 * This version decompress the given gif file into Line of length LineLen. *
|
|
477 * This routine can be called few times (one per scan line, for example), in *
|
|
478 * order the complete the whole image. *
|
|
479 ******************************************************************************/
|
|
480 static void DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line,
|
|
481 int LineLen)
|
|
482 {
|
|
483 int i = 0, j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
|
|
484 GifByteType *Stack, *Suffix;
|
|
485 unsigned int *Prefix;
|
|
486 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
487
|
|
488 StackPtr = Private->StackPtr;
|
|
489 Prefix = Private->Prefix;
|
|
490 Suffix = Private->Suffix;
|
|
491 Stack = Private->Stack;
|
|
492 EOFCode = Private->EOFCode;
|
|
493 ClearCode = Private->ClearCode;
|
|
494 LastCode = Private->LastCode;
|
|
495
|
|
496 CrntPrefix = 0;
|
|
497 if (StackPtr != 0) {
|
|
498 /* Let pop the stack off before continueing to read the gif file: */
|
|
499 while (StackPtr != 0 && i < LineLen) Line[i++] = Stack[--StackPtr];
|
|
500 }
|
|
501
|
|
502 while (i < LineLen) { /* Decode LineLen items. */
|
|
503 DGifDecompressInput(GifFile, &CrntCode);
|
|
504
|
|
505 if (CrntCode == EOFCode) {
|
|
506 /* Note however that usually we will not be here as we will stop */
|
|
507 /* decoding as soon as we got all the pixel, or EOF code will */
|
|
508 /* not be read at all, and DGifGetLine/Pixel clean everything. */
|
|
509 if (i != LineLen - 1 || Private->PixelCount != 0) {
|
|
510 GifInternError(GifFile, D_GIF_ERR_EOF_TOO_SOON);
|
|
511 }
|
|
512 i++;
|
|
513 }
|
|
514 else if (CrntCode == ClearCode) {
|
|
515 /* We need to start over again: */
|
|
516 for (j = 0; j <= LZ_MAX_CODE; j++) Prefix[j] = NO_SUCH_CODE;
|
|
517 Private->RunningCode = Private->EOFCode + 1;
|
|
518 Private->RunningBits = Private->BitsPerPixel + 1;
|
|
519 Private->MaxCode1 = 1 << Private->RunningBits;
|
|
520 LastCode = Private->LastCode = NO_SUCH_CODE;
|
|
521 }
|
|
522 else {
|
|
523 /* Its regular code - if in pixel range simply add it to output */
|
|
524 /* stream, otherwise trace to codes linked list until the prefix */
|
|
525 /* is in pixel range: */
|
|
526 if (CrntCode < ClearCode) {
|
|
527 /* This is simple - its pixel scalar, so add it to output: */
|
|
528 Line[i++] = CrntCode;
|
|
529 }
|
|
530 else {
|
|
531 /* Its a code to needed to be traced: trace the linked list */
|
|
532 /* until the prefix is a pixel, while pushing the suffix */
|
|
533 /* pixels on our stack. If we done, pop the stack in reverse */
|
|
534 /* (thats what stack is good for!) order to output. */
|
|
535 if (Prefix[CrntCode] == NO_SUCH_CODE) {
|
|
536 /* Only allowed if CrntCode is exactly the running code: */
|
|
537 /* In that case CrntCode = XXXCode, CrntCode or the */
|
|
538 /* prefix code is last code and the suffix char is */
|
|
539 /* exactly the prefix of last code! */
|
|
540 if (CrntCode == Private->RunningCode - 2) {
|
|
541 CrntPrefix = LastCode;
|
|
542 Suffix[Private->RunningCode - 2] =
|
|
543 Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
|
|
544 LastCode, ClearCode);
|
|
545 }
|
|
546 else {
|
|
547 GifInternError(GifFile, D_GIF_ERR_IMAGE_DEFECT);
|
|
548 }
|
|
549 }
|
|
550 else
|
|
551 CrntPrefix = CrntCode;
|
|
552
|
|
553 /* Now (if image is O.K.) we should not get an NO_SUCH_CODE */
|
|
554 /* During the trace. As we might loop forever, in case of */
|
|
555 /* defective image, we count the number of loops we trace */
|
|
556 /* and stop if we got LZ_MAX_CODE. obviously we can not */
|
|
557 /* loop more than that. */
|
|
558 j = 0;
|
|
559 while (j++ <= LZ_MAX_CODE &&
|
|
560 CrntPrefix > ClearCode &&
|
|
561 CrntPrefix <= LZ_MAX_CODE) {
|
|
562 Stack[StackPtr++] = Suffix[CrntPrefix];
|
|
563 CrntPrefix = Prefix[CrntPrefix];
|
|
564 }
|
|
565 if (j >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {
|
|
566 GifInternError(GifFile, D_GIF_ERR_IMAGE_DEFECT);
|
|
567 }
|
|
568 /* Push the last character on stack: */
|
|
569 Stack[StackPtr++] = CrntPrefix;
|
|
570
|
|
571 /* Now lets pop all the stack into output: */
|
|
572 while (StackPtr != 0 && i < LineLen)
|
|
573 Line[i++] = Stack[--StackPtr];
|
|
574 }
|
|
575 if (LastCode != NO_SUCH_CODE) {
|
|
576 Prefix[Private->RunningCode - 2] = LastCode;
|
|
577
|
|
578 if (CrntCode == Private->RunningCode - 2) {
|
|
579 /* Only allowed if CrntCode is exactly the running code: */
|
|
580 /* In that case CrntCode = XXXCode, CrntCode or the */
|
|
581 /* prefix code is last code and the suffix char is */
|
|
582 /* exactly the prefix of last code! */
|
|
583 Suffix[Private->RunningCode - 2] =
|
|
584 DGifGetPrefixChar(Prefix, LastCode, ClearCode);
|
|
585 }
|
|
586 else {
|
|
587 Suffix[Private->RunningCode - 2] =
|
|
588 DGifGetPrefixChar(Prefix, CrntCode, ClearCode);
|
|
589 }
|
|
590 }
|
|
591 LastCode = CrntCode;
|
|
592 }
|
|
593 }
|
|
594
|
|
595 Private->LastCode = LastCode;
|
|
596 Private->StackPtr = StackPtr;
|
|
597 }
|
|
598
|
|
599 /******************************************************************************
|
|
600 * Routine to trace the Prefixes linked list until we get a prefix which is *
|
|
601 * not code, but a pixel value (less than ClearCode). Returns that pixel value.*
|
|
602 * If image is defective, we might loop here forever, so we limit the loops to *
|
|
603 * the maximum possible if image O.k. - LZ_MAX_CODE times. *
|
|
604 ******************************************************************************/
|
|
605 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode)
|
|
606 {
|
|
607 int i = 0;
|
|
608
|
|
609 while (Code > ClearCode && i++ <= LZ_MAX_CODE) Code = Prefix[Code];
|
|
610 return Code;
|
|
611 }
|
|
612
|
|
613 /******************************************************************************
|
|
614 * Interface for accessing the LZ codes directly. Set Code to the real code *
|
|
615 * (12bits), or to -1 if EOF code is returned. *
|
|
616 ******************************************************************************/
|
|
617 void DGifGetLZCodes(GifFileType *GifFile, int *Code)
|
|
618 {
|
|
619 GifByteType *CodeBlock;
|
|
620 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
621
|
|
622 if (!IS_READABLE(Private)) {
|
|
623 /* This file was NOT open for reading: */
|
|
624 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
|
|
625 }
|
|
626
|
|
627 DGifDecompressInput(GifFile, Code);
|
|
628
|
|
629 if (*Code == Private->EOFCode) {
|
|
630 /* Skip rest of codes (hopefully only NULL terminating block): */
|
|
631 do
|
|
632 DGifGetCodeNext(GifFile, &CodeBlock);
|
|
633 while (CodeBlock != NULL);
|
|
634
|
|
635 *Code = -1;
|
|
636 }
|
|
637 else if (*Code == Private->ClearCode) {
|
|
638 /* We need to start over again: */
|
|
639 Private->RunningCode = Private->EOFCode + 1;
|
|
640 Private->RunningBits = Private->BitsPerPixel + 1;
|
|
641 Private->MaxCode1 = 1 << Private->RunningBits;
|
|
642 }
|
|
643 }
|
|
644
|
|
645 /******************************************************************************
|
|
646 * The LZ decompression input routine: *
|
|
647 * This routine is responsable for the decompression of the bit stream from *
|
|
648 * 8 bits (bytes) packets, into the real codes. *
|
|
649 * Returns GIF_OK if read succesfully. *
|
|
650 ******************************************************************************/
|
|
651 static void DGifDecompressInput(GifFileType *GifFile, int *Code)
|
|
652 {
|
|
653 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
654 GifByteType NextByte;
|
|
655 static unsigned int CodeMasks[] = {
|
|
656 0x0000, 0x0001, 0x0003, 0x0007,
|
|
657 0x000f, 0x001f, 0x003f, 0x007f,
|
|
658 0x00ff, 0x01ff, 0x03ff, 0x07ff,
|
|
659 0x0fff
|
|
660 };
|
|
661
|
|
662 while (Private->CrntShiftState < Private->RunningBits) {
|
|
663 /* Needs to get more bytes from input stream for next code: */
|
|
664 DGifBufferedInput(GifFile, &NextByte);
|
|
665 Private->CrntShiftDWord |=
|
|
666 ((unsigned long) NextByte) << Private->CrntShiftState;
|
|
667 Private->CrntShiftState += 8;
|
|
668 }
|
|
669 *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
|
|
670
|
|
671 Private->CrntShiftDWord >>= Private->RunningBits;
|
|
672 Private->CrntShiftState -= Private->RunningBits;
|
|
673
|
|
674 /* If code cannt fit into RunningBits bits, must raise its size. Note */
|
|
675 /* however that codes above 4095 are used for special signaling. */
|
|
676 if (++Private->RunningCode > Private->MaxCode1 &&
|
|
677 Private->RunningBits < LZ_BITS) {
|
|
678 Private->MaxCode1 <<= 1;
|
|
679 Private->RunningBits++;
|
|
680 }
|
|
681 }
|
|
682
|
|
683 /******************************************************************************
|
|
684 * This routines read one gif data block at a time and buffers it internally *
|
|
685 * so that the decompression routine could access it. *
|
|
686 * The routine returns the next byte from its internal buffer (or read next *
|
|
687 * block in if buffer empty) *
|
|
688 ******************************************************************************/
|
|
689 static void DGifBufferedInput(GifFileType *GifFile, GifByteType *NextByte)
|
|
690 {
|
|
691 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
|
|
692 GifByteType *Buf = Private->Buf;
|
|
693
|
|
694 if (Buf[0] == 0) {
|
|
695 /* Needs to read the next buffer - this one is empty: */
|
|
696 GifRead(Buf, 1, GifFile);
|
|
697 GifRead((Buf + 1), Buf[0], GifFile);
|
|
698 *NextByte = Buf[1];
|
|
699 Buf[1] = 2; /* We use now the second place as last char read! */
|
|
700 Buf[0]--;
|
|
701 }
|
|
702 else {
|
|
703 *NextByte = Buf[Buf[1]++];
|
|
704 Buf[0]--;
|
|
705 }
|
|
706 }
|
|
707
|
|
708 /******************************************************************************
|
|
709 * This routine reads an entire GIF into core, hanging all its state info off *
|
|
710 * the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle() *
|
|
711 * first to initialize I/O. Its inverse is EGifSpew(). *
|
|
712 ******************************************************************************/
|
|
713 void DGifSlurp(GifFileType *GifFile)
|
|
714 {
|
|
715 int ImageSize;
|
|
716 GifRecordType RecordType;
|
|
717 SavedImage *sp;
|
|
718 GifByteType *ExtData;
|
|
719
|
|
720 /* Some versions of malloc dislike 0-length requests */
|
|
721 GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
|
722 memset(GifFile->SavedImages, 0, sizeof(SavedImage));
|
|
723 sp = &GifFile->SavedImages[0];
|
|
724
|
|
725 do {
|
|
726 DGifGetRecordType(GifFile, &RecordType);
|
|
727
|
|
728 switch (RecordType) {
|
|
729 case IMAGE_DESC_RECORD_TYPE:
|
|
730 DGifGetImageDesc(GifFile);
|
|
731
|
|
732 sp = &GifFile->SavedImages[GifFile->ImageCount-1];
|
|
733 ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
|
|
734
|
|
735 sp->RasterBits
|
|
736 = (GifPixelType*) malloc (ImageSize * sizeof(GifPixelType));
|
|
737
|
|
738 DGifGetLine(GifFile, sp->RasterBits, ImageSize);
|
|
739 break;
|
|
740
|
|
741 case EXTENSION_RECORD_TYPE:
|
|
742 DGifGetExtension(GifFile,&sp->Function,&ExtData);
|
|
743
|
2062
|
744 while (ExtData != NULL) {
|
428
|
745 if (AddExtensionBlock(sp, ExtData[0], ExtData+1) == GIF_ERROR)
|
|
746 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
|
|
747 DGifGetExtensionNext(GifFile, &ExtData);
|
2062
|
748 }
|
428
|
749 break;
|
|
750
|
|
751 case TERMINATE_RECORD_TYPE:
|
|
752 break;
|
|
753
|
|
754 default: /* Should be trapped by DGifGetRecordType */
|
|
755 break;
|
|
756 }
|
|
757 } while (RecordType != TERMINATE_RECORD_TYPE);
|
|
758 }
|
|
759
|
|
760 /******************************************************************************
|
|
761 * Extension record functions *
|
|
762 ******************************************************************************/
|
|
763
|
|
764 void MakeExtension(SavedImage *New, int Function)
|
|
765 {
|
|
766 New->Function = Function;
|
|
767 /*
|
|
768 * Someday we might have to deal with multiple extensions.
|
|
769 */
|
|
770 }
|
|
771
|
|
772 int AddExtensionBlock(SavedImage *New, int Len, GifByteType *data)
|
|
773 {
|
|
774 int size;
|
|
775 ExtensionBlock *ep;
|
|
776
|
|
777 if (New->ExtensionBlocks == NULL)
|
|
778 New->ExtensionBlocks = (ExtensionBlock *)malloc(sizeof(ExtensionBlock));
|
|
779 else
|
|
780 New->ExtensionBlocks =
|
|
781 (ExtensionBlock *)realloc(New->ExtensionBlocks,
|
|
782 sizeof(ExtensionBlock) * (New->ExtensionBlockCount + 1));
|
|
783
|
|
784 if (New->ExtensionBlocks == NULL)
|
|
785 return(GIF_ERROR);
|
|
786
|
|
787 ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
|
|
788 ep->ByteCount = Len;
|
|
789 size = Len * sizeof(GifByteType);
|
|
790 ep->Bytes = (GifByteType *)malloc(size);
|
|
791 memcpy(ep->Bytes, data, size);
|
|
792 return(GIF_OK);
|
|
793 }
|
|
794
|
|
795 void FreeExtension(SavedImage *Image)
|
|
796 {
|
|
797 ExtensionBlock *ep;
|
|
798
|
|
799 for (ep = Image->ExtensionBlocks;
|
|
800 ep < Image->ExtensionBlocks + Image->ExtensionBlockCount;
|
|
801 ep++)
|
|
802 (void) free((char *)ep->Bytes);
|
|
803 free((char *)Image->ExtensionBlocks);
|
|
804 Image->ExtensionBlocks = NULL;
|
|
805 }
|
|
806
|
|
807 /******************************************************************************
|
|
808 * Image block allocation functions *
|
|
809 ******************************************************************************/
|
|
810 SavedImage *MakeSavedImage(GifFileType *GifFile, SavedImage *CopyFrom)
|
|
811 /*
|
|
812 * Append an image block to the SavedImages array
|
|
813 */
|
|
814 {
|
|
815 SavedImage *sp;
|
|
816
|
|
817 if (GifFile->SavedImages == NULL)
|
|
818 GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
|
819 else
|
|
820 GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
|
|
821 sizeof(SavedImage) * (GifFile->ImageCount+1));
|
|
822
|
|
823 if (GifFile->SavedImages == NULL)
|
|
824 return((SavedImage *)NULL);
|
|
825 else
|
|
826 {
|
|
827 sp = &GifFile->SavedImages[GifFile->ImageCount++];
|
|
828 memset((char *)sp, '\0', sizeof(SavedImage));
|
|
829
|
|
830 if (CopyFrom)
|
|
831 {
|
|
832 memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
|
|
833
|
|
834 /*
|
|
835 * Make our own allocated copies of the heap fields in the
|
|
836 * copied record. This guards against potential aliasing
|
|
837 * problems.
|
|
838 */
|
|
839
|
|
840 /* first, the local color map */
|
|
841 if (sp->ImageDesc.ColorMap)
|
|
842 sp->ImageDesc.ColorMap =
|
|
843 MakeMapObject(CopyFrom->ImageDesc.ColorMap->ColorCount,
|
|
844 CopyFrom->ImageDesc.ColorMap->Colors);
|
|
845
|
|
846 /* next, the raster */
|
|
847 sp->RasterBits = (GifPixelType *) malloc(sizeof(GifPixelType)
|
|
848 * CopyFrom->ImageDesc.Height
|
|
849 * CopyFrom->ImageDesc.Width);
|
|
850 memcpy(sp->RasterBits,
|
|
851 CopyFrom->RasterBits,
|
|
852 sizeof(GifPixelType)
|
|
853 * CopyFrom->ImageDesc.Height
|
|
854 * CopyFrom->ImageDesc.Width);
|
|
855
|
|
856 /* finally, the extension blocks */
|
|
857 if (sp->ExtensionBlocks)
|
|
858 {
|
|
859 sp->ExtensionBlocks
|
|
860 = (ExtensionBlock*)malloc(sizeof(ExtensionBlock)
|
|
861 * CopyFrom->ExtensionBlockCount);
|
|
862 memcpy(sp->ExtensionBlocks,
|
|
863 CopyFrom->ExtensionBlocks,
|
|
864 sizeof(ExtensionBlock)
|
|
865 * CopyFrom->ExtensionBlockCount);
|
|
866
|
|
867 /*
|
|
868 * For the moment, the actual blocks can take their
|
|
869 * chances with free(). We'll fix this later.
|
|
870 */
|
|
871 }
|
|
872 }
|
|
873
|
|
874 return(sp);
|
|
875 }
|
|
876 }
|
|
877
|
|
878 void FreeSavedImages(GifFileType *GifFile)
|
|
879 {
|
|
880 SavedImage *sp;
|
|
881
|
|
882 for (sp = GifFile->SavedImages;
|
|
883 sp < GifFile->SavedImages + GifFile->ImageCount;
|
|
884 sp++)
|
|
885 {
|
|
886 if (sp->ImageDesc.ColorMap)
|
|
887 FreeMapObject(sp->ImageDesc.ColorMap);
|
|
888
|
|
889 if (sp->RasterBits)
|
|
890 free((char *)sp->RasterBits);
|
|
891
|
|
892 if (sp->ExtensionBlocks)
|
|
893 FreeExtension(sp);
|
|
894 }
|
|
895 free((char *) GifFile->SavedImages);
|
|
896 }
|
|
897
|
|
898 /******************************************************************************
|
|
899 * Miscellaneous utility functions *
|
|
900 ******************************************************************************/
|
|
901
|
|
902 static int BitSize(int n)
|
|
903 /* return smallest bitfield size n will fit in */
|
|
904 {
|
|
905 register int i;
|
|
906
|
|
907 for (i = 1; i <= 8; i++)
|
|
908 if ((1 << i) >= n)
|
|
909 break;
|
|
910 return(i);
|
|
911 }
|
|
912
|
|
913 /******************************************************************************
|
|
914 * Color map object functions *
|
|
915 ******************************************************************************/
|
|
916
|
|
917 ColorMapObject *MakeMapObject(int ColorCount, GifColorType *ColorMap)
|
|
918 /*
|
|
919 * Allocate a color map of given size; initialize with contents of
|
|
920 * ColorMap if that pointer is non-NULL.
|
|
921 */
|
|
922 {
|
|
923 ColorMapObject *Object;
|
|
924
|
|
925 if (ColorCount != (1 << BitSize(ColorCount)))
|
|
926 return((ColorMapObject *)NULL);
|
|
927
|
|
928 Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
|
|
929 if (Object == (ColorMapObject *)NULL)
|
|
930 return((ColorMapObject *)NULL);
|
|
931
|
|
932 Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
|
3462
|
933 if (Object->Colors == (GifColorType *)NULL) {
|
|
934 free(Object);
|
428
|
935 return((ColorMapObject *)NULL);
|
3462
|
936 }
|
428
|
937
|
|
938 Object->ColorCount = ColorCount;
|
|
939 Object->BitsPerPixel = BitSize(ColorCount);
|
|
940
|
|
941 if (ColorMap)
|
|
942 memcpy((char *)Object->Colors,
|
|
943 (char *)ColorMap, ColorCount * sizeof(GifColorType));
|
|
944
|
|
945 return(Object);
|
|
946 }
|
|
947
|
|
948 void FreeMapObject(ColorMapObject *Object)
|
|
949 /*
|
|
950 * Free a color map object
|
|
951 */
|
|
952 {
|
|
953 free(Object->Colors);
|
|
954 free(Object);
|
|
955 }
|