1 /******************************************************************************
2  *   "Gif-Lib" - Yet another gif library.
3  *
4  * Written by:  Gershon Elber                Ver 1.1, Aug. 1990
5  ******************************************************************************
6  * The kernel of the GIF Encoding process can be found here.
7  ******************************************************************************
8  * History:
9  * 14 Jun 89 - Version 1.0 by Gershon Elber.
10  *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names).
11  * 26 Jun 96 - Version 3.0 by Eric S. Raymond (Full GIF89 support)
12  *****************************************************************************/
13 
14 #if defined(__sun__) && __STDC_VERSION__ >= 201112L && _XOPEN_SOURCE < 600
15 #ifdef _XOPEN_SOURCE
16 #undef _XOPEN_SOURCE
17 #endif
18 #define _XOPEN_SOURCE 600
19 #endif
20 
21 #if defined(_MSC_VER) || defined(__MSDOS__)
22 #  include <io.h>
23 #  include <sys\stat.h>
24 #  ifndef _MSC_VER
25 #    include <alloc.h>
26 #  endif
27 #else
28 #  include <sys/types.h>
29 #  include <sys/stat.h>
30 #  ifdef R6000
31 #    include <sys/mode.h>
32 #  endif
33 #endif /* _MSC_VER || __MSDOS__ */
34 
35 #if defined(unix) || defined(__unix__) || defined(__sun__) || defined(__APPLE__)
36 #include <unistd.h>
37 #endif
38 
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include "gif_lib.h"
44 #include "gif_lib_private.h"
45 
46 #if !defined(S_IREAD) && defined(S_IRUSR)
47 #  define S_IREAD  S_IRUSR
48 #  define S_IWRITE S_IRUSR
49 #endif
50 
51 /* #define DEBUG_NO_PREFIX                  Dump only compressed data. */
52 
53 /* Masks given codes to BitsPerPixel, to make sure all codes are in range: */
54 static GifPixelType CodeMask[] = {
55     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
56 };
57 
58 static char GifVersionPrefix[GIF_STAMP_LEN + 1] = GIF87_STAMP;
59 
60 #define WRITE(_gif,_buf,_len)   \
61   (((GifFilePrivateType*)_gif->Private)->Write ?    \
62    ((GifFilePrivateType*)_gif->Private)->Write(_gif,_buf,(int)(_len)) :    \
63    fwrite(_buf, 1, _len, ((GifFilePrivateType*)_gif->Private)->File))
64 
65 static int EGifPutWord(int Word, GifFileType * GifFile);
66 static int EGifSetupCompress(GifFileType * GifFile);
67 static int EGifCompressLine(GifFileType * GifFile, GifPixelType * Line,
68                             int LineLen);
69 static int EGifCompressOutput(GifFileType * GifFile, int Code);
70 static int EGifBufferedOutput(GifFileType * GifFile, GifByteType * Buf,
71                               int c);
72 
73 /******************************************************************************
74  * Open a new gif file for write, given by its name. If TestExistence then
75  * if the file exists this routines fails (returns NULL).
76  * Returns GifFileType pointer dynamically allocated which serves as the gif
77  * info record. _GifError is cleared if successfully.
78  *****************************************************************************/
79 GifFileType *
EGifOpenFileName(const char * FileName,int TestExistence)80 EGifOpenFileName(const char *FileName,
81                  int TestExistence) {
82 
83     int FileHandle;
84     GifFileType *GifFile;
85 
86     if (TestExistence)
87         FileHandle = open(FileName, O_WRONLY | O_CREAT | O_EXCL
88 #if defined(O_BINARY)
89                           | O_BINARY
90 #endif /* __MSDOS__ */
91                           , S_IREAD | S_IWRITE);
92     else
93         FileHandle = open(FileName, O_WRONLY | O_CREAT | O_TRUNC
94 #if defined(O_BINARY)
95                           | O_BINARY
96 #endif /* __MSDOS__ */
97                           , S_IREAD | S_IWRITE);
98 
99     if (FileHandle == -1) {
100         _GifError = E_GIF_ERR_OPEN_FAILED;
101         return NULL;
102     }
103     GifFile = EGifOpenFileHandle(FileHandle);
104     if (GifFile == (GifFileType *) NULL)
105         close(FileHandle);
106     return GifFile;
107 }
108 
109 /******************************************************************************
110  * Update a new gif file, given its file handle, which must be opened for
111  * write in binary mode.
112  * Returns GifFileType pointer dynamically allocated which serves as the gif
113  * info record. _GifError is cleared if successfully.
114  *****************************************************************************/
115 GifFileType *
EGifOpenFileHandle(int FileHandle)116 EGifOpenFileHandle(int FileHandle) {
117 
118     GifFileType *GifFile;
119     GifFilePrivateType *Private;
120     FILE *f;
121 
122     GifFile = (GifFileType *) malloc(sizeof(GifFileType));
123     if (GifFile == NULL) {
124         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
125         return NULL;
126     }
127 
128     memset(GifFile, '\0', sizeof(GifFileType));
129 
130     Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
131     if (Private == NULL) {
132         free(GifFile);
133         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
134         return NULL;
135     }
136     if ((Private->HashTable = _InitHashTable()) == NULL) {
137         free(GifFile);
138         free(Private);
139         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
140         return NULL;
141     }
142 
143 #if defined(O_BINARY)
144     setmode(FileHandle, O_BINARY);    /* Make sure it is in binary mode. */
145 #endif /* __MSDOS__ */
146 
147     f = fdopen(FileHandle, "wb");    /* Make it into a stream: */
148 
149 #if defined (__MSDOS__) || defined(WIN32)
150     setvbuf(f, NULL, _IOFBF, GIF_FILE_BUFFER_SIZE);    /* And inc. stream
151                                                         * buffer. */
152 #endif /* __MSDOS__ */
153 
154     GifFile->Private = (VoidPtr)Private;
155     Private->FileHandle = FileHandle;
156     Private->File = f;
157     Private->FileState = FILE_STATE_WRITE;
158 
159     Private->Write = (OutputFunc) 0;    /* No user write routine (MRB) */
160     GifFile->UserData = (VoidPtr) 0;    /* No user write handle (MRB) */
161 
162     _GifError = 0;
163 
164     return GifFile;
165 }
166 
167 /******************************************************************************
168  * Output constructor that takes user supplied output function.
169  * Basically just a copy of EGifOpenFileHandle. (MRB)
170  *****************************************************************************/
171 GifFileType *
EGifOpen(void * userData,OutputFunc writeFunc)172 EGifOpen(void *userData,
173          OutputFunc writeFunc) {
174 
175     GifFileType *GifFile;
176     GifFilePrivateType *Private;
177 
178     GifFile = (GifFileType *)malloc(sizeof(GifFileType));
179     if (GifFile == NULL) {
180         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
181         return NULL;
182     }
183 
184     memset(GifFile, '\0', sizeof(GifFileType));
185 
186     Private = (GifFilePrivateType *)malloc(sizeof(GifFilePrivateType));
187     if (Private == NULL) {
188         free(GifFile);
189         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
190         return NULL;
191     }
192 
193     Private->HashTable = _InitHashTable();
194     if (Private->HashTable == NULL) {
195         free (GifFile);
196         free (Private);
197         _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
198         return NULL;
199     }
200 
201     GifFile->Private = (VoidPtr) Private;
202     Private->FileHandle = 0;
203     Private->File = (FILE *) 0;
204     Private->FileState = FILE_STATE_WRITE;
205 
206     Private->Write = writeFunc;    /* User write routine (MRB) */
207     GifFile->UserData = userData;    /* User write handle (MRB) */
208 
209     _GifError = 0;
210 
211     return GifFile;
212 }
213 
214 /******************************************************************************
215  * Routine to set current GIF version. All files open for write will be
216  * using this version until next call to this routine. Version consists of
217  * 3 characters as "87a" or "89a". No test is made to validate the version.
218  *****************************************************************************/
219 void
EGifSetGifVersion(const char * Version)220 EGifSetGifVersion(const char *Version) {
221     strncpy(GifVersionPrefix + GIF_VERSION_POS, Version, 3);
222 }
223 
224 /******************************************************************************
225  * This routine should be called before any other EGif calls, immediately
226  * follows the GIF file opening.
227  *****************************************************************************/
228 int
EGifPutScreenDesc(GifFileType * GifFile,int Width,int Height,int ColorRes,int BackGround,const ColorMapObject * ColorMap)229 EGifPutScreenDesc(GifFileType * GifFile,
230                   int Width,
231                   int Height,
232                   int ColorRes,
233                   int BackGround,
234                   const ColorMapObject * ColorMap) {
235 
236     int i;
237     GifByteType Buf[3];
238     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
239 
240     if (Private->FileState & FILE_STATE_SCREEN) {
241         /* If already has screen descriptor - something is wrong! */
242         _GifError = E_GIF_ERR_HAS_SCRN_DSCR;
243         return GIF_ERROR;
244     }
245     if (!IS_WRITEABLE(Private)) {
246         /* This file was NOT open for writing: */
247         _GifError = E_GIF_ERR_NOT_WRITEABLE;
248         return GIF_ERROR;
249     }
250 
251 /* First write the version prefix into the file. */
252 #ifndef DEBUG_NO_PREFIX
253     if (WRITE(GifFile, (unsigned char *)GifVersionPrefix,
254               (int)strlen(GifVersionPrefix)) != strlen(GifVersionPrefix)) {
255         _GifError = E_GIF_ERR_WRITE_FAILED;
256         return GIF_ERROR;
257     }
258 #endif /* DEBUG_NO_PREFIX */
259 
260     GifFile->SWidth = Width;
261     GifFile->SHeight = Height;
262     GifFile->SColorResolution = ColorRes;
263     GifFile->SBackGroundColor = BackGround;
264     if (ColorMap) {
265         GifFile->SColorMap = MakeMapObject(ColorMap->ColorCount,
266                                            ColorMap->Colors);
267         if (GifFile->SColorMap == NULL) {
268             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
269             return GIF_ERROR;
270         }
271     } else
272         GifFile->SColorMap = NULL;
273 
274     /*
275      * Put the logical screen descriptor into the file:
276      */
277     /* Logical Screen Descriptor: Dimensions */
278     EGifPutWord(Width, GifFile);
279     EGifPutWord(Height, GifFile);
280 
281     /* Logical Screen Descriptor: Packed Fields */
282     /* Note: We have actual size of the color table default to the largest
283      * possible size (7+1 == 8 bits) because the decoder can use it to decide
284      * how to display the files.
285      */
286     Buf[0] = (ColorMap ? 0x80 : 0x00) | /* Yes/no global colormap */
287              ((ColorRes - 1) << 4) | /* Bits allocated to each primary color */
288         (ColorMap ? ColorMap->BitsPerPixel - 1 : 0x07 ); /* Actual size of the
289                                                             color table. */
290     Buf[1] = BackGround;    /* Index into the ColorTable for background color */
291     Buf[2] = 0;             /* Pixel Aspect Ratio */
292 #ifndef DEBUG_NO_PREFIX
293     WRITE(GifFile, Buf, 3);
294 #endif /* DEBUG_NO_PREFIX */
295 
296     /* If we have Global color map - dump it also: */
297 #ifndef DEBUG_NO_PREFIX
298     if (ColorMap != NULL)
299         for (i = 0; i < ColorMap->ColorCount; i++) {
300             /* Put the ColorMap out also: */
301             Buf[0] = ColorMap->Colors[i].Red;
302             Buf[1] = ColorMap->Colors[i].Green;
303             Buf[2] = ColorMap->Colors[i].Blue;
304             if (WRITE(GifFile, Buf, 3) != 3) {
305                 _GifError = E_GIF_ERR_WRITE_FAILED;
306                 return GIF_ERROR;
307             }
308         }
309 #endif /* DEBUG_NO_PREFIX */
310 
311     /* Mark this file as has screen descriptor, and no pixel written yet: */
312     Private->FileState |= FILE_STATE_SCREEN;
313 
314     return GIF_OK;
315 }
316 
317 /******************************************************************************
318  * This routine should be called before any attempt to dump an image - any
319  * call to any of the pixel dump routines.
320  *****************************************************************************/
321 int
EGifPutImageDesc(GifFileType * GifFile,int Left,int Top,int Width,int Height,int Interlace,const ColorMapObject * ColorMap)322 EGifPutImageDesc(GifFileType * GifFile,
323                  int Left,
324                  int Top,
325                  int Width,
326                  int Height,
327                  int Interlace,
328                  const ColorMapObject * ColorMap) {
329 
330     int i;
331     GifByteType Buf[3];
332     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
333 
334     if (Private->FileState & FILE_STATE_IMAGE &&
335 #if defined(__MSDOS__) || defined(WIN32) || defined(__GNUC__)
336         Private->PixelCount > 0xffff0000UL) {
337 #else
338         Private->PixelCount > 0xffff0000) {
339 #endif /* __MSDOS__ */
340         /* If already has active image descriptor - something is wrong! */
341         _GifError = E_GIF_ERR_HAS_IMAG_DSCR;
342         return GIF_ERROR;
343     }
344     if (!IS_WRITEABLE(Private)) {
345         /* This file was NOT open for writing: */
346         _GifError = E_GIF_ERR_NOT_WRITEABLE;
347         return GIF_ERROR;
348     }
349     GifFile->Image.Left = Left;
350     GifFile->Image.Top = Top;
351     GifFile->Image.Width = Width;
352     GifFile->Image.Height = Height;
353     GifFile->Image.Interlace = Interlace;
354     if (ColorMap) {
355         GifFile->Image.ColorMap = MakeMapObject(ColorMap->ColorCount,
356                                                 ColorMap->Colors);
357         if (GifFile->Image.ColorMap == NULL) {
358             _GifError = E_GIF_ERR_NOT_ENOUGH_MEM;
359             return GIF_ERROR;
360         }
361     } else {
362         GifFile->Image.ColorMap = NULL;
363     }
364 
365     /* Put the image descriptor into the file: */
366     Buf[0] = ',';    /* Image separator character. */
367 #ifndef DEBUG_NO_PREFIX
368     WRITE(GifFile, Buf, 1);
369 #endif /* DEBUG_NO_PREFIX */
370     EGifPutWord(Left, GifFile);
371     EGifPutWord(Top, GifFile);
372     EGifPutWord(Width, GifFile);
373     EGifPutWord(Height, GifFile);
374     Buf[0] = (ColorMap ? 0x80 : 0x00) |
375        (Interlace ? 0x40 : 0x00) |
376        (ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
377 #ifndef DEBUG_NO_PREFIX
378     WRITE(GifFile, Buf, 1);
379 #endif /* DEBUG_NO_PREFIX */
380 
381     /* If we have Global color map - dump it also: */
382 #ifndef DEBUG_NO_PREFIX
383     if (ColorMap != NULL)
384         for (i = 0; i < ColorMap->ColorCount; i++) {
385             /* Put the ColorMap out also: */
386             Buf[0] = ColorMap->Colors[i].Red;
387             Buf[1] = ColorMap->Colors[i].Green;
388             Buf[2] = ColorMap->Colors[i].Blue;
389             if (WRITE(GifFile, Buf, 3) != 3) {
390                 _GifError = E_GIF_ERR_WRITE_FAILED;
391                 return GIF_ERROR;
392             }
393         }
394 #endif /* DEBUG_NO_PREFIX */
395     if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL) {
396         _GifError = E_GIF_ERR_NO_COLOR_MAP;
397         return GIF_ERROR;
398     }
399 
400     /* Mark this file as has screen descriptor: */
401     Private->FileState |= FILE_STATE_IMAGE;
402     Private->PixelCount = (long)Width *(long)Height;
403 
404     EGifSetupCompress(GifFile);    /* Reset compress algorithm parameters. */
405 
406     return GIF_OK;
407 }
408 
409 /******************************************************************************
410  * Put one full scanned line (Line) of length LineLen into GIF file.
411  *****************************************************************************/
412 int
413 EGifPutLine(GifFileType * GifFile,
414             GifPixelType * Line,
415             int LineLen) {
416 
417     int i;
418     GifPixelType Mask;
419     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
420 
421     if (!IS_WRITEABLE(Private)) {
422         /* This file was NOT open for writing: */
423         _GifError = E_GIF_ERR_NOT_WRITEABLE;
424         return GIF_ERROR;
425     }
426 
427     if (!LineLen)
428         LineLen = GifFile->Image.Width;
429     if (Private->PixelCount < (unsigned)LineLen) {
430         _GifError = E_GIF_ERR_DATA_TOO_BIG;
431         return GIF_ERROR;
432     }
433     Private->PixelCount -= LineLen;
434 
435     /* Make sure the codes are not out of bit range, as we might generate
436      * wrong code (because of overflow when we combine them) in this case: */
437     Mask = CodeMask[Private->BitsPerPixel];
438     for (i = 0; i < LineLen; i++)
439         Line[i] &= Mask;
440 
441     return EGifCompressLine(GifFile, Line, LineLen);
442 }
443 
444 /******************************************************************************
445  * Put one pixel (Pixel) into GIF file.
446  *****************************************************************************/
447 int
448 EGifPutPixel(GifFileType * GifFile,
449              GifPixelType Pixel) {
450 
451     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
452 
453     if (!IS_WRITEABLE(Private)) {
454         /* This file was NOT open for writing: */
455         _GifError = E_GIF_ERR_NOT_WRITEABLE;
456         return GIF_ERROR;
457     }
458 
459     if (Private->PixelCount == 0) {
460         _GifError = E_GIF_ERR_DATA_TOO_BIG;
461         return GIF_ERROR;
462     }
463     --Private->PixelCount;
464 
465     /* Make sure the code is not out of bit range, as we might generate
466      * wrong code (because of overflow when we combine them) in this case: */
467     Pixel &= CodeMask[Private->BitsPerPixel];
468 
469     return EGifCompressLine(GifFile, &Pixel, 1);
470 }
471 
472 /******************************************************************************
473  * Put a comment into GIF file using the GIF89 comment extension block.
474  *****************************************************************************/
475 int
476 EGifPutComment(GifFileType * GifFile,
477                const char *Comment) {
478 
479     unsigned int length;
480     char *buf;
481 
482     length = (unsigned int)strlen(Comment);
483     if (length <= 255) {
484         return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
485                                 length, Comment);
486     } else {
487         buf = (char *)Comment;
488         if (EGifPutExtensionFirst(GifFile, COMMENT_EXT_FUNC_CODE, 255, buf)
489                 == GIF_ERROR) {
490             return GIF_ERROR;
491         }
492         length -= 255;
493         buf = buf + 255;
494 
495         /* Break the comment into 255 byte sub blocks */
496         while (length > 255) {
497             if (EGifPutExtensionNext(GifFile, 0, 255, buf) == GIF_ERROR) {
498                 return GIF_ERROR;
499             }
500             buf = buf + 255;
501             length -= 255;
502         }
503         /* Output any partial block and the clear code. */
504         if (EGifPutExtensionLast(GifFile, 0, length, buf) == GIF_ERROR) {
505             return GIF_ERROR;
506         }
507     }
508     return GIF_OK;
509 }
510 
511 /******************************************************************************
512  * Put a first extension block (see GIF manual) into gif file.  Here more
513  * extensions can be dumped using EGifPutExtensionNext until
514  * EGifPutExtensionLast is invoked.
515  *****************************************************************************/
516 int
517 EGifPutExtensionFirst(GifFileType * GifFile,
518                       int ExtCode,
519                       int ExtLen,
520                       const VoidPtr Extension) {
521 
522     GifByteType Buf[3];
523     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
524 
525     if (!IS_WRITEABLE(Private)) {
526         /* This file was NOT open for writing: */
527         _GifError = E_GIF_ERR_NOT_WRITEABLE;
528         return GIF_ERROR;
529     }
530 
531     if (ExtCode == 0) {
532         WRITE(GifFile, (GifByteType *)&ExtLen, 1);
533     } else {
534         Buf[0] = '!';
535         Buf[1] = ExtCode;
536         Buf[2] = ExtLen;
537         WRITE(GifFile, Buf, 3);
538     }
539 
540     WRITE(GifFile, Extension, ExtLen);
541 
542     return GIF_OK;
543 }
544 
545 /******************************************************************************
546  * Put a middle extension block (see GIF manual) into gif file.
547  *****************************************************************************/
548 int
549 EGifPutExtensionNext(GifFileType * GifFile,
550                      int ExtCode,
551                      int ExtLen,
552                      const VoidPtr Extension) {
553 
554     GifByteType Buf;
555     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
556 
557     if (!IS_WRITEABLE(Private)) {
558         /* This file was NOT open for writing: */
559         _GifError = E_GIF_ERR_NOT_WRITEABLE;
560         return GIF_ERROR;
561     }
562 
563     Buf = ExtLen;
564     WRITE(GifFile, &Buf, 1);
565     WRITE(GifFile, Extension, ExtLen);
566 
567     return GIF_OK;
568 }
569 
570 /******************************************************************************
571  * Put a last extension block (see GIF manual) into gif file.
572  *****************************************************************************/
573 int
574 EGifPutExtensionLast(GifFileType * GifFile,
575                      int ExtCode,
576                      int ExtLen,
577                      const VoidPtr Extension) {
578 
579     GifByteType Buf;
580     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
581 
582     if (!IS_WRITEABLE(Private)) {
583         /* This file was NOT open for writing: */
584         _GifError = E_GIF_ERR_NOT_WRITEABLE;
585         return GIF_ERROR;
586     }
587 
588     /* If we are given an extension sub-block output it now. */
589     if (ExtLen > 0) {
590         Buf = ExtLen;
591         WRITE(GifFile, &Buf, 1);
592         WRITE(GifFile, Extension, ExtLen);
593     }
594 
595     /* Write the block terminator */
596     Buf = 0;
597     WRITE(GifFile, &Buf, 1);
598 
599     return GIF_OK;
600 }
601 
602 /******************************************************************************
603  * Put an extension block (see GIF manual) into gif file.
604  * Warning: This function is only useful for Extension blocks that have at
605  * most one subblock.  Extensions with more than one subblock need to use the
606  * EGifPutExtension{First,Next,Last} functions instead.
607  *****************************************************************************/
608 int
609 EGifPutExtension(GifFileType * GifFile,
610                  int ExtCode,
611                  int ExtLen,
612                  const VoidPtr Extension) {
613 
614     GifByteType Buf[3];
615     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
616 
617     if (!IS_WRITEABLE(Private)) {
618         /* This file was NOT open for writing: */
619         _GifError = E_GIF_ERR_NOT_WRITEABLE;
620         return GIF_ERROR;
621     }
622 
623     if (ExtCode == 0)
624         WRITE(GifFile, (GifByteType *)&ExtLen, 1);
625     else {
626         Buf[0] = '!';       /* Extension Introducer 0x21 */
627         Buf[1] = ExtCode;   /* Extension Label */
628         Buf[2] = ExtLen;    /* Extension length */
629         WRITE(GifFile, Buf, 3);
630     }
631     WRITE(GifFile, Extension, ExtLen);
632     Buf[0] = 0;
633     WRITE(GifFile, Buf, 1);
634 
635     return GIF_OK;
636 }
637 
638 /******************************************************************************
639  * Put the image code in compressed form. This routine can be called if the
640  * information needed to be piped out as is. Obviously this is much faster
641  * than decoding and encoding again. This routine should be followed by calls
642  * to EGifPutCodeNext, until NULL block is given.
643  * The block should NOT be freed by the user (not dynamically allocated).
644  *****************************************************************************/
645 int
646 EGifPutCode(GifFileType * GifFile,
647             int CodeSize,
648             const GifByteType * CodeBlock) {
649 
650     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
651 
652     if (!IS_WRITEABLE(Private)) {
653         /* This file was NOT open for writing: */
654         _GifError = E_GIF_ERR_NOT_WRITEABLE;
655         return GIF_ERROR;
656     }
657 
658     /* No need to dump code size as Compression set up does any for us: */
659     /*
660      * Buf = CodeSize;
661      * if (WRITE(GifFile, &Buf, 1) != 1) {
662      *      _GifError = E_GIF_ERR_WRITE_FAILED;
663      *      return GIF_ERROR;
664      * }
665      */
666 
667     return EGifPutCodeNext(GifFile, CodeBlock);
668 }
669 
670 /******************************************************************************
671  * Continue to put the image code in compressed form. This routine should be
672  * called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If
673  * given buffer pointer is NULL, empty block is written to mark end of code.
674  *****************************************************************************/
675 int
676 EGifPutCodeNext(GifFileType * GifFile,
677                 const GifByteType * CodeBlock) {
678 
679     GifByteType Buf;
680     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
681 
682     if (CodeBlock != NULL) {
683         if (WRITE(GifFile, CodeBlock, CodeBlock[0] + 1)
684                != (unsigned)(CodeBlock[0] + 1)) {
685             _GifError = E_GIF_ERR_WRITE_FAILED;
686             return GIF_ERROR;
687         }
688     } else {
689         Buf = 0;
690         if (WRITE(GifFile, &Buf, 1) != 1) {
691             _GifError = E_GIF_ERR_WRITE_FAILED;
692             return GIF_ERROR;
693         }
694         Private->PixelCount = 0;    /* And local info. indicate image read. */
695     }
696 
697     return GIF_OK;
698 }
699 
700 /******************************************************************************
701  * This routine should be called last, to close GIF file.
702  *****************************************************************************/
703 int
704 EGifCloseFile(GifFileType * GifFile) {
705 
706     GifByteType Buf;
707     GifFilePrivateType *Private;
708     FILE *File;
709 
710     if (GifFile == NULL || GifFile->Private == NULL)
711         return GIF_ERROR;
712 
713     Private = (GifFilePrivateType *) GifFile->Private;
714     if (!IS_WRITEABLE(Private)) {
715         /* This file was NOT open for writing: */
716         _GifError = E_GIF_ERR_NOT_WRITEABLE;
717         free(GifFile);
718         return GIF_ERROR;
719     }
720 
721     File = Private->File;
722 
723     Buf = ';';
724     WRITE(GifFile, &Buf, 1);
725 
726     if (GifFile->Image.ColorMap) {
727         FreeMapObject(GifFile->Image.ColorMap);
728         GifFile->Image.ColorMap = NULL;
729     }
730     if (GifFile->SColorMap) {
731         FreeMapObject(GifFile->SColorMap);
732         GifFile->SColorMap = NULL;
733     }
734 
735     if (Private->HashTable) {
736         free((char *) Private->HashTable);
737     }
738 
739     if (File && fclose(File) != 0) {
740         _GifError = E_GIF_ERR_CLOSE_FAILED;
741         free((char *) Private);
742         free(GifFile);
743         return GIF_ERROR;
744     }
745 
746     free((char *) Private);
747     free(GifFile);
748 
749     return GIF_OK;
750 }
751 
752 /******************************************************************************
753  * Put 2 bytes (word) into the given file:
754  *****************************************************************************/
755 static int
756 EGifPutWord(int Word,
757             GifFileType * GifFile) {
758 
759     unsigned char c[2];
760 
761     c[0] = Word & 0xff;
762     c[1] = (Word >> 8) & 0xff;
763 #ifndef DEBUG_NO_PREFIX
764     if (WRITE(GifFile, c, 2) == 2)
765         return GIF_OK;
766     else
767         return GIF_ERROR;
768 #else
769     return GIF_OK;
770 #endif /* DEBUG_NO_PREFIX */
771 }
772 
773 /******************************************************************************
774  * Setup the LZ compression for this image:
775  *****************************************************************************/
776 static int
777 EGifSetupCompress(GifFileType * GifFile) {
778 
779     int BitsPerPixel;
780     GifByteType Buf;
781     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
782 
783     /* Test and see what color map to use, and from it # bits per pixel: */
784     if (GifFile->Image.ColorMap)
785         BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
786     else if (GifFile->SColorMap)
787         BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
788     else {
789         _GifError = E_GIF_ERR_NO_COLOR_MAP;
790         return GIF_ERROR;
791     }
792 
793     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
794     WRITE(GifFile, &Buf, 1);    /* Write the Code size to file. */
795 
796     Private->Buf[0] = 0;    /* Nothing was output yet. */
797     Private->BitsPerPixel = BitsPerPixel;
798     Private->ClearCode = (1 << BitsPerPixel);
799     Private->EOFCode = Private->ClearCode + 1;
800     Private->RunningCode = Private->EOFCode + 1;
801     Private->RunningBits = BitsPerPixel + 1;    /* Number of bits per code. */
802     Private->MaxCode1 = 1 << Private->RunningBits;    /* Max. code + 1. */
803     Private->CrntCode = FIRST_CODE;    /* Signal that this is first one! */
804     Private->CrntShiftState = 0;    /* No information in CrntShiftDWord. */
805     Private->CrntShiftDWord = 0;
806 
807    /* Clear hash table and send Clear to make sure the decoder do the same. */
808     _ClearHashTable(Private->HashTable);
809 
810     if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) {
811         _GifError = E_GIF_ERR_DISK_IS_FULL;
812         return GIF_ERROR;
813     }
814     return GIF_OK;
815 }
816 
817 /******************************************************************************
818  * The LZ compression routine:
819  * This version compresses the given buffer Line of length LineLen.
820  * This routine can be called a few times (one per scan line, for example), in
821  * order to complete the whole image.
822 ******************************************************************************/
823 static int
824 EGifCompressLine(GifFileType * GifFile,
825                  GifPixelType * Line,
826                  int LineLen) {
827 
828     int i = 0, CrntCode, NewCode;
829     unsigned long NewKey;
830     GifPixelType Pixel;
831     GifHashTableType *HashTable;
832     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
833 
834     HashTable = Private->HashTable;
835 
836     if (Private->CrntCode == FIRST_CODE)    /* Its first time! */
837         CrntCode = Line[i++];
838     else
839         CrntCode = Private->CrntCode;    /* Get last code in compression. */
840 
841     while (i < LineLen) {   /* Decode LineLen items. */
842         Pixel = Line[i++];  /* Get next pixel from stream. */
843         /* Form a new unique key to search hash table for the code combines
844          * CrntCode as Prefix string with Pixel as postfix char.
845          */
846         NewKey = (((UINT32) CrntCode) << 8) + Pixel;
847         if ((NewCode = _ExistsHashTable(HashTable, (UINT32)NewKey)) >= 0) {
848             /* This Key is already there, or the string is old one, so
849              * simple take new code as our CrntCode:
850              */
851             CrntCode = NewCode;
852         } else {
853             /* Put it in hash table, output the prefix code, and make our
854              * CrntCode equal to Pixel.
855              */
856             if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
857                 _GifError = E_GIF_ERR_DISK_IS_FULL;
858                 return GIF_ERROR;
859             }
860             CrntCode = Pixel;
861 
862             /* If however the HashTable if full, we send a clear first and
863              * Clear the hash table.
864              */
865             if (Private->RunningCode >= LZ_MAX_CODE) {
866                 /* Time to do some clearance: */
867                 if (EGifCompressOutput(GifFile, Private->ClearCode)
868                         == GIF_ERROR) {
869                     _GifError = E_GIF_ERR_DISK_IS_FULL;
870                     return GIF_ERROR;
871                 }
872                 Private->RunningCode = Private->EOFCode + 1;
873                 Private->RunningBits = Private->BitsPerPixel + 1;
874                 Private->MaxCode1 = 1 << Private->RunningBits;
875                 _ClearHashTable(HashTable);
876             } else {
877                 /* Put this unique key with its relative Code in hash table: */
878                 _InsertHashTable(HashTable, (UINT32)NewKey, Private->RunningCode++);
879             }
880         }
881 
882     }
883 
884     /* Preserve the current state of the compression algorithm: */
885     Private->CrntCode = CrntCode;
886 
887     if (Private->PixelCount == 0) {
888         /* We are done - output last Code and flush output buffers: */
889         if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
890             _GifError = E_GIF_ERR_DISK_IS_FULL;
891             return GIF_ERROR;
892         }
893         if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
894             _GifError = E_GIF_ERR_DISK_IS_FULL;
895             return GIF_ERROR;
896         }
897         if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
898             _GifError = E_GIF_ERR_DISK_IS_FULL;
899             return GIF_ERROR;
900         }
901     }
902 
903     return GIF_OK;
904 }
905 
906 /******************************************************************************
907  * The LZ compression output routine:
908  * This routine is responsible for the compression of the bit stream into
909  * 8 bits (bytes) packets.
910  * Returns GIF_OK if written successfully.
911  *****************************************************************************/
912 static int
913 EGifCompressOutput(GifFileType * GifFile,
914                    int Code) {
915 
916     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
917     int retval = GIF_OK;
918 
919     if (Code == FLUSH_OUTPUT) {
920         while (Private->CrntShiftState > 0) {
921             /* Get Rid of what is left in DWord, and flush it. */
922             if (EGifBufferedOutput(GifFile, Private->Buf,
923                                  Private->CrntShiftDWord & 0xff) == GIF_ERROR)
924                 retval = GIF_ERROR;
925             Private->CrntShiftDWord >>= 8;
926             Private->CrntShiftState -= 8;
927         }
928         Private->CrntShiftState = 0;    /* For next time. */
929         if (EGifBufferedOutput(GifFile, Private->Buf,
930                                FLUSH_OUTPUT) == GIF_ERROR)
931             retval = GIF_ERROR;
932     } else {
933         Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState;
934         Private->CrntShiftState += Private->RunningBits;
935         while (Private->CrntShiftState >= 8) {
936             /* Dump out full bytes: */
937             if (EGifBufferedOutput(GifFile, Private->Buf,
938                                  Private->CrntShiftDWord & 0xff) == GIF_ERROR)
939                 retval = GIF_ERROR;
940             Private->CrntShiftDWord >>= 8;
941             Private->CrntShiftState -= 8;
942         }
943     }
944 
945     /* If code cannot fit into RunningBits bits, must raise its size. Note */
946     /* however that codes above 4095 are used for special signaling.      */
947     if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
948        Private->MaxCode1 = 1 << ++Private->RunningBits;
949     }
950 
951     return retval;
952 }
953 
954 /******************************************************************************
955  * This routines buffers the given characters until 255 characters are ready
956  * to be output. If Code is equal to -1 the buffer is flushed (EOF).
957  * The buffer is Dumped with first byte as its size, as GIF format requires.
958  * Returns GIF_OK if written successfully.
959  *****************************************************************************/
960 static int
961 EGifBufferedOutput(GifFileType * GifFile,
962                    GifByteType * Buf,
963                    int c) {
964 
965     if (c == FLUSH_OUTPUT) {
966         /* Flush everything out. */
967         if (Buf[0] != 0
968             && WRITE(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
969             _GifError = E_GIF_ERR_WRITE_FAILED;
970             return GIF_ERROR;
971         }
972         /* Mark end of compressed data, by an empty block (see GIF doc): */
973         Buf[0] = 0;
974         if (WRITE(GifFile, Buf, 1) != 1) {
975             _GifError = E_GIF_ERR_WRITE_FAILED;
976             return GIF_ERROR;
977         }
978     } else {
979         if (Buf[0] == 255) {
980             /* Dump out this buffer - it is full: */
981             if (WRITE(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
982                 _GifError = E_GIF_ERR_WRITE_FAILED;
983                 return GIF_ERROR;
984             }
985             Buf[0] = 0;
986         }
987         Buf[++Buf[0]] = c;
988     }
989 
990     return GIF_OK;
991 }
992 
993 /******************************************************************************
994  * This routine writes to disk an in-core representation of a GIF previously
995  * created by DGifSlurp().
996  *****************************************************************************/
997 int
998 EGifSpew(GifFileType * GifFileOut) {
999 
1000     int i, j, gif89 = FALSE;
1001     int bOff;   /* Block Offset for adding sub blocks in Extensions */
1002     char SavedStamp[GIF_STAMP_LEN + 1];
1003 
1004     for (i = 0; i < GifFileOut->ImageCount; i++) {
1005         for (j = 0; j < GifFileOut->SavedImages[i].ExtensionBlockCount; j++) {
1006             int function =
1007                GifFileOut->SavedImages[i].ExtensionBlocks[j].Function;
1008 
1009             if (function == COMMENT_EXT_FUNC_CODE
1010                 || function == GRAPHICS_EXT_FUNC_CODE
1011                 || function == PLAINTEXT_EXT_FUNC_CODE
1012                 || function == APPLICATION_EXT_FUNC_CODE)
1013                 gif89 = TRUE;
1014         }
1015     }
1016 
1017     memcpy(SavedStamp, GifVersionPrefix, GIF_STAMP_LEN);
1018     if (gif89) {
1019         memcpy(GifVersionPrefix, GIF89_STAMP, GIF_STAMP_LEN);
1020     } else {
1021         memcpy(GifVersionPrefix, GIF87_STAMP, GIF_STAMP_LEN);
1022     }
1023     if (EGifPutScreenDesc(GifFileOut,
1024                           GifFileOut->SWidth,
1025                           GifFileOut->SHeight,
1026                           GifFileOut->SColorResolution,
1027                           GifFileOut->SBackGroundColor,
1028                           GifFileOut->SColorMap) == GIF_ERROR) {
1029         memcpy(GifVersionPrefix, SavedStamp, GIF_STAMP_LEN);
1030         return (GIF_ERROR);
1031     }
1032     memcpy(GifVersionPrefix, SavedStamp, GIF_STAMP_LEN);
1033 
1034     for (i = 0; i < GifFileOut->ImageCount; i++) {
1035         SavedImage *sp = &GifFileOut->SavedImages[i];
1036         int SavedHeight = sp->ImageDesc.Height;
1037         int SavedWidth = sp->ImageDesc.Width;
1038         ExtensionBlock *ep;
1039 
1040         /* this allows us to delete images by nuking their rasters */
1041         if (sp->RasterBits == NULL)
1042             continue;
1043 
1044         if (sp->ExtensionBlocks) {
1045             for (j = 0; j < sp->ExtensionBlockCount; j++) {
1046                 ep = &sp->ExtensionBlocks[j];
1047                 if (j == sp->ExtensionBlockCount - 1 || (ep+1)->Function != 0) {
1048                     /*** FIXME: Must check whether outputting
1049                      * <ExtLen><Extension> is ever valid or if we should just
1050                      * drop anything with a 0 for the Function.  (And whether
1051                      * we should drop here or in EGifPutExtension)
1052                      */
1053                     if (EGifPutExtension(GifFileOut,
1054                                          (ep->Function != 0) ? ep->Function : '\0',
1055                                          ep->ByteCount,
1056                                          ep->Bytes) == GIF_ERROR) {
1057                         return (GIF_ERROR);
1058                     }
1059                 } else {
1060                     EGifPutExtensionFirst(GifFileOut, ep->Function, ep->ByteCount, ep->Bytes);
1061                     for (bOff = j+1; bOff < sp->ExtensionBlockCount; bOff++) {
1062                         ep = &sp->ExtensionBlocks[bOff];
1063                         if (ep->Function != 0) {
1064                             break;
1065                         }
1066                         EGifPutExtensionNext(GifFileOut, 0,
1067                                 ep->ByteCount, ep->Bytes);
1068                     }
1069                     EGifPutExtensionLast(GifFileOut, 0, 0, NULL);
1070                     j = bOff-1;
1071                 }
1072             }
1073         }
1074 
1075         if (EGifPutImageDesc(GifFileOut,
1076                              sp->ImageDesc.Left,
1077                              sp->ImageDesc.Top,
1078                              SavedWidth,
1079                              SavedHeight,
1080                              sp->ImageDesc.Interlace,
1081                              sp->ImageDesc.ColorMap) == GIF_ERROR)
1082             return (GIF_ERROR);
1083 
1084         for (j = 0; j < SavedHeight; j++) {
1085             if (EGifPutLine(GifFileOut,
1086                             sp->RasterBits + j * SavedWidth,
1087                             SavedWidth) == GIF_ERROR)
1088                 return (GIF_ERROR);
1089         }
1090     }
1091 
1092     if (EGifCloseFile(GifFileOut) == GIF_ERROR)
1093         return (GIF_ERROR);
1094 
1095     return (GIF_OK);
1096 }
1097