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 */
45int
46GifBitSize(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 */
64ColorMapObject *
65GifMakeMapObject(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/*******************************************************************************
99Free a color map object
100*******************************************************************************/
101void
102GifFreeMapObject(ColorMapObject *Object)
103{
104 if (Object != NULL) {
105 (void)free(Object->Colors);
106 (void)free(Object);
107 }
108}
109
110#ifdef DEBUG
111void
112DumpColorMap(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*******************************************************************************/
138ColorMapObject *
139GifUnionColorMap(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*******************************************************************************/
235void
236GifApplyTranslation(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******************************************************************************/
248int
249GifAddExtensionBlock(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
286void
287GifFreeExtensions(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 */
311void
312FreeLastSavedImage(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 */
347SavedImage *
348GifMakeSavedImage(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
418void
419GifFreeSavedImages(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 */
443