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