Coverage Report

Created: 2023-03-26 07:33

/src/giflib-code/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.93k
{
26
3.93k
    register int i;
27
28
5.21k
    for (i = 1; i <= 8; i++)
29
5.21k
        if ((1 << i) >= n)
30
3.93k
            break;
31
3.93k
    return (i);
32
3.93k
}
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.96k
{
45
1.96k
    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.96k
    if (ColorCount != (1 << GifBitSize(ColorCount))) {
50
0
        return ((ColorMapObject *) NULL);
51
0
    }
52
    
53
1.96k
    Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
54
1.96k
    if (Object == (ColorMapObject *) NULL) {
55
0
        return ((ColorMapObject *) NULL);
56
0
    }
57
58
1.96k
    Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
59
1.96k
    if (Object->Colors == (GifColorType *) NULL) {
60
0
  free(Object);
61
0
        return ((ColorMapObject *) NULL);
62
0
    }
63
64
1.96k
    Object->ColorCount = ColorCount;
65
1.96k
    Object->BitsPerPixel = GifBitSize(ColorCount);
66
1.96k
    Object->SortFlag = false;
67
68
1.96k
    if (ColorMap != NULL) {
69
911
        memcpy((char *)Object->Colors,
70
911
               (char *)ColorMap, ColorCount * sizeof(GifColorType));
71
911
    }
72
73
1.96k
    return (Object);
74
1.96k
}
75
76
/*******************************************************************************
77
Free a color map object
78
*******************************************************************************/
79
void
80
GifFreeMapObject(ColorMapObject *Object)
81
1.97k
{
82
1.97k
    if (Object != NULL) {
83
1.96k
        (void)free(Object->Colors);
84
1.96k
        (void)free(Object);
85
1.96k
    }
86
1.97k
}
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
75.0k
{
233
75.0k
    ExtensionBlock *ep;
234
235
75.0k
    if (*ExtensionBlocks == NULL)
236
1.77k
        *ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
237
73.2k
    else {
238
73.2k
        ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
239
73.2k
         (*ExtensionBlocks, (*ExtensionBlockCount + 1),
240
73.2k
                                      sizeof(ExtensionBlock));
241
73.2k
        if( ep_new == NULL )
242
0
            return (GIF_ERROR);
243
73.2k
        *ExtensionBlocks = ep_new;
244
73.2k
    }
245
246
75.0k
    if (*ExtensionBlocks == NULL)
247
0
        return (GIF_ERROR);
248
249
75.0k
    ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
250
251
75.0k
    ep->Function = Function;
252
75.0k
    ep->ByteCount=Len;
253
75.0k
    ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
254
75.0k
    if (ep->Bytes == NULL)
255
0
        return (GIF_ERROR);
256
257
75.0k
    if (ExtData != NULL) {
258
75.0k
        memcpy(ep->Bytes, ExtData, Len);
259
75.0k
    }
260
261
75.0k
    return (GIF_OK);
262
75.0k
}
263
264
void
265
GifFreeExtensions(int *ExtensionBlockCount,
266
      ExtensionBlock **ExtensionBlocks)
267
40.8k
{
268
40.8k
    ExtensionBlock *ep;
269
270
40.8k
    if (*ExtensionBlocks == NULL)
271
39.0k
        return;
272
273
1.77k
    for (ep = *ExtensionBlocks;
274
76.8k
   ep < (*ExtensionBlocks + *ExtensionBlockCount); 
275
75.0k
   ep++)
276
75.0k
        (void)free((char *)ep->Bytes);
277
1.77k
    (void)free((char *)*ExtensionBlocks);
278
1.77k
    *ExtensionBlocks = NULL;
279
1.77k
    *ExtensionBlockCount = 0;
280
1.77k
}
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
781
{
399
781
    SavedImage *sp;
400
401
781
    if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
402
0
        return;
403
0
    }
404
781
    for (sp = GifFile->SavedImages;
405
40.6k
         sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
406
39.9k
        if (sp->ImageDesc.ColorMap != NULL) {
407
911
            GifFreeMapObject(sp->ImageDesc.ColorMap);
408
911
            sp->ImageDesc.ColorMap = NULL;
409
911
        }
410
411
39.9k
        if (sp->RasterBits != NULL)
412
39.8k
            free((char *)sp->RasterBits);
413
  
414
39.9k
  GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
415
39.9k
    }
416
781
    free((char *)GifFile->SavedImages);
417
781
    GifFile->SavedImages = NULL;
418
781
}
419
420
/* end */