1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*****************************************************************************
  26 
  27  GIF construction tools
  28 
  29 ****************************************************************************/
  30 
  31 #include <stdlib.h>
  32 #include <stdio.h>
  33 #include <string.h>
  34 
  35 #include "gif_lib.h"
  36 #include "gif_lib_private.h"
  37 
  38 #define MAX(x, y)    (((x) > (y)) ? (x) : (y))
  39 
  40 /******************************************************************************
  41  Miscellaneous utility functions                          
  42 ******************************************************************************/
  43 
  44 /* return smallest bitfield size n will fit in */
  45 int
  46 GifBitSize(int n)
  47 {
  48     register int i;
  49 
  50     for (i = 1; i <= 8; i++)
  51         if ((1 << i) >= n)
  52             break;
  53     return (i);
  54 }
  55 
  56 /******************************************************************************
  57   Color map object functions                              
  58 ******************************************************************************/
  59 
  60 /*
  61  * Allocate a color map of given size; initialize with contents of
  62  * ColorMap if that pointer is non-NULL.
  63  */
  64 ColorMapObject *
  65 GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
  66 {
  67     ColorMapObject *Object;
  68 
  69     /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
  70      * make the user know that or should we automatically round up instead? */
  71     if (ColorCount != (1 << GifBitSize(ColorCount))) {
  72         return ((ColorMapObject *) NULL);
  73     }
  74     
  75     Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
  76     if (Object == (ColorMapObject *) NULL) {
  77         return ((ColorMapObject *) NULL);
  78     }
  79 
  80     Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
  81     if (Object->Colors == (GifColorType *) NULL) {
  82         free(Object);
  83         return ((ColorMapObject *) NULL);
  84     }
  85 
  86     Object->ColorCount = ColorCount;
  87     Object->BitsPerPixel = GifBitSize(ColorCount);
  88     Object->SortFlag = false;
  89 
  90     if (ColorMap != NULL) {
  91         memcpy((char *)Object->Colors,
  92                (char *)ColorMap, ColorCount * sizeof(GifColorType));
  93     }
  94 
  95     return (Object);
  96 }
  97 
  98 /*******************************************************************************
  99 Free a color map object
 100 *******************************************************************************/
 101 void
 102 GifFreeMapObject(ColorMapObject *Object)
 103 {
 104     if (Object != NULL) {
 105         (void)free(Object->Colors);
 106         (void)free(Object);
 107     }
 108 }
 109 
 110 #ifdef DEBUG
 111 void
 112 DumpColorMap(ColorMapObject *Object,
 113              FILE * fp)
 114 {
 115     if (Object != NULL) {
 116         int i, j, Len = Object->ColorCount;
 117 
 118         for (i = 0; i < Len; i += 4) {
 119             for (j = 0; j < 4 && j < Len; j++) {
 120                 (void)fprintf(fp, "%3d: %02x %02x %02x   ", i + j,
 121                               Object->Colors[i + j].Red,
 122                               Object->Colors[i + j].Green,
 123                               Object->Colors[i + j].Blue);
 124             }
 125             (void)fprintf(fp, "\n");
 126         }
 127     }
 128 }
 129 #endif /* DEBUG */
 130 
 131 /*******************************************************************************
 132  Compute the union of two given color maps and return it.  If result can't 
 133  fit into 256 colors, NULL is returned, the allocated union otherwise.
 134  ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
 135  copied iff they didn't exist before.  ColorTransIn2 maps the old
 136  ColorIn2 into the ColorUnion color map table./
 137 *******************************************************************************/
 138 ColorMapObject *
 139 GifUnionColorMap(const ColorMapObject *ColorIn1,
 140               const ColorMapObject *ColorIn2,
 141               GifPixelType ColorTransIn2[])
 142 {
 143     int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
 144     ColorMapObject *ColorUnion;
 145 
 146     /*
 147      * We don't worry about duplicates within either color map; if
 148      * the caller wants to resolve those, he can perform unions
 149      * with an empty color map.
 150      */
 151 
 152     /* Allocate table which will hold the result for sure. */
 153     ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
 154                                ColorIn2->ColorCount) * 2, NULL);
 155 
 156     if (ColorUnion == NULL)
 157         return (NULL);
 158 
 159     /* 
 160      * Copy ColorIn1 to ColorUnion.
 161      */
 162     for (i = 0; i < ColorIn1->ColorCount; i++)
 163         ColorUnion->Colors[i] = ColorIn1->Colors[i];
 164     CrntSlot = ColorIn1->ColorCount;
 165 
 166     /* 
 167      * Potentially obnoxious hack:
 168      *
 169      * Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
 170      * of table 1.  This is very useful if your display is limited to
 171      * 16 colors.
 172      */
 173     while (ColorIn1->Colors[CrntSlot - 1].Red == 0
 174            && ColorIn1->Colors[CrntSlot - 1].Green == 0
 175            && ColorIn1->Colors[CrntSlot - 1].Blue == 0)
 176         CrntSlot--;
 177 
 178     /* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
 179     for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
 180         /* Let's see if this color already exists: */
 181         for (j = 0; j < ColorIn1->ColorCount; j++)
 182             if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i], 
 183                         sizeof(GifColorType)) == 0)
 184                 break;
 185 
 186         if (j < ColorIn1->ColorCount)
 187             ColorTransIn2[i] = j;    /* color exists in Color1 */
 188         else {
 189             /* Color is new - copy it to a new slot: */
 190             ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
 191             ColorTransIn2[i] = CrntSlot++;
 192         }
 193     }
 194 
 195     if (CrntSlot > 256) {
 196         GifFreeMapObject(ColorUnion);
 197         return ((ColorMapObject *) NULL);
 198     }
 199 
 200     NewGifBitSize = GifBitSize(CrntSlot);
 201     RoundUpTo = (1 << NewGifBitSize);
 202 
 203     if (RoundUpTo != ColorUnion->ColorCount) {
 204         register GifColorType *Map = ColorUnion->Colors;
 205 
 206         /* 
 207          * Zero out slots up to next power of 2.
 208          * We know these slots exist because of the way ColorUnion's
 209          * start dimension was computed.
 210          */
 211         for (j = CrntSlot; j < RoundUpTo; j++)
 212             Map[j].Red = Map[j].Green = Map[j].Blue = 0;
 213 
 214         /* perhaps we can shrink the map? */
 215         if (RoundUpTo < ColorUnion->ColorCount) {
 216             GifColorType *new_map = (GifColorType *)reallocarray(Map,
 217                                  RoundUpTo, sizeof(GifColorType));
 218             if( new_map == NULL ) {
 219                 GifFreeMapObject(ColorUnion);
 220                 return ((ColorMapObject *) NULL);
 221             }
 222             ColorUnion->Colors = new_map;
 223         }
 224     }
 225 
 226     ColorUnion->ColorCount = RoundUpTo;
 227     ColorUnion->BitsPerPixel = NewGifBitSize;
 228 
 229     return (ColorUnion);
 230 }
 231 
 232 /*******************************************************************************
 233  Apply a given color translation to the raster bits of an image
 234 *******************************************************************************/
 235 void
 236 GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
 237 {
 238     register int i;
 239     register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
 240 
 241     for (i = 0; i < RasterSize; i++)
 242         Image->RasterBits[i] = Translation[Image->RasterBits[i]];
 243 }
 244 
 245 /******************************************************************************
 246  Extension record functions                              
 247 ******************************************************************************/
 248 int
 249 GifAddExtensionBlock(int *ExtensionBlockCount,
 250                      ExtensionBlock **ExtensionBlocks,
 251                      int Function,
 252                      unsigned int Len,
 253                      unsigned char ExtData[])
 254 {
 255     ExtensionBlock *ep;
 256 
 257     if (*ExtensionBlocks == NULL)
 258         *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
 259     else {
 260         ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
 261                                  (*ExtensionBlocks, (*ExtensionBlockCount + 1),
 262                                       sizeof(ExtensionBlock));
 263         if( ep_new == NULL )
 264             return (GIF_ERROR);
 265         *ExtensionBlocks = ep_new;
 266     }
 267 
 268     if (*ExtensionBlocks == NULL)
 269         return (GIF_ERROR);
 270 
 271     ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
 272 
 273     ep->Function = Function;
 274     ep->ByteCount=Len;
 275     ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
 276     if (ep->Bytes == NULL)
 277         return (GIF_ERROR);
 278 
 279     if (ExtData != NULL) {
 280         memcpy(ep->Bytes, ExtData, Len);
 281     }
 282 
 283     return (GIF_OK);
 284 }
 285 
 286 void
 287 GifFreeExtensions(int *ExtensionBlockCount,
 288                   ExtensionBlock **ExtensionBlocks)
 289 {
 290     ExtensionBlock *ep;
 291 
 292     if (*ExtensionBlocks == NULL)
 293         return;
 294 
 295     for (ep = *ExtensionBlocks;
 296          ep < (*ExtensionBlocks + *ExtensionBlockCount); 
 297          ep++)
 298         (void)free((char *)ep->Bytes);
 299     (void)free((char *)*ExtensionBlocks);
 300     *ExtensionBlocks = NULL;
 301     *ExtensionBlockCount = 0;
 302 }
 303 
 304 /******************************************************************************
 305  Image block allocation functions                          
 306 ******************************************************************************/
 307 
 308 /* Private Function:
 309  * Frees the last image in the GifFile->SavedImages array
 310  */
 311 void
 312 FreeLastSavedImage(GifFileType *GifFile)
 313 {
 314     SavedImage *sp;
 315     
 316     if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
 317         return;
 318 
 319     /* Remove one SavedImage from the GifFile */
 320     GifFile->ImageCount--;
 321     sp = &GifFile->SavedImages[GifFile->ImageCount];
 322 
 323     /* Deallocate its Colormap */
 324     if (sp->ImageDesc.ColorMap != NULL) {
 325         GifFreeMapObject(sp->ImageDesc.ColorMap);
 326         sp->ImageDesc.ColorMap = NULL;
 327     }
 328 
 329     /* Deallocate the image data */
 330     if (sp->RasterBits != NULL)
 331         free((char *)sp->RasterBits);
 332 
 333     /* Deallocate any extensions */
 334     GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
 335 
 336     /*** FIXME: We could realloc the GifFile->SavedImages structure but is
 337      * there a point to it? Saves some memory but we'd have to do it every
 338      * time.  If this is used in GifFreeSavedImages then it would be inefficient
 339      * (The whole array is going to be deallocated.)  If we just use it when
 340      * we want to free the last Image it's convenient to do it here.
 341      */
 342 }
 343 
 344 /*
 345  * Append an image block to the SavedImages array  
 346  */
 347 SavedImage *
 348 GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
 349 {
 350     if (GifFile->SavedImages == NULL)
 351         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
 352     else {
 353         SavedImage* newSavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
 354                                (GifFile->ImageCount + 1), sizeof(SavedImage));
 355         if( newSavedImages == NULL)
 356             return ((SavedImage *)NULL);
 357         GifFile->SavedImages = newSavedImages;
 358     }
 359     if (GifFile->SavedImages == NULL)
 360         return ((SavedImage *)NULL);
 361     else {
 362         SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
 363 
 364         if (CopyFrom != NULL) {
 365             memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
 366 
 367             /* 
 368              * Make our own allocated copies of the heap fields in the
 369              * copied record.  This guards against potential aliasing
 370              * problems.
 371              */
 372 
 373             /* first, the local color map */
 374             if (CopyFrom->ImageDesc.ColorMap != NULL) {
 375                 sp->ImageDesc.ColorMap = GifMakeMapObject(
 376                                          CopyFrom->ImageDesc.ColorMap->ColorCount,
 377                                          CopyFrom->ImageDesc.ColorMap->Colors);
 378                 if (sp->ImageDesc.ColorMap == NULL) {
 379                     FreeLastSavedImage(GifFile);
 380                     return (SavedImage *)(NULL);
 381                 }
 382             }
 383 
 384             /* next, the raster */
 385             sp->RasterBits = (unsigned char *)reallocarray(NULL,
 386                                                   (CopyFrom->ImageDesc.Height *
 387                                                   CopyFrom->ImageDesc.Width),
 388                                                   sizeof(GifPixelType));
 389             if (sp->RasterBits == NULL) {
 390                 FreeLastSavedImage(GifFile);
 391                 return (SavedImage *)(NULL);
 392             }
 393             memcpy(sp->RasterBits, CopyFrom->RasterBits,
 394                    sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
 395                    CopyFrom->ImageDesc.Width);
 396 
 397             /* finally, the extension blocks */
 398             if (CopyFrom->ExtensionBlocks != NULL) {
 399                 sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
 400                                       CopyFrom->ExtensionBlockCount,
 401                                       sizeof(ExtensionBlock));
 402                 if (sp->ExtensionBlocks == NULL) {
 403                     FreeLastSavedImage(GifFile);
 404                     return (SavedImage *)(NULL);
 405                 }
 406                 memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
 407                        sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
 408             }
 409         }
 410         else {
 411             memset((char *)sp, '\0', sizeof(SavedImage));
 412         }
 413 
 414         return (sp);
 415     }
 416 }
 417 
 418 void
 419 GifFreeSavedImages(GifFileType *GifFile)
 420 {
 421     SavedImage *sp;
 422 
 423     if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
 424         return;
 425     }
 426     for (sp = GifFile->SavedImages;
 427          sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
 428         if (sp->ImageDesc.ColorMap != NULL) {
 429             GifFreeMapObject(sp->ImageDesc.ColorMap);
 430             sp->ImageDesc.ColorMap = NULL;
 431         }
 432 
 433         if (sp->RasterBits != NULL)
 434             free((char *)sp->RasterBits);
 435         
 436         GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
 437     }
 438     free((char *)GifFile->SavedImages);
 439     GifFile->SavedImages = NULL;
 440 }
 441 
 442 /* end */