Coverage Report

Created: 2026-05-16 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/giflib-code/gif_font.c
Line
Count
Source
1
/****************************************************************************
2
3
gif_font.c - utility font handling and simple drawing for the GIF library
4
5
****************************************************************************/
6
// SPDX-License-Identifier: MIT
7
// SPDX-File-Copyright-Txt: (C) Eric S. Raymond <esr@thyrsus.com>
8
9
#include <limits.h>
10
#include <stdint.h>
11
#include <stdlib.h>
12
#include <string.h>
13
14
#include "gif_lib.h"
15
16
/****************************************************************************
17
 Ascii 8 by 8 regular font - only first 128 characters are supported.
18
*****************************************************************************/
19
20
/*
21
 * Each array entry holds the bits for 8 horizontal scan lines, topmost
22
 * first.  The most significant bit of each constant is the leftmost bit of
23
 * the scan line.
24
 */
25
/*@+charint@*/
26
const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH] = {
27
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* Ascii 0 */
28
    {0x3c, 0x42, 0xa5, 0x81, 0xbd, 0x42, 0x3c, 0x00}, /* Ascii 1 */
29
    {0x3c, 0x7e, 0xdb, 0xff, 0xc3, 0x7e, 0x3c, 0x00}, /* Ascii 2 */
30
    {0x00, 0xee, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 3 */
31
    {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 4 */
32
    {0x00, 0x3c, 0x18, 0xff, 0xff, 0x08, 0x18, 0x00}, /* Ascii 5 */
33
    {0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x10, 0x38, 0x00}, /* Ascii 6 */
34
    {0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, 0x00, 0x00}, /* Ascii 7 */
35
    {0xff, 0xff, 0xe7, 0xc3, 0xe7, 0xff, 0xff, 0xff}, /* Ascii 8 */
36
    {0x00, 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c, 0x00}, /* Ascii 9 */
37
    {0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0xbd, 0xc3, 0xff}, /* Ascii 10 */
38
    {0x1f, 0x07, 0x0d, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* Ascii 11 */
39
    {0x00, 0x7e, 0xc3, 0xc3, 0x7e, 0x18, 0x7e, 0x18}, /* Ascii 12 */
40
    {0x04, 0x06, 0x07, 0x04, 0x04, 0xfc, 0xf8, 0x00}, /* Ascii 13 */
41
    {0x0c, 0x0a, 0x0d, 0x0b, 0xf9, 0xf9, 0x1f, 0x1f}, /* Ascii 14 */
42
    {0x00, 0x92, 0x7c, 0x44, 0xc6, 0x7c, 0x92, 0x00}, /* Ascii 15 */
43
    {0x00, 0x00, 0x60, 0x78, 0x7e, 0x78, 0x60, 0x00}, /* Ascii 16 */
44
    {0x00, 0x00, 0x06, 0x1e, 0x7e, 0x1e, 0x06, 0x00}, /* Ascii 17 */
45
    {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18}, /* Ascii 18 */
46
    {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, /* Ascii 19 */
47
    {0xff, 0xb6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x00}, /* Ascii 20 */
48
    {0x7e, 0xc1, 0xdc, 0x22, 0x22, 0x1f, 0x83, 0x7e}, /* Ascii 21 */
49
    {0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}, /* Ascii 22 */
50
    {0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x00, 0xff}, /* Ascii 23 */
51
    {0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* Ascii 24 */
52
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x00}, /* Ascii 25 */
53
    {0x00, 0x04, 0x06, 0xff, 0x06, 0x04, 0x00, 0x00}, /* Ascii 26 */
54
    {0x00, 0x20, 0x60, 0xff, 0x60, 0x20, 0x00, 0x00}, /* Ascii 27 */
55
    {0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xff, 0x00}, /* Ascii 28 */
56
    {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, /* Ascii 29 */
57
    {0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00}, /* Ascii 30 */
58
    {0x00, 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 31 */
59
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
60
    {0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00}, /* ! */
61
    {0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
62
    {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, /* # */
63
    {0x10, 0x7c, 0xd2, 0x7c, 0x86, 0x7c, 0x10, 0x00}, /* $ */
64
    {0xf0, 0x96, 0xfc, 0x18, 0x3e, 0x72, 0xde, 0x00}, /* % */
65
    {0x30, 0x48, 0x30, 0x78, 0xce, 0xcc, 0x78, 0x00}, /* & */
66
    {0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
67
    {0x10, 0x60, 0xc0, 0xc0, 0xc0, 0x60, 0x10, 0x00}, /* ( */
68
    {0x10, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x10, 0x00}, /* ) */
69
    {0x00, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x00, 0x00}, /* * */
70
    {0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00}, /* + */
71
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x70}, /* , */
72
    {0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}, /* - */
73
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00}, /* . */
74
    {0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00}, /* / */
75
    {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* 0 */
76
    {0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* 1 */
77
    {0x7c, 0xc6, 0x06, 0x0c, 0x30, 0x60, 0xfe, 0x00}, /* 2 */
78
    {0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00}, /* 3 */
79
    {0x0e, 0x1e, 0x36, 0x66, 0xfe, 0x06, 0x06, 0x00}, /* 4 */
80
    {0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xfc, 0x00}, /* 5 */
81
    {0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00}, /* 6 */
82
    {0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00}, /* 7 */
83
    {0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* 8 */
84
    {0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00}, /* 9 */
85
    {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}, /* : */
86
    {0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00}, /* }, */
87
    {0x00, 0x1c, 0x30, 0x60, 0x30, 0x1c, 0x00, 0x00}, /* < */
88
    {0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}, /* = */
89
    {0x00, 0x70, 0x18, 0x0c, 0x18, 0x70, 0x00, 0x00}, /* > */
90
    {0x7c, 0xc6, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, /* ? */
91
    {0x7c, 0x82, 0x9a, 0xaa, 0xaa, 0x9e, 0x7c, 0x00}, /* @ */
92
    {0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, /* A */
93
    {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x00}, /* B */
94
    {0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00}, /* C */
95
    {0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00}, /* D */
96
    {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xfe, 0x00}, /* E */
97
    {0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* F */
98
    {0x7c, 0xc6, 0xc0, 0xce, 0xc6, 0xc6, 0x7e, 0x00}, /* G */
99
    {0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00}, /* H */
100
    {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, /* I */
101
    {0x1e, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00}, /* J */
102
    {0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x00}, /* K */
103
    {0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00}, /* L */
104
    {0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00}, /* M */
105
    {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, /* N */
106
    {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* O */
107
    {0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* P */
108
    {0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x06}, /* Q */
109
    {0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0x00}, /* R */
110
    {0x78, 0xcc, 0x60, 0x30, 0x18, 0xcc, 0x78, 0x00}, /* S */
111
    {0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, /* T */
112
    {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* U */
113
    {0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* V */
114
    {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, /* W */
115
    {0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00}, /* X */
116
    {0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00}, /* Y */
117
    {0xfe, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00}, /* Z */
118
    {0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00}, /* [ */
119
    {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x00}, /* \ */
120
    {0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00}, /* ] */
121
    {0x00, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, /* ^ */
122
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /* _ */
123
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
124
    {0x00, 0x00, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00}, /* a */
125
    {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0x00}, /* b */
126
    {0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0x7e, 0x00}, /* c */
127
    {0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x00}, /* d */
128
    {0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7e, 0x00}, /* e */
129
    {0x1e, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x00}, /* f */
130
    {0x00, 0x00, 0x7e, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* g */
131
    {0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* */
132
    {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* i */
133
    {0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0xf0}, /* j */
134
    {0xc0, 0xc0, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0x00}, /* k */
135
    {0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* l */
136
    {0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, /* m */
137
    {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* n */
138
    {0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* o */
139
    {0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0xc0}, /* p */
140
    {0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x06}, /* q */
141
    {0x00, 0x00, 0x6e, 0x70, 0x60, 0x60, 0x60, 0x00}, /* r */
142
    {0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00}, /* s */
143
    {0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x1c, 0x00}, /* t */
144
    {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00}, /* u */
145
    {0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* v */
146
    {0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x00}, /* w */
147
    {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, /* x */
148
    {0x00, 0x00, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* y */
149
    {0x00, 0x00, 0xfc, 0x18, 0x30, 0x60, 0xfc, 0x00}, /* z */
150
    {0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00}, /* { */
151
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */
152
    {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, /* } */
153
    {0x00, 0x00, 0x70, 0x9a, 0x0e, 0x00, 0x00, 0x00}, /* ~ */
154
    {0x00, 0x00, 0x18, 0x3c, 0x66, 0xff, 0x00, 0x00}  /* Ascii 127 */
155
};
156
/*@=charint@*/
157
158
static bool GifImageGetGeometry(const SavedImage *Image,
159
                                size_t *width,
160
                                size_t *height,
161
                                size_t *pixels)
162
0
{
163
0
    size_t w, h;
164
165
0
    if (Image == NULL || Image->RasterBits == NULL) {
166
0
        return false;
167
0
    }
168
0
    if (Image->ImageDesc.Width <= 0 || Image->ImageDesc.Height <= 0) {
169
0
        return false;
170
0
    }
171
172
0
    w = (size_t)Image->ImageDesc.Width;
173
0
    h = (size_t)Image->ImageDesc.Height;
174
0
    if (w > SIZE_MAX / h) {
175
0
        return false;
176
0
    }
177
178
0
    if (width != NULL) {
179
0
        *width = w;
180
0
    }
181
0
    if (height != NULL) {
182
0
        *height = h;
183
0
    }
184
0
    if (pixels != NULL) {
185
0
        *pixels = w * h;
186
0
    }
187
0
    return true;
188
0
}
189
190
static void GifPutPixelClipped(SavedImage *Image, int x, int y, GifPixelType color)
191
0
{
192
0
    size_t width, height;
193
194
0
    if (!GifImageGetGeometry(Image, &width, &height, NULL)) {
195
0
        return;
196
0
    }
197
0
    if (x < 0 || y < 0) {
198
0
        return;
199
0
    }
200
0
    if ((size_t)x >= width || (size_t)y >= height) {
201
0
        return;
202
0
    }
203
204
0
    Image->RasterBits[(size_t)y * width + (size_t)x] = color;
205
0
}
206
207
void GifDrawText8x8(SavedImage *Image, const int x, const int y,
208
                    const char *legend, const int color)
209
0
{
210
0
    int i;
211
0
    const unsigned char *cp;
212
213
0
    if (legend == NULL) {
214
0
        return;
215
0
    }
216
217
0
    for (i = 0; i < GIF_FONT_HEIGHT; i++) {
218
0
        int row_y = y + i;
219
220
0
        if (row_y < 0 || row_y > INT_MAX) {
221
0
            continue;
222
0
        }
223
224
0
        for (cp = (const unsigned char *)legend; *cp != '\0'; cp++) {
225
0
            size_t char_index = (size_t)(cp - (const unsigned char *)legend);
226
0
            size_t j;
227
0
            int glyph_x;
228
0
            unsigned int glyph;
229
230
0
            if (*cp >= 128) {
231
0
                continue;
232
0
            }
233
0
            if (char_index > (size_t)(INT_MAX / GIF_FONT_WIDTH)) {
234
0
                break;
235
0
            }
236
237
0
            glyph_x = x + (int)(char_index * GIF_FONT_WIDTH);
238
0
            glyph = GifAsciiTable8x8[*cp][i];
239
0
            for (j = 0; j < GIF_FONT_WIDTH; j++) {
240
0
                if ((glyph & (1U << (GIF_FONT_WIDTH - 1 - j))) != 0U) {
241
0
                    if (glyph_x <= INT_MAX - (int)j) {
242
0
                        GifPutPixelClipped(Image, glyph_x + (int)j, row_y,
243
0
                                           (GifPixelType)color);
244
0
                    }
245
0
                }
246
0
            }
247
0
        }
248
0
    }
249
0
}
250
251
void GifDrawBox(SavedImage *Image, const int x, const int y, const int w,
252
                const int d, const int color)
253
0
{
254
0
    int j;
255
256
0
    if (w < 0 || d < 0) {
257
0
        return;
258
0
    }
259
260
0
    for (j = 0; j <= w; j++) {
261
0
        if (x <= INT_MAX - j) {
262
0
            GifPutPixelClipped(Image, x + j, y, (GifPixelType)color);
263
0
            if (y <= INT_MAX - d) {
264
0
                GifPutPixelClipped(Image, x + j, y + d,
265
0
                                   (GifPixelType)color);
266
0
            }
267
0
        }
268
0
    }
269
270
0
    for (j = 0; j <= d; j++) {
271
0
        if (y <= INT_MAX - j) {
272
0
            GifPutPixelClipped(Image, x, y + j, (GifPixelType)color);
273
0
            if (x <= INT_MAX - w) {
274
0
                GifPutPixelClipped(Image, x + w, y + j,
275
0
                                   (GifPixelType)color);
276
0
            }
277
0
        }
278
0
    }
279
0
}
280
281
void GifDrawRectangle(SavedImage *Image, const int x, const int y, const int w,
282
                      const int d, const int color)
283
0
{
284
0
    size_t width, height;
285
0
    size_t row;
286
0
    size_t x0, y0, x1, y1;
287
288
0
    if (!GifImageGetGeometry(Image, &width, &height, NULL)) {
289
0
        return;
290
0
    }
291
0
    if (w <= 0 || d <= 0) {
292
0
        return;
293
0
    }
294
295
0
    x0 = (x <= 0) ? 0U : (size_t)x;
296
0
    y0 = (y <= 0) ? 0U : (size_t)y;
297
298
0
    if (x >= 0 && (size_t)x < width) {
299
0
        size_t rw = (size_t)w;
300
0
        x1 = rw > width - (size_t)x ? width : (size_t)x + rw;
301
0
    } else if (x < 0) {
302
0
        size_t rw = (size_t)w;
303
0
        size_t start = (size_t)(-x);
304
0
        if (rw <= start) {
305
0
            return;
306
0
        }
307
0
        x1 = rw - start;
308
0
        if (x1 > width) {
309
0
            x1 = width;
310
0
        }
311
0
    } else {
312
0
        return;
313
0
    }
314
315
0
    if (y >= 0 && (size_t)y < height) {
316
0
        size_t rh = (size_t)d;
317
0
        y1 = rh > height - (size_t)y ? height : (size_t)y + rh;
318
0
    } else if (y < 0) {
319
0
        size_t rh = (size_t)d;
320
0
        size_t start = (size_t)(-y);
321
0
        if (rh <= start) {
322
0
            return;
323
0
        }
324
0
        y1 = rh - start;
325
0
        if (y1 > height) {
326
0
            y1 = height;
327
0
        }
328
0
    } else {
329
0
        return;
330
0
    }
331
332
0
    if (x0 >= x1 || y0 >= y1) {
333
0
        return;
334
0
    }
335
336
0
    for (row = y0; row < y1; row++) {
337
0
        memset(Image->RasterBits + row * width + x0, (GifPixelType)color,
338
0
               x1 - x0);
339
0
    }
340
0
}
341
342
void GifDrawBoxedText8x8(SavedImage *Image, const int x, const int y,
343
                         const char *legend, const int border, const int bg,
344
                         const int fg)
345
0
{
346
0
    size_t j = 0, LineCount = 0, TextWidth = 0;
347
0
    const char *cp;
348
0
    char *dup;
349
0
    size_t legend_len;
350
351
0
    if (legend == NULL || border < 0) {
352
0
        return;
353
0
    }
354
355
    /* compute size of text to box */
356
0
    for (cp = legend; *cp != '\0'; cp++) {
357
0
        if (*cp == '\r' || *cp == '\n') {
358
0
            if (j > TextWidth) {
359
0
                TextWidth = j;
360
0
            }
361
0
            j = 0;
362
0
            LineCount++;
363
0
        } else if (*cp != '\t') {
364
0
            ++j;
365
0
        }
366
0
    }
367
0
    LineCount++;         /* count last line */
368
0
    if (j > TextWidth) { /* last line might be longer than any previous */
369
0
        TextWidth = j;
370
0
    }
371
372
0
    legend_len = strlen(legend);
373
0
    dup = malloc(legend_len + 1);
374
    /* FIXME: should return bad status, but that would require API change */
375
0
    if (dup != NULL) {
376
0
        size_t fill_w = 0, fill_h = 0, box_w = 0, box_h = 0;
377
0
        int i = 0;
378
0
        char *line, *next;
379
380
0
        if (TextWidth <= (SIZE_MAX - (size_t)(2 * border)) / GIF_FONT_WIDTH) {
381
0
            box_w = (size_t)(2 * border) + TextWidth * GIF_FONT_WIDTH;
382
0
            if (box_w > 0) {
383
0
                fill_w = box_w - 1;
384
0
            }
385
0
        }
386
0
        if (LineCount <= (SIZE_MAX - (size_t)(2 * border)) / GIF_FONT_HEIGHT) {
387
0
            box_h = (size_t)(2 * border) + LineCount * GIF_FONT_HEIGHT;
388
0
            if (box_h > 0) {
389
0
                fill_h = box_h - 1;
390
0
            }
391
0
        }
392
393
0
        if (fill_w > (size_t)INT_MAX) {
394
0
            fill_w = (size_t)INT_MAX;
395
0
        }
396
0
        if (fill_h > (size_t)INT_MAX) {
397
0
            fill_h = (size_t)INT_MAX;
398
0
        }
399
0
        if (box_w > (size_t)INT_MAX) {
400
0
            box_w = (size_t)INT_MAX;
401
0
        }
402
0
        if (box_h > (size_t)INT_MAX) {
403
0
            box_h = (size_t)INT_MAX;
404
0
        }
405
406
        /* fill the box */
407
0
        GifDrawRectangle(Image, x + 1, y + 1, (int)fill_w, (int)fill_h,
408
0
                         bg);
409
0
        memcpy(dup, legend, legend_len + 1);
410
411
0
        for (line = dup; line != NULL; line = next) {
412
0
            size_t leadspace = 0;
413
0
            char *eol = strpbrk(line, "\r\n");
414
415
0
            next = NULL;
416
0
            if (eol != NULL) {
417
0
                next = eol + 1;
418
0
                if ((*eol == '\r' && *next == '\n') ||
419
0
                    (*eol == '\n' && *next == '\r')) {
420
0
                    ++next;
421
0
                }
422
0
                *eol = '\0';
423
0
            }
424
425
0
            if (line[0] == '\t') {
426
0
                size_t linelen = strlen(line + 1);
427
0
                if (linelen < TextWidth) {
428
0
                    leadspace = (TextWidth - linelen) / 2;
429
0
                }
430
0
                ++line;
431
0
            }
432
433
0
            if ((size_t)i <= (size_t)(INT_MAX / GIF_FONT_HEIGHT)) {
434
0
                int text_x = x + border;
435
0
                int text_y = y + border + (GIF_FONT_HEIGHT * i++);
436
437
0
                if (leadspace <= (size_t)(INT_MAX / GIF_FONT_WIDTH) &&
438
0
                    text_x <= INT_MAX - (int)(leadspace * GIF_FONT_WIDTH)) {
439
0
                    text_x += (int)(leadspace * GIF_FONT_WIDTH);
440
0
                }
441
0
                GifDrawText8x8(Image, text_x, text_y, line, fg);
442
0
            }
443
0
        }
444
0
        free(dup);
445
446
        /* outline the box */
447
0
        GifDrawBox(Image, x, y, (int)box_w, (int)box_h, fg);
448
0
    }
449
0
}
450
451
/* end */