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