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  *   "Gif-Lib" - Yet another gif library.
  27  *
  28  * Written by:  Gershon Elber                Ver 0.1, Jun. 1989
  29  * Extensively hacked by: Eric S. Raymond        Ver 1.?, Sep 1992
  30  *****************************************************************************
  31  * GIF construction tools
  32  *****************************************************************************
  33  * History:
  34  * 15 Sep 92 - Version 1.0 by Eric Raymond.
  35  ****************************************************************************/
  36 
  37 #ifdef HAVE_CONFIG_H
  38 #include <config.h>
  39 #endif
  40 
  41 #include <stdlib.h>
  42 #include <stdio.h>
  43 #include <string.h>
  44 #include "gif_lib.h"
  45 
  46 #define MAX(x, y)    (((x) > (y)) ? (x) : (y))
  47 
  48 /******************************************************************************
  49  * Miscellaneous utility functions
  50  *****************************************************************************/
  51 
  52 /* return smallest bitfield size n will fit in */
  53 int
  54 BitSize(int n) {
  55 
  56     register int i;
  57 
  58     for (i = 1; i <= 8; i++)
  59         if ((1 << i) >= n)
  60             break;
  61     return (i);
  62 }
  63 
  64 /******************************************************************************
  65  * Color map object functions
  66  *****************************************************************************/
  67 
  68 /*
  69  * Allocate a color map of given size; initialize with contents of
  70  * ColorMap if that pointer is non-NULL.
  71  */
  72 ColorMapObject *
  73 MakeMapObject(int ColorCount,
  74               const GifColorType * ColorMap) {
  75 
  76     ColorMapObject *Object;
  77 
  78     /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
  79      * make the user know that or should we automatically round up instead? */
  80     if (ColorCount != (1 << BitSize(ColorCount))) {
  81         return ((ColorMapObject *) NULL);
  82     }
  83 
  84     Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
  85     if (Object == (ColorMapObject *) NULL) {
  86         return ((ColorMapObject *) NULL);
  87     }
  88 
  89     Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
  90     if (Object->Colors == (GifColorType *) NULL) {
  91         free(Object);
  92         return ((ColorMapObject *) NULL);
  93     }
  94 
  95     Object->ColorCount = ColorCount;
  96     Object->BitsPerPixel = BitSize(ColorCount);
  97 
  98     if (ColorMap) {
  99         memcpy((char *)Object->Colors,
 100                (char *)ColorMap, ColorCount * sizeof(GifColorType));
 101     }
 102 
 103     return (Object);
 104 }
 105 
 106 /*
 107  * Free a color map object
 108  */
 109 void
 110 FreeMapObject(ColorMapObject * Object) {
 111 
 112     if (Object != NULL) {
 113         free(Object->Colors);
 114         free(Object);
 115         Object = NULL;
 116     }
 117 }
 118 
 119 #ifdef DEBUG
 120 void
 121 DumpColorMap(ColorMapObject * Object,
 122              FILE * fp) {
 123 
 124     if (Object) {
 125         int i, j, Len = Object->ColorCount;
 126 
 127         for (i = 0; i < Len; i += 4) {
 128             for (j = 0; j < 4 && j < Len; j++) {
 129                 fprintf(fp, "%3d: %02x %02x %02x   ", i + j,
 130                         Object->Colors[i + j].Red,
 131                         Object->Colors[i + j].Green,
 132                         Object->Colors[i + j].Blue);
 133             }
 134             fprintf(fp, "\n");
 135         }
 136     }
 137 }
 138 #endif /* DEBUG */
 139 
 140 /******************************************************************************
 141  * Extension record functions
 142  *****************************************************************************/
 143 
 144 void
 145 MakeExtension(SavedImage * New,
 146               int Function) {
 147 
 148     New->Function = Function;
 149     /*** FIXME:
 150      * Someday we might have to deal with multiple extensions.
 151      * ??? Was this a note from Gershon or from me?  Does the multiple
 152      * extension blocks solve this or do we need multiple Functions?  Or is
 153      * this an obsolete function?  (People should use AddExtensionBlock
 154      * instead?)
 155      * Looks like AddExtensionBlock needs to take the int Function argument
 156      * then it can take the place of this function.  Right now people have to
 157      * use both.  Fix AddExtensionBlock and add this to the deprecation list.
 158      */
 159 }
 160 
 161 int
 162 AddExtensionBlock(SavedImage * New,
 163                   int Len,
 164                   unsigned char ExtData[]) {
 165 
 166     ExtensionBlock *ep;
 167 
 168     if (New->ExtensionBlocks == NULL)
 169         New->ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
 170     else
 171         New->ExtensionBlocks = (ExtensionBlock *)realloc(New->ExtensionBlocks,
 172                                       sizeof(ExtensionBlock) *
 173                                       (New->ExtensionBlockCount + 1));
 174 
 175     if (New->ExtensionBlocks == NULL)
 176         return (GIF_ERROR);
 177 
 178     ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
 179 
 180     ep->ByteCount=Len;
 181     ep->Bytes = (char *)malloc(ep->ByteCount);
 182     if (ep->Bytes == NULL)
 183         return (GIF_ERROR);
 184 
 185     if (ExtData) {
 186         memcpy(ep->Bytes, ExtData, Len);
 187         ep->Function = New->Function;
 188     }
 189 
 190     return (GIF_OK);
 191 }
 192 
 193 void
 194 FreeExtension(SavedImage * Image)
 195 {
 196     ExtensionBlock *ep;
 197 
 198     if ((Image == NULL) || (Image->ExtensionBlocks == NULL)) {
 199         return;
 200     }
 201     for (ep = Image->ExtensionBlocks;
 202          ep < (Image->ExtensionBlocks + Image->ExtensionBlockCount); ep++)
 203         (void)free((char *)ep->Bytes);
 204     free((char *)Image->ExtensionBlocks);
 205     Image->ExtensionBlocks = NULL;
 206 }
 207 
 208 /******************************************************************************
 209  * Image block allocation functions
 210 ******************************************************************************/
 211 
 212 /* Private Function:
 213  * Frees the last image in the GifFile->SavedImages array
 214  */
 215 void
 216 FreeLastSavedImage(GifFileType *GifFile) {
 217 
 218     SavedImage *sp;
 219 
 220     if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
 221         return;
 222 
 223     /* Remove one SavedImage from the GifFile */
 224     GifFile->ImageCount--;
 225     sp = &GifFile->SavedImages[GifFile->ImageCount];
 226 
 227     /* Deallocate its Colormap */
 228     if (sp->ImageDesc.ColorMap)
 229         FreeMapObject(sp->ImageDesc.ColorMap);
 230 
 231     /* Deallocate the image data */
 232     if (sp->RasterBits)
 233         free((char *)sp->RasterBits);
 234 
 235     /* Deallocate any extensions */
 236     if (sp->ExtensionBlocks)
 237         FreeExtension(sp);
 238 
 239     /*** FIXME: We could realloc the GifFile->SavedImages structure but is
 240      * there a point to it? Saves some memory but we'd have to do it every
 241      * time.  If this is used in FreeSavedImages then it would be inefficient
 242      * (The whole array is going to be deallocated.)  If we just use it when
 243      * we want to free the last Image it's convenient to do it here.
 244      */
 245 }
 246 
 247 /*
 248  * Append an image block to the SavedImages array
 249  */
 250 SavedImage *
 251 MakeSavedImage(GifFileType * GifFile,
 252                const SavedImage * CopyFrom) {
 253 
 254     SavedImage *sp;
 255 
 256     if (GifFile->SavedImages == NULL)
 257         GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
 258     else
 259         GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages,
 260                                sizeof(SavedImage) * (GifFile->ImageCount + 1));
 261 
 262     if (GifFile->SavedImages == NULL)
 263         return ((SavedImage *)NULL);
 264     else {
 265         sp = &GifFile->SavedImages[GifFile->ImageCount++];
 266         memset((char *)sp, '\0', sizeof(SavedImage));
 267 
 268         if (CopyFrom) {
 269             memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
 270 
 271             /*
 272              * Make our own allocated copies of the heap fields in the
 273              * copied record.  This guards against potential aliasing
 274              * problems.
 275              */
 276 
 277             /* first, the local color map */
 278             if (sp->ImageDesc.ColorMap) {
 279                 sp->ImageDesc.ColorMap = MakeMapObject(
 280                                          CopyFrom->ImageDesc.ColorMap->ColorCount,
 281                                          CopyFrom->ImageDesc.ColorMap->Colors);
 282                 if (sp->ImageDesc.ColorMap == NULL) {
 283                     FreeLastSavedImage(GifFile);
 284                     return (SavedImage *)(NULL);
 285                 }
 286             }
 287 
 288             /* next, the raster */
 289             sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) *
 290                                                    CopyFrom->ImageDesc.Height *
 291                                                    CopyFrom->ImageDesc.Width);
 292             if (sp->RasterBits == NULL) {
 293                 FreeLastSavedImage(GifFile);
 294                 return (SavedImage *)(NULL);
 295             }
 296             memcpy(sp->RasterBits, CopyFrom->RasterBits,
 297                    sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
 298                    CopyFrom->ImageDesc.Width);
 299 
 300             /* finally, the extension blocks */
 301             if (sp->ExtensionBlocks) {
 302                 sp->ExtensionBlocks = (ExtensionBlock *)malloc(
 303                                       sizeof(ExtensionBlock) *
 304                                       CopyFrom->ExtensionBlockCount);
 305                 if (sp->ExtensionBlocks == NULL) {
 306                     FreeLastSavedImage(GifFile);
 307                     return (SavedImage *)(NULL);
 308                 }
 309                 memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
 310                        sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
 311 
 312                 /*
 313                  * For the moment, the actual blocks can take their
 314                  * chances with free().  We'll fix this later.
 315                  *** FIXME: [Better check this out... Toshio]
 316                  * 2004 May 27: Looks like this was an ESR note.
 317                  * It means the blocks are shallow copied from InFile to
 318                  * OutFile.  However, I don't see that in this code....
 319                  * Did ESR fix it but never remove this note (And other notes
 320                  * in gifspnge?)
 321                  */
 322             }
 323         }
 324 
 325         return (sp);
 326     }
 327 }
 328 
 329 void
 330 FreeSavedImages(GifFileType * GifFile) {
 331 
 332     SavedImage *sp;
 333 
 334     if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
 335         return;
 336     }
 337     for (sp = GifFile->SavedImages;
 338          sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
 339         if (sp->ImageDesc.ColorMap)
 340             FreeMapObject(sp->ImageDesc.ColorMap);
 341 
 342         if (sp->RasterBits)
 343             free((char *)sp->RasterBits);
 344 
 345         if (sp->ExtensionBlocks)
 346             FreeExtension(sp);
 347     }
 348     free((char *)GifFile->SavedImages);
 349     GifFile->SavedImages=NULL;
 350 }