Home | History | Annotate | Download | only in giflib
      1 /******************************************************************************
      2 
      3 egif_lib.c - GIF encoding
      4 
      5 The functions here and in dgif_lib.c are partitioned carefully so that
      6 if you only require one of read and write capability, only one of these
      7 two 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@*/
     30 static const GifPixelType CodeMask[] = {
     31     0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
     32 };
     33 /*@-charint@*/
     34 
     35 static int EGifPutWord(int Word, GifFileType * GifFile);
     36 static int EGifSetupCompress(GifFileType * GifFile);
     37 static int EGifCompressLine(GifFileType * GifFile, GifPixelType * Line,
     38                             int LineLen);
     39 static int EGifCompressOutput(GifFileType * GifFile, int Code);
     40 static 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 ******************************************************************************/
     53 GifFileType *
     54 EGifOpenFileName(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 ******************************************************************************/
     87 GifFileType *
     88 EGifOpenFileHandle(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 ******************************************************************************/
    139 GifFileType *
    140 EGifOpen(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 ******************************************************************************/
    189 char *
    190 EGifGetGifVersion(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 ******************************************************************************/
    236 void 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 ******************************************************************************/
    246 static 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 ******************************************************************************/
    260 int
    261 EGifPutScreenDesc(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 ******************************************************************************/
    353 int
    354 EGifPutImageDesc(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 ******************************************************************************/
    436 int
    437 EGifPutLine(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 ******************************************************************************/
    469 int
    470 EGifPutPixel(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 ******************************************************************************/
    496 int
    497 EGifPutComment(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 ******************************************************************************/
    539 int
    540 EGifPutExtensionLeader(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 ******************************************************************************/
    561 int
    562 EGifPutExtensionBlock(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 ******************************************************************************/
    585 int
    586 EGifPutExtensionTrailer(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 ******************************************************************************/
    610 int
    611 EGifPutExtension(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 
    644 size_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 
    661 int 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 ******************************************************************************/
    697 int
    698 EGifPutCode(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 ******************************************************************************/
    725 int
    726 EGifPutCodeNext(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 ******************************************************************************/
    752 int
    753 EGifCloseFile(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 ******************************************************************************/
    810 static int
    811 EGifPutWord(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 ******************************************************************************/
    826 static int
    827 EGifSetupCompress(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 ******************************************************************************/
    873 static int
    874 EGifCompressLine(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 ******************************************************************************/
    962 static int
    963 EGifCompressOutput(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 ******************************************************************************/
   1010 static int
   1011 EGifBufferedOutput(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 
   1048 static int
   1049 EGifWriteExtensions(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 
   1073 int
   1074 EGifSpew(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