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