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