1 /******************************************************************************
2 * "Gif-Lib" - Yet another gif library. *
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 *******************************************************************************
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 ******************************************************************************/
19 #include "ui/gifrlib.h"
21 #define PROGRAM_NAME "GIFLIB"
23 static void DGifGetWord(GifFileType * GifFile, int *Word);
24 static void DGifSetupDecompress(GifFileType * GifFile);
25 static void DGifDecompressLine(GifFileType * GifFile, GifPixelType * Line,
27 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode);
28 static void DGifDecompressInput(GifFileType * GifFile, int *Code);
29 static void DGifBufferedInput(GifFileType * GifFile, GifByteType * NextByte);
31 /******************************************************************************
32 * Open a new gif file for read, given by its name. *
33 * Returns GifFileType pointer dynamically allocated which serves as the gif *
35 ******************************************************************************/
36 void DGifOpenFileName(GifFileType * GifFile, const char *FileName)
40 if ((f = fopen(FileName,
43 GifInternError(GifFile, D_GIF_ERR_OPEN_FAILED);
45 GifStdIOInit(GifFile, f, -1);
46 DGifInitRead(GifFile);
49 /******************************************************************************
50 * Update a new gif file, given its file handle. *
51 * Returns GifFileType pointer dynamically allocated which serves as the gif *
53 ******************************************************************************/
54 void DGifOpenFileHandle(GifFileType * GifFile, int FileHandle)
58 f = fdopen(FileHandle, "r"); /* Make it into a stream: */
60 GifStdIOInit(GifFile, f, -1);
61 DGifInitRead(GifFile);
64 /******************************************************************************
65 * Update a new gif file, given its file handle. *
66 * Returns GifFileType pointer dynamically allocated which serves as the gif *
67 * info record. _GifError is cleared if succesfull. *
68 ******************************************************************************/
69 void DGifInitRead(GifFileType * GifFile)
71 GifByteType Buf[GIF_STAMP_LEN + 1];
72 GifFilePrivateType *Private;
75 (GifFilePrivateType *) malloc(sizeof(GifFilePrivateType)))
77 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
79 memset(Private, '\0', sizeof(GifFilePrivateType));
80 GifFile->Private = (VoidPtr) Private;
82 Private->FileState = 0; /* Make sure bit 0 = 0 (File open for read). */
84 /* Lets see if this is a GIF file: */
85 GifRead(Buf, GIF_STAMP_LEN, GifFile);
87 /* The GIF Version number is ignored at this time. Maybe we should do */
88 /* something more useful with it. */
89 Buf[GIF_STAMP_LEN] = 0;
90 if (strncmp(GIF_STAMP, (const char *)Buf, GIF_VERSION_POS) != 0) {
91 GifInternError(GifFile, D_GIF_ERR_NOT_GIF_FILE);
94 DGifGetScreenDesc(GifFile);
97 /******************************************************************************
98 * This routine should be called before any other DGif calls. Note that *
99 * this routine is called automatically from DGif file open routines. *
100 ******************************************************************************/
101 void DGifGetScreenDesc(GifFileType * GifFile)
105 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
107 if (!IS_READABLE(Private)) {
108 /* This file was NOT open for reading: */
109 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
112 /* Put the screen descriptor into the file: */
113 DGifGetWord(GifFile, &GifFile->SWidth);
114 DGifGetWord(GifFile, &GifFile->SHeight);
116 GifRead(Buf, 3, GifFile);
117 GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
118 BitsPerPixel = (Buf[0] & 0x07) + 1;
119 GifFile->SBackGroundColor = Buf[1];
120 if (Buf[0] & 0x80) { /* Do we have global color map? */
122 GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
124 /* Get the global color map: */
125 for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
126 GifRead(Buf, 3, GifFile);
127 GifFile->SColorMap->Colors[i].Red = Buf[0];
128 GifFile->SColorMap->Colors[i].Green = Buf[1];
129 GifFile->SColorMap->Colors[i].Blue = Buf[2];
132 /* We should always have a colormap */
133 GifFile->SColorMap = MakeMapObject(2, NULL);
134 GifFile->SColorMap->Colors[0].Red = 0;
135 GifFile->SColorMap->Colors[0].Green = 0;
136 GifFile->SColorMap->Colors[0].Blue = 0;
137 GifFile->SColorMap->Colors[1].Red = 0xff;
138 GifFile->SColorMap->Colors[1].Green = 0xff;
139 GifFile->SColorMap->Colors[1].Blue = 0xff;
143 /******************************************************************************
144 * This routine should be called before any attemp to read an image. *
145 ******************************************************************************/
146 void DGifGetRecordType(GifFileType * GifFile, GifRecordType * Type)
149 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
151 if (!IS_READABLE(Private)) {
152 /* This file was NOT open for reading: */
153 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
156 GifRead(&Buf, 1, GifFile);
160 *Type = IMAGE_DESC_RECORD_TYPE;
163 *Type = EXTENSION_RECORD_TYPE;
166 *Type = TERMINATE_RECORD_TYPE;
169 *Type = UNDEFINED_RECORD_TYPE;
170 GifInternError(GifFile, D_GIF_ERR_WRONG_RECORD);
174 /******************************************************************************
175 * This routine should be called before any attemp to read an image. *
176 * Note it is assumed the Image desc. header (',') has been read. *
177 ******************************************************************************/
178 void DGifGetImageDesc(GifFileType * GifFile)
182 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
184 if (!IS_READABLE(Private)) {
185 /* This file was NOT open for reading: */
186 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
189 DGifGetWord(GifFile, &GifFile->Image.Left);
190 DGifGetWord(GifFile, &GifFile->Image.Top);
191 DGifGetWord(GifFile, &GifFile->Image.Width);
192 DGifGetWord(GifFile, &GifFile->Image.Height);
194 GifRead(Buf, 1, GifFile);
195 BitsPerPixel = (Buf[0] & 0x07) + 1;
196 GifFile->Image.Interlace = (Buf[0] & 0x40);
197 if (Buf[0] & 0x80) { /* Does this image have local color map? */
199 if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL)
200 FreeMapObject(GifFile->Image.ColorMap);
202 GifFile->Image.ColorMap =
203 MakeMapObject(1 << BitsPerPixel, NULL);
205 /* Get the image local color map: */
206 for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
207 GifRead(Buf, 3, GifFile);
208 GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
209 GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
210 GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
214 if (GifFile->SavedImages) {
217 if ((GifFile->SavedImages =
218 (SavedImage *) realloc(GifFile->SavedImages,
220 (GifFile->ImageCount + 1))) ==
222 GifInternError(GifFile, D_GIF_ERR_NOT_ENOUGH_MEM);
225 sp = &GifFile->SavedImages[GifFile->ImageCount];
226 memcpy(&sp->ImageDesc, &GifFile->Image, sizeof(GifImageDesc));
227 if (GifFile->Image.ColorMap) {
228 sp->ImageDesc.ColorMap =
229 MakeMapObject(GifFile->Image.ColorMap->ColorCount,
230 GifFile->Image.ColorMap->Colors);
232 sp->RasterBits = NULL;
233 sp->ExtensionBlockCount = 0;
234 sp->ExtensionBlocks = (ExtensionBlock *) NULL;
237 GifFile->ImageCount++;
239 Private->PixelCount = (long)GifFile->Image.Width *
240 (long)GifFile->Image.Height;
242 DGifSetupDecompress(GifFile); /* Reset decompress algorithm parameters. */
245 /******************************************************************************
246 * Get one full scanned line (Line) of length LineLen from GIF file. *
247 ******************************************************************************/
248 void DGifGetLine(GifFileType * GifFile, GifPixelType * Line, int LineLen)
251 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
253 if (!IS_READABLE(Private)) {
254 /* This file was NOT open for reading: */
255 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
259 LineLen = GifFile->Image.Width;
261 #if defined(__GNUC__)
262 if ((Private->PixelCount -= LineLen) > 0xffff0000UL)
264 if ((Private->PixelCount -= LineLen) > 0xffff0000)
267 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
270 DGifDecompressLine(GifFile, Line, LineLen);
271 if (Private->PixelCount == 0) {
272 /* We probably would not be called any more, so lets clean */
273 /* everything before we return: need to flush out all rest of */
274 /* image until empty block (size 0) detected. We use GetCodeNext. */
276 DGifGetCodeNext(GifFile, &Dummy);
277 while (Dummy != NULL);
281 /******************************************************************************
282 * Put one pixel (Pixel) into GIF file. *
283 ******************************************************************************/
284 void DGifGetPixel(GifFileType * GifFile, GifPixelType Pixel)
287 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
289 if (!IS_READABLE(Private)) {
290 /* This file was NOT open for reading: */
291 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
293 #if defined(__GNUC__)
294 if (--Private->PixelCount > 0xffff0000UL)
296 if (--Private->PixelCount > 0xffff0000)
299 GifInternError(GifFile, D_GIF_ERR_DATA_TOO_BIG);
302 DGifDecompressLine(GifFile, &Pixel, 1);
303 if (Private->PixelCount == 0) {
304 /* We probably would not be called any more, so lets clean */
305 /* everything before we return: need to flush out all rest of */
306 /* image until empty block (size 0) detected. We use GetCodeNext. */
308 DGifGetCodeNext(GifFile, &Dummy);
309 while (Dummy != NULL);
313 /******************************************************************************
314 * Get an extension block (see GIF manual) from gif file. This routine only *
315 * returns the first data block, and DGifGetExtensionNext shouldbe called *
316 * after this one until NULL extension is returned. *
317 * The Extension should NOT be freed by the user (not dynamically allocated).*
318 * Note it is assumed the Extension desc. header ('!') has been read. *
319 ******************************************************************************/
320 void DGifGetExtension(GifFileType * GifFile, int *ExtCode,
321 GifByteType ** Extension)
324 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
326 if (!IS_READABLE(Private)) {
327 /* This file was NOT open for reading: */
328 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
331 GifRead(&Buf, 1, GifFile);
334 DGifGetExtensionNext(GifFile, Extension);
337 /******************************************************************************
338 * Get a following extension block (see GIF manual) from gif file. This *
339 * routine sould be called until NULL Extension is returned. *
340 * The Extension should NOT be freed by the user (not dynamically allocated).*
341 ******************************************************************************/
342 void DGifGetExtensionNext(GifFileType * GifFile, GifByteType ** Extension)
345 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
347 GifRead(&Buf, 1, GifFile);
349 *Extension = Private->Buf; /* Use private unused buffer. */
350 (*Extension)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
351 GifRead(&((*Extension)[1]), Buf, GifFile);
356 /******************************************************************************
357 * This routine should be called second to last, to close the GIF file. *
358 ******************************************************************************/
359 int DGifCloseFile(GifFileType * GifFile)
361 GifFilePrivateType *Private;
366 Private = (GifFilePrivateType *) GifFile->Private;
368 if (!IS_READABLE(Private)) {
369 /* This file was NOT open for reading: */
370 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
373 if (GifClose(GifFile)) {
374 GifInternError(GifFile, D_GIF_ERR_CLOSE_FAILED);
379 /******************************************************************************
380 * Get 2 bytes (word) from the given file: *
381 ******************************************************************************/
382 static void DGifGetWord(GifFileType * GifFile, int *Word)
386 GifRead(c, 2, GifFile);
388 *Word = (((unsigned int)c[1]) << 8) + c[0];
391 /******************************************************************************
392 * Get the image code in compressed form. his routine can be called if the *
393 * information needed to be piped out as is. Obviously this is much faster *
394 * than decoding and encoding again. This routine should be followed by calls *
395 * to DGifGetCodeNext, until NULL block is returned. *
396 * The block should NOT be freed by the user (not dynamically allocated). *
397 ******************************************************************************/
398 void DGifGetCode(GifFileType * GifFile, int *CodeSize, GifByteType ** CodeBlock)
400 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
402 if (!IS_READABLE(Private)) {
403 /* This file was NOT open for reading: */
404 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
407 *CodeSize = Private->BitsPerPixel;
409 DGifGetCodeNext(GifFile, CodeBlock);
412 /******************************************************************************
413 * Continue to get the image code in compressed form. This routine should be *
414 * called until NULL block is returned. *
415 * The block should NOT be freed by the user (not dynamically allocated). *
416 ******************************************************************************/
417 void DGifGetCodeNext(GifFileType * GifFile, GifByteType ** CodeBlock)
420 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
422 GifRead(&Buf, 1, GifFile);
425 *CodeBlock = Private->Buf; /* Use private unused buffer. */
426 (*CodeBlock)[0] = Buf; /* Pascal strings notation (pos. 0 is len.). */
427 GifRead(&((*CodeBlock)[1]), Buf, GifFile);
430 Private->Buf[0] = 0; /* Make sure the buffer is empty! */
431 Private->PixelCount = 0; /* And local info. indicate image read. */
436 /******************************************************************************
437 * Setup the LZ decompression for this image: *
438 ******************************************************************************/
439 static void DGifSetupDecompress(GifFileType * GifFile)
442 GifByteType CodeSize;
443 unsigned int *Prefix;
444 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
446 GifRead(&CodeSize, 1, GifFile); /* Read Code size from file. */
447 BitsPerPixel = CodeSize;
449 Private->Buf[0] = 0; /* Input Buffer empty. */
450 Private->BitsPerPixel = BitsPerPixel;
451 Private->ClearCode = (1 << BitsPerPixel);
452 Private->EOFCode = Private->ClearCode + 1;
453 Private->RunningCode = Private->EOFCode + 1;
454 Private->RunningBits = BitsPerPixel + 1; /* Number of bits per code. */
455 Private->MaxCode1 = 1 << Private->RunningBits; /* Max. code + 1. */
456 Private->StackPtr = 0; /* No pixels on the pixel stack. */
457 Private->LastCode = NO_SUCH_CODE;
458 Private->CrntShiftState = 0; /* No information in CrntShiftDWord. */
459 Private->CrntShiftDWord = 0;
461 Prefix = Private->Prefix;
462 for (i = 0; i <= LZ_MAX_CODE; i++)
463 Prefix[i] = NO_SUCH_CODE;
466 /******************************************************************************
467 * The LZ decompression routine: *
468 * This version decompress the given gif file into Line of length LineLen. *
469 * This routine can be called few times (one per scan line, for example), in *
470 * order the complete the whole image. *
471 ******************************************************************************/
472 static void DGifDecompressLine(GifFileType * GifFile, GifPixelType * Line,
476 0, j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
477 GifByteType *Stack, *Suffix;
478 unsigned int *Prefix;
479 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
481 StackPtr = Private->StackPtr;
482 Prefix = Private->Prefix;
483 Suffix = Private->Suffix;
484 Stack = Private->Stack;
485 EOFCode = Private->EOFCode;
486 ClearCode = Private->ClearCode;
487 LastCode = Private->LastCode;
491 /* Let pop the stack off before continueing to read the gif file: */
492 while (StackPtr != 0 && i < LineLen)
493 Line[i++] = Stack[--StackPtr];
496 while (i < LineLen) { /* Decode LineLen items. */
497 DGifDecompressInput(GifFile, &CrntCode);
499 if (CrntCode == EOFCode) {
500 /* Note however that usually we will not be here as we will stop */
501 /* decoding as soon as we got all the pixel, or EOF code will */
502 /* not be read at all, and DGifGetLine/Pixel clean everything. */
503 if (i != LineLen - 1 || Private->PixelCount != 0) {
504 GifInternError(GifFile, D_GIF_ERR_EOF_TOO_SOON);
507 } else if (CrntCode == ClearCode) {
508 /* We need to start over again: */
509 for (j = 0; j <= LZ_MAX_CODE; j++)
510 Prefix[j] = NO_SUCH_CODE;
511 Private->RunningCode = Private->EOFCode + 1;
512 Private->RunningBits = Private->BitsPerPixel + 1;
513 Private->MaxCode1 = 1 << Private->RunningBits;
514 LastCode = Private->LastCode = NO_SUCH_CODE;
516 /* Its regular code - if in pixel range simply add it to output */
517 /* stream, otherwise trace to codes linked list until the prefix */
518 /* is in pixel range: */
519 if (CrntCode < ClearCode) {
520 /* This is simple - its pixel scalar, so add it to output: */
521 Line[i++] = CrntCode;
523 /* Its a code to needed to be traced: trace the linked list */
524 /* until the prefix is a pixel, while pushing the suffix */
525 /* pixels on our stack. If we done, pop the stack in reverse */
526 /* (thats what stack is good for!) order to output. */
527 if (Prefix[CrntCode] == NO_SUCH_CODE) {
528 /* Only allowed if CrntCode is exactly the running code: */
529 /* In that case CrntCode = XXXCode, CrntCode or the */
530 /* prefix code is last code and the suffix char is */
531 /* exactly the prefix of last code! */
533 Private->RunningCode - 2) {
534 CrntPrefix = LastCode;
535 Suffix[Private->RunningCode -
536 2] = Stack[StackPtr++] =
537 DGifGetPrefixChar(Prefix,
541 GifInternError(GifFile,
542 D_GIF_ERR_IMAGE_DEFECT);
545 CrntPrefix = CrntCode;
547 /* Now (if image is O.K.) we should not get an NO_SUCH_CODE */
548 /* During the trace. As we might loop forever, in case of */
549 /* defective image, we count the number of loops we trace */
550 /* and stop if we got LZ_MAX_CODE. obviously we can not */
551 /* loop more than that. */
553 while (j++ <= LZ_MAX_CODE &&
554 CrntPrefix > ClearCode &&
555 CrntPrefix <= LZ_MAX_CODE) {
556 Stack[StackPtr++] = Suffix[CrntPrefix];
557 CrntPrefix = Prefix[CrntPrefix];
560 || CrntPrefix > LZ_MAX_CODE) {
561 GifInternError(GifFile,
562 D_GIF_ERR_IMAGE_DEFECT);
564 /* Push the last character on stack: */
565 Stack[StackPtr++] = CrntPrefix;
567 /* Now lets pop all the stack into output: */
568 while (StackPtr != 0 && i < LineLen)
569 Line[i++] = Stack[--StackPtr];
571 if (LastCode != NO_SUCH_CODE) {
572 Prefix[Private->RunningCode - 2] = LastCode;
574 if (CrntCode == Private->RunningCode - 2) {
575 /* Only allowed if CrntCode is exactly the running code: */
576 /* In that case CrntCode = XXXCode, CrntCode or the */
577 /* prefix code is last code and the suffix char is */
578 /* exactly the prefix of last code! */
579 Suffix[Private->RunningCode - 2] =
580 DGifGetPrefixChar(Prefix, LastCode,
583 Suffix[Private->RunningCode - 2] =
584 DGifGetPrefixChar(Prefix, CrntCode,
592 Private->LastCode = LastCode;
593 Private->StackPtr = StackPtr;
596 /******************************************************************************
597 * Routine to trace the Prefixes linked list until we get a prefix which is *
598 * not code, but a pixel value (less than ClearCode). Returns that pixel value.*
599 * If image is defective, we might loop here forever, so we limit the loops to *
600 * the maximum possible if image O.k. - LZ_MAX_CODE times. *
601 ******************************************************************************/
602 static int DGifGetPrefixChar(unsigned int *Prefix, int Code, int ClearCode)
606 while (Code > ClearCode && i++ <= LZ_MAX_CODE)
611 /******************************************************************************
612 * Interface for accessing the LZ codes directly. Set Code to the real code *
613 * (12bits), or to -1 if EOF code is returned. *
614 ******************************************************************************/
615 void DGifGetLZCodes(GifFileType * GifFile, int *Code)
617 GifByteType *CodeBlock;
618 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
620 if (!IS_READABLE(Private)) {
621 /* This file was NOT open for reading: */
622 GifInternError(GifFile, D_GIF_ERR_NOT_READABLE);
625 DGifDecompressInput(GifFile, Code);
627 if (*Code == Private->EOFCode) {
628 /* Skip rest of codes (hopefully only NULL terminating block): */
630 DGifGetCodeNext(GifFile, &CodeBlock);
631 while (CodeBlock != NULL);
634 } else if (*Code == Private->ClearCode) {
635 /* We need to start over again: */
636 Private->RunningCode = Private->EOFCode + 1;
637 Private->RunningBits = Private->BitsPerPixel + 1;
638 Private->MaxCode1 = 1 << Private->RunningBits;
642 /******************************************************************************
643 * The LZ decompression input routine: *
644 * This routine is responsable for the decompression of the bit stream from *
645 * 8 bits (bytes) packets, into the real codes. *
646 * Returns GIF_OK if read succesfully. *
647 ******************************************************************************/
648 static void DGifDecompressInput(GifFileType * GifFile, int *Code)
650 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
651 GifByteType NextByte;
652 static unsigned int CodeMasks[] = {
653 0x0000, 0x0001, 0x0003, 0x0007,
654 0x000f, 0x001f, 0x003f, 0x007f,
655 0x00ff, 0x01ff, 0x03ff, 0x07ff,
659 while (Private->CrntShiftState < Private->RunningBits) {
660 /* Needs to get more bytes from input stream for next code: */
661 DGifBufferedInput(GifFile, &NextByte);
662 Private->CrntShiftDWord |=
663 ((unsigned long)NextByte) << Private->CrntShiftState;
664 Private->CrntShiftState += 8;
666 *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
668 Private->CrntShiftDWord >>= Private->RunningBits;
669 Private->CrntShiftState -= Private->RunningBits;
671 /* If code cannt fit into RunningBits bits, must raise its size. Note */
672 /* however that codes above 4095 are used for special signaling. */
673 if (++Private->RunningCode > Private->MaxCode1 &&
674 Private->RunningBits < LZ_BITS) {
675 Private->MaxCode1 <<= 1;
676 Private->RunningBits++;
680 /******************************************************************************
681 * This routines read one gif data block at a time and buffers it internally *
682 * so that the decompression routine could access it. *
683 * The routine returns the next byte from its internal buffer (or read next *
684 * block in if buffer empty) *
685 ******************************************************************************/
686 static void DGifBufferedInput(GifFileType * GifFile, GifByteType * NextByte)
688 GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
689 GifByteType *Buf = Private->Buf;
692 /* Needs to read the next buffer - this one is empty: */
693 GifRead(Buf, 1, GifFile);
694 GifRead((Buf + 1), Buf[0], GifFile);
696 Buf[1] = 2; /* We use now the second place as last char read! */
699 *NextByte = Buf[Buf[1]++];
704 /******************************************************************************
705 * This routine reads an entire GIF into core, hanging all its state info off *
706 * the GifFileType pointer. Call DGifOpenFileName() or DGifOpenFileHandle() *
707 * first to initialize I/O. Its inverse is EGifSpew(). *
708 ******************************************************************************/
709 void DGifSlurp(GifFileType * GifFile)
712 GifRecordType RecordType;
714 GifByteType *ExtData;
716 /* Some versions of malloc dislike 0-length requests */
717 GifFile->SavedImages = (SavedImage *) malloc(sizeof(SavedImage));
718 memset(GifFile->SavedImages, 0, sizeof(SavedImage));
719 sp = &GifFile->SavedImages[0];
722 DGifGetRecordType(GifFile, &RecordType);
724 switch ((unsigned int)RecordType) {
725 case IMAGE_DESC_RECORD_TYPE:
726 DGifGetImageDesc(GifFile);
728 sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
729 ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
733 (GifPixelType *) malloc(ImageSize *
734 sizeof(GifPixelType));
736 DGifGetLine(GifFile, sp->RasterBits, ImageSize);
739 case EXTENSION_RECORD_TYPE:
740 DGifGetExtension(GifFile, &sp->Function, &ExtData);
742 while (ExtData != NULL) {
743 if (AddExtensionBlock
744 (sp, ExtData[0], ExtData + 1) == GIF_ERROR)
745 GifInternError(GifFile,
746 D_GIF_ERR_NOT_ENOUGH_MEM);
747 DGifGetExtensionNext(GifFile, &ExtData);
751 case TERMINATE_RECORD_TYPE:
754 default: /* Should be trapped by DGifGetRecordType */
757 } while (RecordType != TERMINATE_RECORD_TYPE);
760 /******************************************************************************
761 * Extension record functions *
762 ******************************************************************************/
764 void MakeExtension(SavedImage * New, int Function)
766 New->Function = Function;
768 * Someday we might have to deal with multiple extensions.
772 int AddExtensionBlock(SavedImage * New, int Len, GifByteType * data)
777 if (New->ExtensionBlocks == NULL)
778 New->ExtensionBlocks =
779 (ExtensionBlock *) malloc(sizeof(ExtensionBlock));
781 New->ExtensionBlocks =
782 (ExtensionBlock *) realloc(New->ExtensionBlocks,
783 sizeof(ExtensionBlock) *
784 (New->ExtensionBlockCount + 1));
786 if (New->ExtensionBlocks == NULL)
789 ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
791 size = Len * sizeof(GifByteType);
792 ep->Bytes = (GifByteType *) malloc(size);
793 memcpy(ep->Bytes, data, size);
797 void FreeExtension(SavedImage * Image)
801 for (ep = Image->ExtensionBlocks;
802 ep < Image->ExtensionBlocks + Image->ExtensionBlockCount; ep++)
803 (void)free((char *)ep->Bytes);
804 free((char *)Image->ExtensionBlocks);
805 Image->ExtensionBlocks = NULL;
808 /******************************************************************************
809 * Image block allocation functions *
810 ******************************************************************************/
811 SavedImage *MakeSavedImage(GifFileType * GifFile, SavedImage * CopyFrom)
813 * Append an image block to the SavedImages array
818 if (GifFile->SavedImages == NULL)
819 GifFile->SavedImages =
820 (SavedImage *) malloc(sizeof(SavedImage));
822 GifFile->SavedImages =
823 (SavedImage *) realloc(GifFile->SavedImages,
825 (GifFile->ImageCount + 1));
827 if (GifFile->SavedImages == NULL)
828 return ((SavedImage *) NULL);
830 sp = &GifFile->SavedImages[GifFile->ImageCount++];
831 memset((char *)sp, '\0', sizeof(SavedImage));
834 memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
837 * Make our own allocated copies of the heap fields in the
838 * copied record. This guards against potential aliasing
842 /* first, the local color map */
843 if (sp->ImageDesc.ColorMap)
844 sp->ImageDesc.ColorMap =
845 MakeMapObject(CopyFrom->ImageDesc.ColorMap->
847 CopyFrom->ImageDesc.ColorMap->
850 /* next, the raster */
852 (GifPixelType *) malloc(sizeof(GifPixelType)
854 CopyFrom->ImageDesc.Height *
855 CopyFrom->ImageDesc.Width);
856 memcpy(sp->RasterBits, CopyFrom->RasterBits,
858 * CopyFrom->ImageDesc.Height *
859 CopyFrom->ImageDesc.Width);
861 /* finally, the extension blocks */
862 if (sp->ExtensionBlocks) {
866 malloc(sizeof(ExtensionBlock)
867 * CopyFrom->ExtensionBlockCount);
868 memcpy(sp->ExtensionBlocks,
869 CopyFrom->ExtensionBlocks,
870 sizeof(ExtensionBlock)
871 * CopyFrom->ExtensionBlockCount);
874 * For the moment, the actual blocks can take their
875 * chances with free(). We'll fix this later.
884 void FreeSavedImages(GifFileType * GifFile)
888 for (sp = GifFile->SavedImages;
889 sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
890 if (sp->ImageDesc.ColorMap)
891 FreeMapObject(sp->ImageDesc.ColorMap);
894 free((char *)sp->RasterBits);
896 if (sp->ExtensionBlocks)
899 free((char *)GifFile->SavedImages);
902 /******************************************************************************
903 * Miscellaneous utility functions *
904 ******************************************************************************/
906 static int BitSize(int n)
907 /* return smallest bitfield size n will fit in */
911 for (i = 1; i <= 8; i++)
917 /******************************************************************************
918 * Color map object functions *
919 ******************************************************************************/
921 ColorMapObject *MakeMapObject(int ColorCount, GifColorType * ColorMap)
923 * Allocate a color map of given size; initialize with contents of
924 * ColorMap if that pointer is non-NULL.
927 ColorMapObject *Object;
929 if (ColorCount != (1 << BitSize(ColorCount)))
930 return ((ColorMapObject *) NULL);
932 Object = (ColorMapObject *) malloc(sizeof(ColorMapObject));
933 if (Object == (ColorMapObject *) NULL)
934 return ((ColorMapObject *) NULL);
937 (GifColorType *) calloc(ColorCount, sizeof(GifColorType));
938 if (Object->Colors == (GifColorType *) NULL) {
940 return ((ColorMapObject *) NULL);
943 Object->ColorCount = ColorCount;
944 Object->BitsPerPixel = BitSize(ColorCount);
947 memcpy((char *)Object->Colors,
948 (char *)ColorMap, ColorCount * sizeof(GifColorType));
953 void FreeMapObject(ColorMapObject * Object)
955 * Free a color map object
958 free(Object->Colors);