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