| /* |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| |
| /***************************************************************************** |
| * "Gif-Lib" - Yet another gif library. |
| * |
| * Written by: Gershon Elber Ver 0.1, Jun. 1989 |
| * Extensively hacked by: Eric S. Raymond Ver 1.?, Sep 1992 |
| ***************************************************************************** |
| * GIF construction tools |
| ***************************************************************************** |
| * History: |
| * 15 Sep 92 - Version 1.0 by Eric Raymond. |
| ****************************************************************************/ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "gif_lib.h" |
| |
| #define MAX(x, y) (((x) > (y)) ? (x) : (y)) |
| |
| /****************************************************************************** |
| * Miscellaneous utility functions |
| *****************************************************************************/ |
| |
| /* return smallest bitfield size n will fit in */ |
| int |
| BitSize(int n) { |
| |
| register int i; |
| |
| for (i = 1; i <= 8; i++) |
| if ((1 << i) >= n) |
| break; |
| return (i); |
| } |
| |
| /****************************************************************************** |
| * Color map object functions |
| *****************************************************************************/ |
| |
| /* |
| * Allocate a color map of given size; initialize with contents of |
| * ColorMap if that pointer is non-NULL. |
| */ |
| ColorMapObject * |
| MakeMapObject(int ColorCount, |
| const GifColorType * ColorMap) { |
| |
| ColorMapObject *Object; |
| |
| /*** FIXME: Our ColorCount has to be a power of two. Is it necessary to |
| * make the user know that or should we automatically round up instead? */ |
| if (ColorCount != (1 << BitSize(ColorCount))) { |
| return ((ColorMapObject *) NULL); |
| } |
| |
| Object = (ColorMapObject *)malloc(sizeof(ColorMapObject)); |
| if (Object == (ColorMapObject *) NULL) { |
| return ((ColorMapObject *) NULL); |
| } |
| |
| Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType)); |
| if (Object->Colors == (GifColorType *) NULL) { |
| return ((ColorMapObject *) NULL); |
| } |
| |
| Object->ColorCount = ColorCount; |
| Object->BitsPerPixel = BitSize(ColorCount); |
| |
| if (ColorMap) { |
| memcpy((char *)Object->Colors, |
| (char *)ColorMap, ColorCount * sizeof(GifColorType)); |
| } |
| |
| return (Object); |
| } |
| |
| /* |
| * Free a color map object |
| */ |
| void |
| FreeMapObject(ColorMapObject * Object) { |
| |
| if (Object != NULL) { |
| free(Object->Colors); |
| free(Object); |
| Object = NULL; |
| } |
| } |
| |
| #ifdef DEBUG |
| void |
| DumpColorMap(ColorMapObject * Object, |
| FILE * fp) { |
| |
| if (Object) { |
| int i, j, Len = Object->ColorCount; |
| |
| for (i = 0; i < Len; i += 4) { |
| for (j = 0; j < 4 && j < Len; j++) { |
| fprintf(fp, "%3d: %02x %02x %02x ", i + j, |
| Object->Colors[i + j].Red, |
| Object->Colors[i + j].Green, |
| Object->Colors[i + j].Blue); |
| } |
| fprintf(fp, "\n"); |
| } |
| } |
| } |
| #endif /* DEBUG */ |
| |
| /****************************************************************************** |
| * Extension record functions |
| *****************************************************************************/ |
| |
| void |
| MakeExtension(SavedImage * New, |
| int Function) { |
| |
| New->Function = Function; |
| /*** FIXME: |
| * Someday we might have to deal with multiple extensions. |
| * ??? Was this a note from Gershon or from me? Does the multiple |
| * extension blocks solve this or do we need multiple Functions? Or is |
| * this an obsolete function? (People should use AddExtensionBlock |
| * instead?) |
| * Looks like AddExtensionBlock needs to take the int Function argument |
| * then it can take the place of this function. Right now people have to |
| * use both. Fix AddExtensionBlock and add this to the deprecation list. |
| */ |
| } |
| |
| int |
| AddExtensionBlock(SavedImage * New, |
| int Len, |
| unsigned char ExtData[]) { |
| |
| ExtensionBlock *ep; |
| |
| if (New->ExtensionBlocks == NULL) |
| New->ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock)); |
| else |
| New->ExtensionBlocks = (ExtensionBlock *)realloc(New->ExtensionBlocks, |
| sizeof(ExtensionBlock) * |
| (New->ExtensionBlockCount + 1)); |
| |
| if (New->ExtensionBlocks == NULL) |
| return (GIF_ERROR); |
| |
| ep = &New->ExtensionBlocks[New->ExtensionBlockCount++]; |
| |
| ep->ByteCount=Len; |
| ep->Bytes = (char *)malloc(ep->ByteCount); |
| if (ep->Bytes == NULL) |
| return (GIF_ERROR); |
| |
| if (ExtData) { |
| memcpy(ep->Bytes, ExtData, Len); |
| ep->Function = New->Function; |
| } |
| |
| return (GIF_OK); |
| } |
| |
| void |
| FreeExtension(SavedImage * Image) |
| { |
| ExtensionBlock *ep; |
| |
| if ((Image == NULL) || (Image->ExtensionBlocks == NULL)) { |
| return; |
| } |
| for (ep = Image->ExtensionBlocks; |
| ep < (Image->ExtensionBlocks + Image->ExtensionBlockCount); ep++) |
| (void)free((char *)ep->Bytes); |
| free((char *)Image->ExtensionBlocks); |
| Image->ExtensionBlocks = NULL; |
| } |
| |
| /****************************************************************************** |
| * Image block allocation functions |
| ******************************************************************************/ |
| |
| /* Private Function: |
| * Frees the last image in the GifFile->SavedImages array |
| */ |
| void |
| FreeLastSavedImage(GifFileType *GifFile) { |
| |
| SavedImage *sp; |
| |
| if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) |
| return; |
| |
| /* Remove one SavedImage from the GifFile */ |
| GifFile->ImageCount--; |
| sp = &GifFile->SavedImages[GifFile->ImageCount]; |
| |
| /* Deallocate its Colormap */ |
| if (sp->ImageDesc.ColorMap) |
| FreeMapObject(sp->ImageDesc.ColorMap); |
| |
| /* Deallocate the image data */ |
| if (sp->RasterBits) |
| free((char *)sp->RasterBits); |
| |
| /* Deallocate any extensions */ |
| if (sp->ExtensionBlocks) |
| FreeExtension(sp); |
| |
| /*** FIXME: We could realloc the GifFile->SavedImages structure but is |
| * there a point to it? Saves some memory but we'd have to do it every |
| * time. If this is used in FreeSavedImages then it would be inefficient |
| * (The whole array is going to be deallocated.) If we just use it when |
| * we want to free the last Image it's convenient to do it here. |
| */ |
| } |
| |
| /* |
| * Append an image block to the SavedImages array |
| */ |
| SavedImage * |
| MakeSavedImage(GifFileType * GifFile, |
| const SavedImage * CopyFrom) { |
| |
| SavedImage *sp; |
| |
| if (GifFile->SavedImages == NULL) |
| GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage)); |
| else |
| GifFile->SavedImages = (SavedImage *)realloc(GifFile->SavedImages, |
| sizeof(SavedImage) * (GifFile->ImageCount + 1)); |
| |
| if (GifFile->SavedImages == NULL) |
| return ((SavedImage *)NULL); |
| else { |
| sp = &GifFile->SavedImages[GifFile->ImageCount++]; |
| memset((char *)sp, '\0', sizeof(SavedImage)); |
| |
| if (CopyFrom) { |
| memcpy((char *)sp, CopyFrom, sizeof(SavedImage)); |
| |
| /* |
| * Make our own allocated copies of the heap fields in the |
| * copied record. This guards against potential aliasing |
| * problems. |
| */ |
| |
| /* first, the local color map */ |
| if (sp->ImageDesc.ColorMap) { |
| sp->ImageDesc.ColorMap = MakeMapObject( |
| CopyFrom->ImageDesc.ColorMap->ColorCount, |
| CopyFrom->ImageDesc.ColorMap->Colors); |
| if (sp->ImageDesc.ColorMap == NULL) { |
| FreeLastSavedImage(GifFile); |
| return (SavedImage *)(NULL); |
| } |
| } |
| |
| /* next, the raster */ |
| sp->RasterBits = (unsigned char *)malloc(sizeof(GifPixelType) * |
| CopyFrom->ImageDesc.Height * |
| CopyFrom->ImageDesc.Width); |
| if (sp->RasterBits == NULL) { |
| FreeLastSavedImage(GifFile); |
| return (SavedImage *)(NULL); |
| } |
| memcpy(sp->RasterBits, CopyFrom->RasterBits, |
| sizeof(GifPixelType) * CopyFrom->ImageDesc.Height * |
| CopyFrom->ImageDesc.Width); |
| |
| /* finally, the extension blocks */ |
| if (sp->ExtensionBlocks) { |
| sp->ExtensionBlocks = (ExtensionBlock *)malloc( |
| sizeof(ExtensionBlock) * |
| CopyFrom->ExtensionBlockCount); |
| if (sp->ExtensionBlocks == NULL) { |
| FreeLastSavedImage(GifFile); |
| return (SavedImage *)(NULL); |
| } |
| memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks, |
| sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount); |
| |
| /* |
| * For the moment, the actual blocks can take their |
| * chances with free(). We'll fix this later. |
| *** FIXME: [Better check this out... Toshio] |
| * 2004 May 27: Looks like this was an ESR note. |
| * It means the blocks are shallow copied from InFile to |
| * OutFile. However, I don't see that in this code.... |
| * Did ESR fix it but never remove this note (And other notes |
| * in gifspnge?) |
| */ |
| } |
| } |
| |
| return (sp); |
| } |
| } |
| |
| void |
| FreeSavedImages(GifFileType * GifFile) { |
| |
| SavedImage *sp; |
| |
| if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) { |
| return; |
| } |
| for (sp = GifFile->SavedImages; |
| sp < GifFile->SavedImages + GifFile->ImageCount; sp++) { |
| if (sp->ImageDesc.ColorMap) |
| FreeMapObject(sp->ImageDesc.ColorMap); |
| |
| if (sp->RasterBits) |
| free((char *)sp->RasterBits); |
| |
| if (sp->ExtensionBlocks) |
| FreeExtension(sp); |
| } |
| free((char *)GifFile->SavedImages); |
| GifFile->SavedImages=NULL; |
| } |