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