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