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