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 */