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 const 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     const 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 	if (GifFile->Image.ColorMap != NULL) {
    383 	    GifFreeMapObject(GifFile->Image.ColorMap);
    384 	    GifFile->Image.ColorMap = NULL;
    385 	}
    386         GifFile->Image.ColorMap = GifMakeMapObject(ColorMap->ColorCount,
    387                                                 ColorMap->Colors);
    388         if (GifFile->Image.ColorMap == NULL) {
    389             GifFile->Error = E_GIF_ERR_NOT_ENOUGH_MEM;
    390             return GIF_ERROR;
    391         }
    392     } else {
    393         GifFile->Image.ColorMap = NULL;
    394     }
    395 
    396     /* Put the image descriptor into the file: */
    397     Buf[0] = DESCRIPTOR_INTRODUCER;    /* Image separator character. */
    398     InternalWrite(GifFile, Buf, 1);
    399     (void)EGifPutWord(Left, GifFile);
    400     (void)EGifPutWord(Top, GifFile);
    401     (void)EGifPutWord(Width, GifFile);
    402     (void)EGifPutWord(Height, GifFile);
    403     Buf[0] = (ColorMap ? 0x80 : 0x00) |
    404        (Interlace ? 0x40 : 0x00) |
    405        (ColorMap ? ColorMap->BitsPerPixel - 1 : 0);
    406     InternalWrite(GifFile, Buf, 1);
    407 
    408     /* If we have Global color map - dump it also: */
    409     if (ColorMap != NULL) {
    410 	int i;
    411         for (i = 0; i < ColorMap->ColorCount; i++) {
    412             /* Put the ColorMap out also: */
    413             Buf[0] = ColorMap->Colors[i].Red;
    414             Buf[1] = ColorMap->Colors[i].Green;
    415             Buf[2] = ColorMap->Colors[i].Blue;
    416             if (InternalWrite(GifFile, Buf, 3) != 3) {
    417                 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
    418                 return GIF_ERROR;
    419             }
    420         }
    421     }
    422     if (GifFile->SColorMap == NULL && GifFile->Image.ColorMap == NULL) {
    423         GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
    424         return GIF_ERROR;
    425     }
    426 
    427     /* Mark this file as has screen descriptor: */
    428     Private->FileState |= FILE_STATE_IMAGE;
    429     Private->PixelCount = (long)Width *(long)Height;
    430 
    431     /* Reset compress algorithm parameters. */
    432     (void)EGifSetupCompress(GifFile);
    433 
    434     return GIF_OK;
    435 }
    436 
    437 /******************************************************************************
    438  Put one full scanned line (Line) of length LineLen into GIF file.
    439 ******************************************************************************/
    440 int
    441 EGifPutLine(GifFileType * GifFile, GifPixelType *Line, int LineLen)
    442 {
    443     int i;
    444     GifPixelType Mask;
    445     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
    446 
    447     if (!IS_WRITEABLE(Private)) {
    448         /* This file was NOT open for writing: */
    449         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    450         return GIF_ERROR;
    451     }
    452 
    453     if (!LineLen)
    454         LineLen = GifFile->Image.Width;
    455     if (Private->PixelCount < (unsigned)LineLen) {
    456         GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
    457         return GIF_ERROR;
    458     }
    459     Private->PixelCount -= LineLen;
    460 
    461     /* Make sure the codes are not out of bit range, as we might generate
    462      * wrong code (because of overflow when we combine them) in this case: */
    463     Mask = CodeMask[Private->BitsPerPixel];
    464     for (i = 0; i < LineLen; i++)
    465         Line[i] &= Mask;
    466 
    467     return EGifCompressLine(GifFile, Line, LineLen);
    468 }
    469 
    470 /******************************************************************************
    471  Put one pixel (Pixel) into GIF file.
    472 ******************************************************************************/
    473 int
    474 EGifPutPixel(GifFileType *GifFile, GifPixelType Pixel)
    475 {
    476     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    477 
    478     if (!IS_WRITEABLE(Private)) {
    479         /* This file was NOT open for writing: */
    480         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    481         return GIF_ERROR;
    482     }
    483 
    484     if (Private->PixelCount == 0) {
    485         GifFile->Error = E_GIF_ERR_DATA_TOO_BIG;
    486         return GIF_ERROR;
    487     }
    488     --Private->PixelCount;
    489 
    490     /* Make sure the code is not out of bit range, as we might generate
    491      * wrong code (because of overflow when we combine them) in this case: */
    492     Pixel &= CodeMask[Private->BitsPerPixel];
    493 
    494     return EGifCompressLine(GifFile, &Pixel, 1);
    495 }
    496 
    497 /******************************************************************************
    498  Put a comment into GIF file using the GIF89 comment extension block.
    499 ******************************************************************************/
    500 int
    501 EGifPutComment(GifFileType *GifFile, const char *Comment)
    502 {
    503     unsigned int length;
    504     char *buf;
    505 
    506     length = strlen(Comment);
    507     if (length <= 255) {
    508         return EGifPutExtension(GifFile, COMMENT_EXT_FUNC_CODE,
    509                                 length, Comment);
    510     } else {
    511         buf = (char *)Comment;
    512         if (EGifPutExtensionLeader(GifFile, COMMENT_EXT_FUNC_CODE)
    513                 == GIF_ERROR) {
    514             return GIF_ERROR;
    515         }
    516 
    517         /* Break the comment into 255 byte sub blocks */
    518         while (length > 255) {
    519             if (EGifPutExtensionBlock(GifFile, 255, buf) == GIF_ERROR) {
    520                 return GIF_ERROR;
    521             }
    522             buf = buf + 255;
    523             length -= 255;
    524         }
    525         /* Output any partial block and the clear code. */
    526         if (length > 0) {
    527             if (EGifPutExtensionBlock(GifFile, length, buf) == GIF_ERROR) {
    528                 return GIF_ERROR;
    529             }
    530         }
    531 	if (EGifPutExtensionTrailer(GifFile) == GIF_ERROR) {
    532 	    return GIF_ERROR;
    533         }
    534     }
    535     return GIF_OK;
    536 }
    537 
    538 /******************************************************************************
    539  Begin an extension block (see GIF manual).  More
    540  extensions can be dumped using EGifPutExtensionBlock until
    541  EGifPutExtensionTrailer is invoked.
    542 ******************************************************************************/
    543 int
    544 EGifPutExtensionLeader(GifFileType *GifFile, const int ExtCode)
    545 {
    546     GifByteType Buf[3];
    547     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    548 
    549     if (!IS_WRITEABLE(Private)) {
    550         /* This file was NOT open for writing: */
    551         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    552         return GIF_ERROR;
    553     }
    554 
    555     Buf[0] = EXTENSION_INTRODUCER;
    556     Buf[1] = ExtCode;
    557     InternalWrite(GifFile, Buf, 2);
    558 
    559     return GIF_OK;
    560 }
    561 
    562 /******************************************************************************
    563  Put extension block data (see GIF manual) into a GIF file.
    564 ******************************************************************************/
    565 int
    566 EGifPutExtensionBlock(GifFileType *GifFile,
    567 		     const int ExtLen,
    568 		     const void *Extension)
    569 {
    570     GifByteType Buf;
    571     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    572 
    573     if (!IS_WRITEABLE(Private)) {
    574         /* This file was NOT open for writing: */
    575         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    576         return GIF_ERROR;
    577     }
    578 
    579     Buf = ExtLen;
    580     InternalWrite(GifFile, &Buf, 1);
    581     InternalWrite(GifFile, Extension, ExtLen);
    582 
    583     return GIF_OK;
    584 }
    585 
    586 /******************************************************************************
    587  Put a terminating block (see GIF manual) into a GIF file.
    588 ******************************************************************************/
    589 int
    590 EGifPutExtensionTrailer(GifFileType *GifFile) {
    591 
    592     GifByteType Buf;
    593     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    594 
    595     if (!IS_WRITEABLE(Private)) {
    596         /* This file was NOT open for writing: */
    597         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    598         return GIF_ERROR;
    599     }
    600 
    601     /* Write the block terminator */
    602     Buf = 0;
    603     InternalWrite(GifFile, &Buf, 1);
    604 
    605     return GIF_OK;
    606 }
    607 
    608 /******************************************************************************
    609  Put an extension block (see GIF manual) into a GIF file.
    610  Warning: This function is only useful for Extension blocks that have at
    611  most one subblock.  Extensions with more than one subblock need to use the
    612  EGifPutExtension{Leader,Block,Trailer} functions instead.
    613 ******************************************************************************/
    614 int
    615 EGifPutExtension(GifFileType *GifFile,
    616                  const int ExtCode,
    617                  const int ExtLen,
    618                  const void *Extension) {
    619 
    620     GifByteType Buf[3];
    621     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    622 
    623     if (!IS_WRITEABLE(Private)) {
    624         /* This file was NOT open for writing: */
    625         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    626         return GIF_ERROR;
    627     }
    628 
    629     if (ExtCode == 0)
    630         InternalWrite(GifFile, (GifByteType *)&ExtLen, 1);
    631     else {
    632         Buf[0] = EXTENSION_INTRODUCER;
    633         Buf[1] = ExtCode;   /* Extension Label */
    634         Buf[2] = ExtLen;    /* Extension length */
    635         InternalWrite(GifFile, Buf, 3);
    636     }
    637     InternalWrite(GifFile, Extension, ExtLen);
    638     Buf[0] = 0;
    639     InternalWrite(GifFile, Buf, 1);
    640 
    641     return GIF_OK;
    642 }
    643 
    644 /******************************************************************************
    645  Render a Graphics Control Block as raw extension data
    646 ******************************************************************************/
    647 
    648 size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
    649 		       GifByteType *GifExtension)
    650 {
    651     GifExtension[0] = 0;
    652     GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ? 0x00 : 0x01;
    653     GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00;
    654     GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2);
    655     GifExtension[1] = LOBYTE(GCB->DelayTime);
    656     GifExtension[2] = HIBYTE(GCB->DelayTime);
    657     GifExtension[3] = (char)GCB->TransparentColor;
    658     return 4;
    659 }
    660 
    661 /******************************************************************************
    662  Replace the Graphics Control Block for a saved image, if it exists.
    663 ******************************************************************************/
    664 
    665 int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
    666 			    GifFileType *GifFile, int ImageIndex)
    667 {
    668     int i;
    669     size_t Len;
    670     GifByteType buf[sizeof(GraphicsControlBlock)]; /* a bit dodgy... */
    671 
    672     if (ImageIndex < 0 || ImageIndex > GifFile->ImageCount - 1)
    673 	return GIF_ERROR;
    674 
    675     for (i = 0; i < GifFile->SavedImages[ImageIndex].ExtensionBlockCount; i++) {
    676 	ExtensionBlock *ep = &GifFile->SavedImages[ImageIndex].ExtensionBlocks[i];
    677 	if (ep->Function == GRAPHICS_EXT_FUNC_CODE) {
    678 	    EGifGCBToExtension(GCB, ep->Bytes);
    679 	    return GIF_OK;
    680 	}
    681     }
    682 
    683     Len = EGifGCBToExtension(GCB, (GifByteType *)buf);
    684     if (GifAddExtensionBlock(&GifFile->SavedImages[ImageIndex].ExtensionBlockCount,
    685 			     &GifFile->SavedImages[ImageIndex].ExtensionBlocks,
    686 			     GRAPHICS_EXT_FUNC_CODE,
    687 			     Len,
    688 			     (unsigned char *)buf) == GIF_ERROR)
    689 	return (GIF_ERROR);
    690 
    691     return (GIF_OK);
    692 }
    693 
    694 /******************************************************************************
    695  Put the image code in compressed form. This routine can be called if the
    696  information needed to be piped out as is. Obviously this is much faster
    697  than decoding and encoding again. This routine should be followed by calls
    698  to EGifPutCodeNext, until NULL block is given.
    699  The block should NOT be freed by the user (not dynamically allocated).
    700 ******************************************************************************/
    701 int
    702 EGifPutCode(GifFileType *GifFile, int CodeSize, const GifByteType *CodeBlock)
    703 {
    704     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    705 
    706     if (!IS_WRITEABLE(Private)) {
    707         /* This file was NOT open for writing: */
    708         GifFile->Error = E_GIF_ERR_NOT_WRITEABLE;
    709         return GIF_ERROR;
    710     }
    711 
    712     /* No need to dump code size as Compression set up does any for us: */
    713     /*
    714      * Buf = CodeSize;
    715      * if (InternalWrite(GifFile, &Buf, 1) != 1) {
    716      *      GifFile->Error = E_GIF_ERR_WRITE_FAILED;
    717      *      return GIF_ERROR;
    718      * }
    719      */
    720 
    721     return EGifPutCodeNext(GifFile, CodeBlock);
    722 }
    723 
    724 /******************************************************************************
    725  Continue to put the image code in compressed form. This routine should be
    726  called with blocks of code as read via DGifGetCode/DGifGetCodeNext. If
    727  given buffer pointer is NULL, empty block is written to mark end of code.
    728 ******************************************************************************/
    729 int
    730 EGifPutCodeNext(GifFileType *GifFile, const GifByteType *CodeBlock)
    731 {
    732     GifByteType Buf;
    733     GifFilePrivateType *Private = (GifFilePrivateType *)GifFile->Private;
    734 
    735     if (CodeBlock != NULL) {
    736         if (InternalWrite(GifFile, CodeBlock, CodeBlock[0] + 1)
    737                != (unsigned)(CodeBlock[0] + 1)) {
    738             GifFile->Error = E_GIF_ERR_WRITE_FAILED;
    739             return GIF_ERROR;
    740         }
    741     } else {
    742         Buf = 0;
    743         if (InternalWrite(GifFile, &Buf, 1) != 1) {
    744             GifFile->Error = E_GIF_ERR_WRITE_FAILED;
    745             return GIF_ERROR;
    746         }
    747         Private->PixelCount = 0;    /* And local info. indicate image read. */
    748     }
    749 
    750     return GIF_OK;
    751 }
    752 
    753 /******************************************************************************
    754  This routine should be called last, to close the GIF file.
    755 ******************************************************************************/
    756 int
    757 EGifCloseFile(GifFileType *GifFile, int *ErrorCode)
    758 {
    759     GifByteType Buf;
    760     GifFilePrivateType *Private;
    761     FILE *File;
    762 
    763     if (GifFile == NULL)
    764         return GIF_ERROR;
    765 
    766     Private = (GifFilePrivateType *) GifFile->Private;
    767     if (Private == NULL)
    768 	return GIF_ERROR;
    769     if (!IS_WRITEABLE(Private)) {
    770         /* This file was NOT open for writing: */
    771 	if (ErrorCode != NULL)
    772 	    *ErrorCode = E_GIF_ERR_NOT_WRITEABLE;
    773 	free(GifFile);
    774         return GIF_ERROR;
    775     }
    776 
    777     File = Private->File;
    778 
    779     Buf = TERMINATOR_INTRODUCER;
    780     InternalWrite(GifFile, &Buf, 1);
    781 
    782     if (GifFile->Image.ColorMap) {
    783         GifFreeMapObject(GifFile->Image.ColorMap);
    784         GifFile->Image.ColorMap = NULL;
    785     }
    786     if (GifFile->SColorMap) {
    787         GifFreeMapObject(GifFile->SColorMap);
    788         GifFile->SColorMap = NULL;
    789     }
    790     if (Private) {
    791         if (Private->HashTable) {
    792             free((char *) Private->HashTable);
    793         }
    794 	free((char *) Private);
    795     }
    796 
    797     if (File && fclose(File) != 0) {
    798 	if (ErrorCode != NULL)
    799 	    *ErrorCode = E_GIF_ERR_CLOSE_FAILED;
    800 	free(GifFile);
    801         return GIF_ERROR;
    802     }
    803 
    804     free(GifFile);
    805     if (ErrorCode != NULL)
    806 	*ErrorCode = E_GIF_SUCCEEDED;
    807     return GIF_OK;
    808 }
    809 
    810 /******************************************************************************
    811  Put 2 bytes (a word) into the given file in little-endian order:
    812 ******************************************************************************/
    813 static int
    814 EGifPutWord(int Word, GifFileType *GifFile)
    815 {
    816     unsigned char c[2];
    817 
    818     c[0] = LOBYTE(Word);
    819     c[1] = HIBYTE(Word);
    820     if (InternalWrite(GifFile, c, 2) == 2)
    821         return GIF_OK;
    822     else
    823         return GIF_ERROR;
    824 }
    825 
    826 /******************************************************************************
    827  Setup the LZ compression for this image:
    828 ******************************************************************************/
    829 static int
    830 EGifSetupCompress(GifFileType *GifFile)
    831 {
    832     int BitsPerPixel;
    833     GifByteType Buf;
    834     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
    835 
    836     /* Test and see what color map to use, and from it # bits per pixel: */
    837     if (GifFile->Image.ColorMap)
    838         BitsPerPixel = GifFile->Image.ColorMap->BitsPerPixel;
    839     else if (GifFile->SColorMap)
    840         BitsPerPixel = GifFile->SColorMap->BitsPerPixel;
    841     else {
    842         GifFile->Error = E_GIF_ERR_NO_COLOR_MAP;
    843         return GIF_ERROR;
    844     }
    845 
    846     Buf = BitsPerPixel = (BitsPerPixel < 2 ? 2 : BitsPerPixel);
    847     InternalWrite(GifFile, &Buf, 1);    /* Write the Code size to file. */
    848 
    849     Private->Buf[0] = 0;    /* Nothing was output yet. */
    850     Private->BitsPerPixel = BitsPerPixel;
    851     Private->ClearCode = (1 << BitsPerPixel);
    852     Private->EOFCode = Private->ClearCode + 1;
    853     Private->RunningCode = Private->EOFCode + 1;
    854     Private->RunningBits = BitsPerPixel + 1;    /* Number of bits per code. */
    855     Private->MaxCode1 = 1 << Private->RunningBits;    /* Max. code + 1. */
    856     Private->CrntCode = FIRST_CODE;    /* Signal that this is first one! */
    857     Private->CrntShiftState = 0;    /* No information in CrntShiftDWord. */
    858     Private->CrntShiftDWord = 0;
    859 
    860    /* Clear hash table and send Clear to make sure the decoder do the same. */
    861     _ClearHashTable(Private->HashTable);
    862 
    863     if (EGifCompressOutput(GifFile, Private->ClearCode) == GIF_ERROR) {
    864         GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    865         return GIF_ERROR;
    866     }
    867     return GIF_OK;
    868 }
    869 
    870 /******************************************************************************
    871  The LZ compression routine:
    872  This version compresses the given buffer Line of length LineLen.
    873  This routine can be called a few times (one per scan line, for example), in
    874  order to complete the whole image.
    875 ******************************************************************************/
    876 static int
    877 EGifCompressLine(GifFileType *GifFile,
    878                  GifPixelType *Line,
    879                  const int LineLen)
    880 {
    881     int i = 0, CrntCode, NewCode;
    882     unsigned long NewKey;
    883     GifPixelType Pixel;
    884     GifHashTableType *HashTable;
    885     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
    886 
    887     HashTable = Private->HashTable;
    888 
    889     if (Private->CrntCode == FIRST_CODE)    /* Its first time! */
    890         CrntCode = Line[i++];
    891     else
    892         CrntCode = Private->CrntCode;    /* Get last code in compression. */
    893 
    894     while (i < LineLen) {   /* Decode LineLen items. */
    895         Pixel = Line[i++];  /* Get next pixel from stream. */
    896         /* Form a new unique key to search hash table for the code combines
    897          * CrntCode as Prefix string with Pixel as postfix char.
    898          */
    899         NewKey = (((uint32_t) CrntCode) << 8) + Pixel;
    900         if ((NewCode = _ExistsHashTable(HashTable, NewKey)) >= 0) {
    901             /* This Key is already there, or the string is old one, so
    902              * simple take new code as our CrntCode:
    903              */
    904             CrntCode = NewCode;
    905         } else {
    906             /* Put it in hash table, output the prefix code, and make our
    907              * CrntCode equal to Pixel.
    908              */
    909             if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
    910                 GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    911                 return GIF_ERROR;
    912             }
    913             CrntCode = Pixel;
    914 
    915             /* If however the HashTable if full, we send a clear first and
    916              * Clear the hash table.
    917              */
    918             if (Private->RunningCode >= LZ_MAX_CODE) {
    919                 /* Time to do some clearance: */
    920                 if (EGifCompressOutput(GifFile, Private->ClearCode)
    921                         == GIF_ERROR) {
    922                     GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    923                     return GIF_ERROR;
    924                 }
    925                 Private->RunningCode = Private->EOFCode + 1;
    926                 Private->RunningBits = Private->BitsPerPixel + 1;
    927                 Private->MaxCode1 = 1 << Private->RunningBits;
    928                 _ClearHashTable(HashTable);
    929             } else {
    930                 /* Put this unique key with its relative Code in hash table: */
    931                 _InsertHashTable(HashTable, NewKey, Private->RunningCode++);
    932             }
    933         }
    934 
    935     }
    936 
    937     /* Preserve the current state of the compression algorithm: */
    938     Private->CrntCode = CrntCode;
    939 
    940     if (Private->PixelCount == 0) {
    941         /* We are done - output last Code and flush output buffers: */
    942         if (EGifCompressOutput(GifFile, CrntCode) == GIF_ERROR) {
    943             GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    944             return GIF_ERROR;
    945         }
    946         if (EGifCompressOutput(GifFile, Private->EOFCode) == GIF_ERROR) {
    947             GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    948             return GIF_ERROR;
    949         }
    950         if (EGifCompressOutput(GifFile, FLUSH_OUTPUT) == GIF_ERROR) {
    951             GifFile->Error = E_GIF_ERR_DISK_IS_FULL;
    952             return GIF_ERROR;
    953         }
    954     }
    955 
    956     return GIF_OK;
    957 }
    958 
    959 /******************************************************************************
    960  The LZ compression output routine:
    961  This routine is responsible for the compression of the bit stream into
    962  8 bits (bytes) packets.
    963  Returns GIF_OK if written successfully.
    964 ******************************************************************************/
    965 static int
    966 EGifCompressOutput(GifFileType *GifFile,
    967                    const int Code)
    968 {
    969     GifFilePrivateType *Private = (GifFilePrivateType *) GifFile->Private;
    970     int retval = GIF_OK;
    971 
    972     if (Code == FLUSH_OUTPUT) {
    973         while (Private->CrntShiftState > 0) {
    974             /* Get Rid of what is left in DWord, and flush it. */
    975             if (EGifBufferedOutput(GifFile, Private->Buf,
    976                                  Private->CrntShiftDWord & 0xff) == GIF_ERROR)
    977                 retval = GIF_ERROR;
    978             Private->CrntShiftDWord >>= 8;
    979             Private->CrntShiftState -= 8;
    980         }
    981         Private->CrntShiftState = 0;    /* For next time. */
    982         if (EGifBufferedOutput(GifFile, Private->Buf,
    983                                FLUSH_OUTPUT) == GIF_ERROR)
    984             retval = GIF_ERROR;
    985     } else {
    986         Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState;
    987         Private->CrntShiftState += Private->RunningBits;
    988         while (Private->CrntShiftState >= 8) {
    989             /* Dump out full bytes: */
    990             if (EGifBufferedOutput(GifFile, Private->Buf,
    991                                  Private->CrntShiftDWord & 0xff) == GIF_ERROR)
    992                 retval = GIF_ERROR;
    993             Private->CrntShiftDWord >>= 8;
    994             Private->CrntShiftState -= 8;
    995         }
    996     }
    997 
    998     /* If code cannt fit into RunningBits bits, must raise its size. Note */
    999     /* however that codes above 4095 are used for special signaling.      */
   1000     if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) {
   1001        Private->MaxCode1 = 1 << ++Private->RunningBits;
   1002     }
   1003 
   1004     return retval;
   1005 }
   1006 
   1007 /******************************************************************************
   1008  This routines buffers the given characters until 255 characters are ready
   1009  to be output. If Code is equal to -1 the buffer is flushed (EOF).
   1010  The buffer is Dumped with first byte as its size, as GIF format requires.
   1011  Returns GIF_OK if written successfully.
   1012 ******************************************************************************/
   1013 static int
   1014 EGifBufferedOutput(GifFileType *GifFile,
   1015                    GifByteType *Buf,
   1016                    int c)
   1017 {
   1018     if (c == FLUSH_OUTPUT) {
   1019         /* Flush everything out. */
   1020         if (Buf[0] != 0
   1021             && InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
   1022             GifFile->Error = E_GIF_ERR_WRITE_FAILED;
   1023             return GIF_ERROR;
   1024         }
   1025         /* Mark end of compressed data, by an empty block (see GIF doc): */
   1026         Buf[0] = 0;
   1027         if (InternalWrite(GifFile, Buf, 1) != 1) {
   1028             GifFile->Error = E_GIF_ERR_WRITE_FAILED;
   1029             return GIF_ERROR;
   1030         }
   1031     } else {
   1032         if (Buf[0] == 255) {
   1033             /* Dump out this buffer - it is full: */
   1034             if (InternalWrite(GifFile, Buf, Buf[0] + 1) != (unsigned)(Buf[0] + 1)) {
   1035                 GifFile->Error = E_GIF_ERR_WRITE_FAILED;
   1036                 return GIF_ERROR;
   1037             }
   1038             Buf[0] = 0;
   1039         }
   1040         Buf[++Buf[0]] = c;
   1041     }
   1042 
   1043     return GIF_OK;
   1044 }
   1045 
   1046 /******************************************************************************
   1047  This routine writes to disk an in-core representation of a GIF previously
   1048  created by DGifSlurp().
   1049 ******************************************************************************/
   1050 
   1051 static int
   1052 EGifWriteExtensions(GifFileType *GifFileOut,
   1053 			       ExtensionBlock *ExtensionBlocks,
   1054 			       int ExtensionBlockCount)
   1055 {
   1056     if (ExtensionBlocks) {
   1057         ExtensionBlock *ep;
   1058 	int j;
   1059 
   1060 	for (j = 0; j < ExtensionBlockCount; j++) {
   1061 	    ep = &ExtensionBlocks[j];
   1062 	    if (ep->Function != CONTINUE_EXT_FUNC_CODE)
   1063 		if (EGifPutExtensionLeader(GifFileOut, ep->Function) == GIF_ERROR)
   1064 		    return (GIF_ERROR);
   1065 	    if (EGifPutExtensionBlock(GifFileOut, ep->ByteCount, ep->Bytes) == GIF_ERROR)
   1066 		return (GIF_ERROR);
   1067 	    if (j == ExtensionBlockCount - 1 || (ep+1)->Function != CONTINUE_EXT_FUNC_CODE)
   1068 		if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
   1069 		    return (GIF_ERROR);
   1070 	}
   1071     }
   1072 
   1073     return (GIF_OK);
   1074 }
   1075 
   1076 int
   1077 EGifSpew(GifFileType *GifFileOut)
   1078 {
   1079     int i, j;
   1080 
   1081     if (EGifPutScreenDesc(GifFileOut,
   1082                           GifFileOut->SWidth,
   1083                           GifFileOut->SHeight,
   1084                           GifFileOut->SColorResolution,
   1085                           GifFileOut->SBackGroundColor,
   1086                           GifFileOut->SColorMap) == GIF_ERROR) {
   1087         return (GIF_ERROR);
   1088     }
   1089 
   1090     for (i = 0; i < GifFileOut->ImageCount; i++) {
   1091         SavedImage *sp = &GifFileOut->SavedImages[i];
   1092         int SavedHeight = sp->ImageDesc.Height;
   1093         int SavedWidth = sp->ImageDesc.Width;
   1094 
   1095         /* this allows us to delete images by nuking their rasters */
   1096         if (sp->RasterBits == NULL)
   1097             continue;
   1098 
   1099 	if (EGifWriteExtensions(GifFileOut,
   1100 				sp->ExtensionBlocks,
   1101 				sp->ExtensionBlockCount) == GIF_ERROR)
   1102 	    return (GIF_ERROR);
   1103 
   1104         if (EGifPutImageDesc(GifFileOut,
   1105                              sp->ImageDesc.Left,
   1106                              sp->ImageDesc.Top,
   1107                              SavedWidth,
   1108                              SavedHeight,
   1109                              sp->ImageDesc.Interlace,
   1110                              sp->ImageDesc.ColorMap) == GIF_ERROR)
   1111             return (GIF_ERROR);
   1112 
   1113 	if (sp->ImageDesc.Interlace) {
   1114 	     /*
   1115 	      * The way an interlaced image should be written -
   1116 	      * offsets and jumps...
   1117 	      */
   1118 	    int InterlacedOffset[] = { 0, 4, 2, 1 };
   1119 	    int InterlacedJumps[] = { 8, 8, 4, 2 };
   1120 	    int k;
   1121 	    /* Need to perform 4 passes on the images: */
   1122 	    for (k = 0; k < 4; k++)
   1123 		for (j = InterlacedOffset[k];
   1124 		     j < SavedHeight;
   1125 		     j += InterlacedJumps[k]) {
   1126 		    if (EGifPutLine(GifFileOut,
   1127 				    sp->RasterBits + j * SavedWidth,
   1128 				    SavedWidth)	== GIF_ERROR)
   1129 			return (GIF_ERROR);
   1130 		}
   1131 	} else {
   1132 	    for (j = 0; j < SavedHeight; j++) {
   1133 		if (EGifPutLine(GifFileOut,
   1134 				sp->RasterBits + j * SavedWidth,
   1135 				SavedWidth) == GIF_ERROR)
   1136 		    return (GIF_ERROR);
   1137 	    }
   1138 	}
   1139     }
   1140 
   1141     if (EGifWriteExtensions(GifFileOut,
   1142 			    GifFileOut->ExtensionBlocks,
   1143 			    GifFileOut->ExtensionBlockCount) == GIF_ERROR)
   1144 	return (GIF_ERROR);
   1145 
   1146     if (EGifCloseFile(GifFileOut, NULL) == GIF_ERROR)
   1147         return (GIF_ERROR);
   1148 
   1149     return (GIF_OK);
   1150 }
   1151 
   1152 /* end */
   1153