Coverage Report

Created: 2025-01-11 06:55

/src/mupdf/source/fitz/load-gif.c
Line
Count
Source (jump to first uncovered line)
1
// Copyright (C) 2004-2021 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
25
#include "pixmap-imp.h"
26
27
#include <string.h>
28
#include <limits.h>
29
30
struct info
31
{
32
  int gif89a;
33
  unsigned int width, height;
34
  unsigned char aspect;
35
  unsigned int xres, yres;
36
37
  unsigned int image_left, image_top;
38
  unsigned int image_width, image_height;
39
  unsigned int image_interlaced;
40
41
  int has_gct;
42
  int gct_entries;
43
  unsigned char *gct;
44
  unsigned int gct_background;
45
46
  int has_lct;
47
  int lct_entries;
48
  unsigned char *lct;
49
50
  int has_transparency;
51
  unsigned int transparent;
52
  unsigned char *mask;
53
54
  fz_pixmap *pix;
55
};
56
57
/* default color table, where the first two entries are black and white */
58
static const unsigned char dct[256 * 3] = {
59
  0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
60
  0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06,
61
  0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a,
62
  0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e,
63
  0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12,
64
  0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16,
65
  0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a,
66
  0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e,
67
  0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22,
68
  0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26,
69
  0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a,
70
  0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e,
71
  0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32,
72
  0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36,
73
  0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a,
74
  0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e,
75
  0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42,
76
  0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46,
77
  0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a,
78
  0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e,
79
  0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52,
80
  0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56,
81
  0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a,
82
  0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e,
83
  0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62,
84
  0x63, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66,
85
  0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a,
86
  0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e,
87
  0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72,
88
  0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76,
89
  0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7a,
90
  0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e,
91
  0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82,
92
  0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86,
93
  0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8a,
94
  0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e,
95
  0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x92,
96
  0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, 0x95, 0x95, 0x96, 0x96, 0x96,
97
  0x97, 0x97, 0x97, 0x98, 0x98, 0x98, 0x99, 0x99, 0x99, 0x9a, 0x9a, 0x9a,
98
  0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9c, 0x9d, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e,
99
  0x9f, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa2,
100
  0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa4, 0xa5, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6,
101
  0xa7, 0xa7, 0xa7, 0xa8, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xaa,
102
  0xab, 0xab, 0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xad, 0xae, 0xae, 0xae,
103
  0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb0, 0xb1, 0xb1, 0xb1, 0xb2, 0xb2, 0xb2,
104
  0xb3, 0xb3, 0xb3, 0xb4, 0xb4, 0xb4, 0xb5, 0xb5, 0xb5, 0xb6, 0xb6, 0xb6,
105
  0xb7, 0xb7, 0xb7, 0xb8, 0xb8, 0xb8, 0xb9, 0xb9, 0xb9, 0xba, 0xba, 0xba,
106
  0xbb, 0xbb, 0xbb, 0xbc, 0xbc, 0xbc, 0xbd, 0xbd, 0xbd, 0xbe, 0xbe, 0xbe,
107
  0xbf, 0xbf, 0xbf, 0xc0, 0xc0, 0xc0, 0xc1, 0xc1, 0xc1, 0xc2, 0xc2, 0xc2,
108
  0xc3, 0xc3, 0xc3, 0xc4, 0xc4, 0xc4, 0xc5, 0xc5, 0xc5, 0xc6, 0xc6, 0xc6,
109
  0xc7, 0xc7, 0xc7, 0xc8, 0xc8, 0xc8, 0xc9, 0xc9, 0xc9, 0xca, 0xca, 0xca,
110
  0xcb, 0xcb, 0xcb, 0xcc, 0xcc, 0xcc, 0xcd, 0xcd, 0xcd, 0xce, 0xce, 0xce,
111
  0xcf, 0xcf, 0xcf, 0xd0, 0xd0, 0xd0, 0xd1, 0xd1, 0xd1, 0xd2, 0xd2, 0xd2,
112
  0xd3, 0xd3, 0xd3, 0xd4, 0xd4, 0xd4, 0xd5, 0xd5, 0xd5, 0xd6, 0xd6, 0xd6,
113
  0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0xda, 0xda, 0xda,
114
  0xdb, 0xdb, 0xdb, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdd, 0xde, 0xde, 0xde,
115
  0xdf, 0xdf, 0xdf, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe1, 0xe2, 0xe2, 0xe2,
116
  0xe3, 0xe3, 0xe3, 0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6,
117
  0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea,
118
  0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xee, 0xee, 0xee,
119
  0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2,
120
  0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6,
121
  0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa,
122
  0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe,
123
};
124
125
static const unsigned char *
126
gif_read_subblocks(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end, fz_buffer *buf)
127
511
{
128
511
  int len;
129
130
511
  do
131
5.26k
  {
132
5.26k
    if (end - p < 1)
133
6
      fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblocks in gif image");
134
5.25k
    len = *p;
135
5.25k
    p += 1;
136
137
5.25k
    if (len > 0)
138
4.77k
    {
139
4.77k
      if (end - p < len)
140
18
        fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblock in gif image");
141
4.75k
      if (buf)
142
3.91k
        fz_append_data(ctx, buf, p, len);
143
4.75k
      p += len;
144
4.75k
    }
145
5.25k
  } while (len > 0);
146
147
487
  return p;
148
511
}
149
150
static const unsigned char *
151
gif_read_header(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
152
109
{
153
109
  if (end - p < 6)
154
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in header in gif image");
155
156
109
  if (memcmp(&p[0], "GIF", 3))
157
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "invalid signature in gif image");
158
109
  if (memcmp(&p[3], "87a", 3) && memcmp(&p[3], "89a", 3))
159
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported version in gif image");
160
161
109
  info->gif89a = !memcmp(p, "GIF89a", 6);
162
163
109
  return p + 6;
164
109
}
165
166
/* coverity[-tainted_data_return] */
167
static unsigned int
168
safe_load_u16(const unsigned char *p)
169
218
{
170
218
  return p[1] << 8 | p[0];
171
218
}
172
173
static const unsigned char *
174
gif_read_lsd(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
175
109
{
176
109
  if (end - p < 7)
177
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in logical screen descriptor in gif image");
178
179
109
  info->width = safe_load_u16(p);
180
109
  info->height = safe_load_u16(p+2);
181
109
  if (info->width <= 0)
182
1
    fz_throw(ctx, FZ_ERROR_FORMAT, "image width must be > 0");
183
108
  if (info->height <= 0)
184
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "image height must be > 0");
185
108
  if (info->height > UINT_MAX / info->width / 3 /* components */)
186
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "image dimensions might overflow");
187
188
108
  info->has_gct = (p[4] >> 7) & 0x1;
189
108
  if (info->has_gct)
190
18
  {
191
18
    info->gct_entries = 1 << ((p[4] & 0x7) + 1);
192
18
    info->gct_background = fz_clampi(p[5], 0, info->gct_entries - 1);
193
18
  }
194
108
  info->aspect = p[6];
195
196
108
  info->xres = 96;
197
108
  info->yres = 96;
198
108
  if (info->aspect > 0)
199
34
    info->yres = (((float) info->aspect + 15) / 64) * 96;
200
201
108
  return p + 7;
202
108
}
203
204
static const unsigned char *
205
gif_read_gct(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
206
9
{
207
9
  if (end - p < info->gct_entries * 3)
208
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in global color table in gif image");
209
210
9
  info->gct = Memento_label(fz_malloc(ctx, info->gct_entries * 3), "gif_gct");
211
9
  memmove(info->gct, p, info->gct_entries * 3);
212
213
9
  return p + info->gct_entries * 3;
214
9
}
215
216
static const unsigned char *
217
gif_read_id(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
218
119
{
219
119
  if (end - p < 10)
220
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in image descriptor in gif image");
221
222
119
  info->image_left = p[2] << 8 | p[1];
223
119
  info->image_top = p[4] << 8 | p[3];
224
119
  info->image_width = p[6] << 8 | p[5];
225
119
  info->image_height = p[8] << 8 | p[7];
226
119
  info->has_lct = (p[9] >> 7) & 0x1;
227
119
  info->image_interlaced = (p[9] >> 6) & 0x1;
228
229
119
  if (info->has_lct)
230
3
    info->lct_entries = 1 << ((p[9] & 0x7) + 1);
231
232
119
  return p + 10;
233
119
}
234
235
static const unsigned char *
236
gif_read_lct(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
237
3
{
238
3
  if (end - p < info->lct_entries * 3)
239
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in local color table in gif image");
240
241
3
  info->lct = Memento_label(fz_malloc(ctx, info->lct_entries * 3), "gif_lct");
242
3
  memmove(info->lct, p, info->lct_entries * 3);
243
244
3
  return p + info->lct_entries * 3;
245
3
}
246
247
static void
248
gif_read_line(fz_context *ctx, struct info *info, int ct_entries, const unsigned char *ct, unsigned int y, unsigned char *sp)
249
214k
{
250
214k
  unsigned int index = (info->image_top + y) * info->width + info->image_left;
251
214k
  unsigned char *samples = fz_pixmap_samples(ctx, info->pix);
252
214k
  unsigned char *dp = &samples[index * 4];
253
214k
  unsigned char *mp = &info->mask[index];
254
214k
  unsigned int x, k;
255
256
214k
  if (info->image_top + y >= info->height)
257
154k
    return;
258
259
105M
  for (x = 0; x < info->image_width && info->image_left + x < info->width; x++, sp++, mp++, dp += 4)
260
105M
    if (!info->has_transparency || *sp != info->transparent)
261
105M
    {
262
105M
      *mp = 0x02;
263
420M
      for (k = 0; k < 3; k++)
264
315M
        dp[k] = ct[fz_clampi(*sp, 0, ct_entries - 1) * 3 + k];
265
105M
      dp[3] = 255;
266
105M
    }
267
0
    else if (*mp == 0x01)
268
0
      *mp = 0x00;
269
59.9k
}
270
271
static const unsigned char *
272
gif_read_tbid(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
273
119
{
274
119
  fz_stream *stm = NULL, *lzwstm = NULL;
275
119
  unsigned int mincodesize, y;
276
119
  fz_buffer *compressed = NULL, *uncompressed = NULL;
277
119
  const unsigned char *ct;
278
119
  unsigned char *sp;
279
119
  int ct_entries;
280
281
119
  if (end - p < 1)
282
1
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in table based image data in gif image");
283
284
118
  mincodesize = *p;
285
286
  /* if there is no overlap, avoid pasting image data, just consume it */
287
118
  if (info->image_top >= info->height || info->image_left >= info->width)
288
23
  {
289
23
    p = gif_read_subblocks(ctx, info, p + 1, end, NULL);
290
23
    return p;
291
23
  }
292
293
95
  fz_var(compressed);
294
95
  fz_var(lzwstm);
295
95
  fz_var(stm);
296
95
  fz_var(uncompressed);
297
298
190
  fz_try(ctx)
299
190
  {
300
95
    compressed = fz_new_buffer(ctx, 0);
301
95
    p = gif_read_subblocks(ctx, info, p + 1, end, compressed);
302
303
95
    stm = fz_open_buffer(ctx, compressed);
304
95
    lzwstm = fz_open_lzwd(ctx, stm, 0, mincodesize + 1, 1, 1);
305
306
95
    uncompressed = fz_read_all(ctx, lzwstm, 0);
307
95
    if (uncompressed->len < (size_t)info->image_width * info->image_height)
308
86
    {
309
86
      fz_warn(ctx, "premature end in compressed table based image data in gif image");
310
1.21G
      while (uncompressed->len < (size_t)info->image_width * info->image_height)
311
1.21G
        fz_append_byte(ctx, uncompressed, 0x00);
312
86
    }
313
314
95
    if (info->has_lct)
315
0
    {
316
0
      ct = info->lct;
317
0
      ct_entries = info->lct_entries;
318
0
    }
319
95
    else if (info->has_gct)
320
0
    {
321
0
      ct = info->gct;
322
0
      ct_entries = info->gct_entries;
323
0
    }
324
95
    else
325
95
    {
326
95
      ct = dct;
327
95
      ct_entries = 256;
328
95
    }
329
330
95
    sp = uncompressed->data;
331
95
    if (info->image_interlaced)
332
6
    {
333
9.47k
      for (y = 0; y < info->image_height; y += 8, sp += info->image_width)
334
9.47k
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
335
9.47k
      for (y = 4; y < info->image_height; y += 8, sp += info->image_width)
336
9.46k
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
337
18.9k
      for (y = 2; y < info->image_height; y += 4, sp += info->image_width)
338
18.9k
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
339
37.8k
      for (y = 1; y < info->image_height; y += 2, sp += info->image_width)
340
37.8k
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
341
6
    }
342
89
    else
343
139k
      for (y = 0; y < info->image_height; y++, sp += info->image_width)
344
139k
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
345
95
  }
346
190
  fz_always(ctx)
347
95
  {
348
95
    fz_drop_buffer(ctx, uncompressed);
349
95
    fz_drop_buffer(ctx, compressed);
350
95
    fz_drop_stream(ctx, lzwstm);
351
95
    fz_drop_stream(ctx, stm);
352
95
  }
353
95
  fz_catch(ctx)
354
8
  {
355
8
    fz_rethrow(ctx);
356
8
  }
357
358
87
  return p;
359
95
}
360
361
static const unsigned char *
362
gif_read_gce(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
363
17
{
364
17
  if (end - p < 8)
365
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in graphic control extension in gif image");
366
17
  if (p[2] != 0x04)
367
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "out of range graphic control extension block size in gif image");
368
369
17
  info->has_transparency = p[3] & 0x1;
370
17
  if (info->has_transparency)
371
1
    info->transparent = p[6];
372
373
17
  return p + 8;
374
17
}
375
376
static const unsigned char *
377
gif_read_ce(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
378
7
{
379
7
  return gif_read_subblocks(ctx, info, p + 2, end, NULL);
380
7
}
381
382
static const unsigned char*
383
gif_read_pte(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
384
0
{
385
0
  if (end - p < 15)
386
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in plain text extension in gif image");
387
0
  if (p[2] != 0x0c)
388
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "out of range plain text extension block size in gif image");
389
0
  return gif_read_subblocks(ctx, info, p + 15, end, NULL);
390
0
}
391
392
static const unsigned char *
393
gif_read_icc(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
394
6
{
395
6
#if FZ_ENABLE_ICC
396
6
  fz_colorspace *icc = NULL;
397
6
  fz_buffer *buf = NULL;
398
399
6
  fz_var(p);
400
401
6
  buf = fz_new_buffer(ctx, 0);
402
12
  fz_try(ctx)
403
12
  {
404
6
    p = gif_read_subblocks(ctx, info, p, end, buf);
405
6
    icc = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, NULL, buf);
406
6
    fz_drop_colorspace(ctx, info->pix->colorspace);
407
6
    info->pix->colorspace = icc;
408
6
  }
409
12
  fz_always(ctx)
410
6
    fz_drop_buffer(ctx, buf);
411
6
  fz_catch(ctx)
412
6
  {
413
6
    fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
414
6
    fz_report_error(ctx);
415
6
    fz_warn(ctx, "ignoring embedded ICC profile in GIF");
416
6
  }
417
418
6
  return p;
419
#else
420
  return gif_read_subblocks(ctx, info, p, end, NULL);
421
#endif
422
6
}
423
424
/*
425
NETSCAPE2.0
426
  http://odur.let.rug.nl/~kleiweg/gif/netscape.html
427
  http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
428
  http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
429
  https://code.google.com/p/gifdotnet/source/browse/src/GifDotNet/GifApplicationExtensionBlock.cs#95
430
  http://trac.webkit.org/browser/trunk/Source/WebCore/platform/image-decoders/gif/GIFImageReader.cpp#L617
431
432
ANIMEXTS1.0
433
  http://www.vurdalakov.net/misc/gif/animexts-looping-application-extension
434
  https://code.google.com/p/gifdotnet/source/browse/src/GifDotNet/GifApplicationExtensionBlock.cs#95
435
436
ICCRGBG1012
437
  http://www.color.org/icc1V42.pdf
438
439
XMP DataXMP
440
  http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf
441
442
fractint
443
  http://fractint.net/fractsvn/trunk/fractint/common/loadfile.c
444
445
ZGATEXTI5 ZGATILEI5 ZGACTRLI5 ZGANPIMGI5
446
ZGAVECTI5 ZGAALPHAI5 ZGATITLE4.0 ZGATEXTI4.0
447
  Zoner GIF animator 4.0 and 5.0
448
*/
449
static const unsigned char *
450
gif_read_ae(fz_context *ctx, struct info *info, const unsigned char *p, const unsigned char *end)
451
8
{
452
8
  static char *ignorable[] = {
453
8
    "NETSACPE2.0", "ANIMEXTS1.0", "XMP DataXMP",
454
8
    "ZGATEXTI5\0\0", "ZGATILEI5\0\0", "ZGANPIMGI5\0", "ZGACTRLI5\0\0",
455
8
    "ZGAVECTI5\0\0", "ZGAALPHAI5\0", "ZGATITLE4.0", "ZGATEXTI4.0",
456
8
  };
457
8
  int i, ignored;
458
459
8
  if (end - p < 14)
460
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in application extension in gif image");
461
8
  if (p[2] != 0x0b)
462
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "out of range application extension block size in gif image");
463
464
8
  ignored = 0;
465
96
  for (i = 0; i < (int)nelem(ignorable); i++)
466
88
    ignored |= memcmp(&p[3], ignorable[i], 8 + 3);
467
8
  if (!ignored)
468
0
  {
469
0
    char extension[9];
470
0
    memmove(extension, &p[3], 8);
471
0
    extension[8] = '\0';
472
0
    fz_warn(ctx, "ignoring unsupported application extension '%s' in gif image", extension);
473
0
  }
474
475
8
  if (!memcmp(&p[3], "ICCRGBG1012", 11))
476
6
    return gif_read_icc(ctx, info, p + 14, end);
477
478
2
  return gif_read_subblocks(ctx, info, p + 14, end, NULL);
479
8
}
480
481
static void
482
gif_mask_transparency(fz_context *ctx, struct info *info)
483
0
{
484
0
  unsigned char *mp = info->mask;
485
0
  unsigned char *dp = fz_pixmap_samples(ctx, info->pix);
486
0
  unsigned int x, y;
487
488
0
  for (y = 0; y < info->height; y++)
489
0
    for (x = 0; x < info->width; x++, mp++, dp += 4)
490
0
      if (*mp == 0x00)
491
0
        dp[3] = 0;
492
0
}
493
494
static fz_pixmap *
495
gif_read_image(fz_context *ctx, struct info *info, const unsigned char *p, size_t total, int only_metadata)
496
109
{
497
109
  const unsigned char *end = p + total;
498
499
109
  memset(info, 0x00, sizeof (*info));
500
501
  /* Read header */
502
109
  p = gif_read_header(ctx, info, p, end);
503
504
  /* Read logical screen descriptor */
505
109
  p = gif_read_lsd(ctx, info, p, end);
506
507
109
  if (only_metadata)
508
54
    return NULL;
509
510
55
  info->pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), info->width, info->height, NULL, 1);
511
512
108
  fz_try(ctx)
513
108
  {
514
54
    info->mask = fz_calloc(ctx, (size_t)info->width * info->height, 1);
515
516
    /* Read optional global color table */
517
54
    if (info->has_gct)
518
9
    {
519
9
      unsigned char *bp, *dp = fz_pixmap_samples(ctx, info->pix);
520
9
      unsigned int x, y, k;
521
522
9
      p = gif_read_gct(ctx, info, p, end);
523
9
      bp = &info->gct[info->gct_background * 3];
524
525
9
      memset(info->mask, 0x01, (size_t)info->width * info->height);
526
527
63.0k
      for (y = 0; y < info->height; y++)
528
156M
        for (x = 0; x < info->width; x++, dp += 4)
529
156M
        {
530
627M
          for (k = 0; k < 3; k++)
531
470M
            dp[k] = bp[k];
532
156M
          dp[3] = 255;
533
156M
        }
534
9
    }
535
536
583
    while (1)
537
563
    {
538
      /* Read block indicator */
539
563
      if (end - p < 1)
540
4
        fz_throw(ctx, FZ_ERROR_FORMAT, "premature end of block indicator in gif image");
541
542
      /* Read trailer */
543
559
      if (p[0] == 0x3b)
544
0
      {
545
0
        break;
546
0
      }
547
      /* Read extension */
548
559
      else if (p[0] == 0x21)
549
412
      {
550
        /* Read extension label */
551
412
        if (end - p < 2)
552
2
          fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in extension label in gif image");
553
554
410
        if (p[1] == 0x01 && info->gif89a)
555
0
        {
556
          /* Read plain text extension */
557
0
          p = gif_read_pte(ctx, info, p, end);
558
559
          /* Graphic control extension applies only to the graphic rendering block following it */
560
0
          info->transparent = 0;
561
0
          info->has_transparency = 0;
562
0
        }
563
410
        else if (p[1] == 0xf9 && info->gif89a)
564
          /* Read graphic control extension */
565
17
          p = gif_read_gce(ctx, info, p, end);
566
393
        else if (p[1] == 0xfe && info->gif89a)
567
          /* Read comment extension */
568
7
          p = gif_read_ce(ctx, info, p, end);
569
386
        else if (p[1] == 0xff && info->gif89a)
570
          /* Read application extension */
571
8
          p = gif_read_ae(ctx, info, p, end);
572
378
        else
573
378
        {
574
378
          fz_warn(ctx, "ignoring unsupported extension label %02x in gif image", p[1]);
575
378
          p = gif_read_subblocks(ctx, info, p + 2, end, NULL);
576
378
        }
577
410
      }
578
      /* Read image descriptor */
579
147
      else if (p[0] == 0x2c)
580
119
      {
581
119
        p = gif_read_id(ctx, info, p, end);
582
583
119
        if (info->has_lct)
584
          /* Read local color table */
585
3
          p = gif_read_lct(ctx, info, p, end);
586
587
        /* Read table based image data */
588
119
        p = gif_read_tbid(ctx, info, p, end);
589
590
        /* Graphic control extension applies only to the graphic rendering block following it */
591
119
        info->transparent = 0;
592
119
        info->has_transparency = 0;
593
594
        /* Image descriptor applies only to the table based image data following it */
595
119
        info->image_left = info->image_top = 0;
596
119
        info->image_width = info->width;
597
119
        info->image_height = info->height;
598
119
        info->image_interlaced = 0;
599
119
        fz_free(ctx, info->lct);
600
119
        info->lct = NULL;
601
119
        info->has_lct = 0;
602
119
      }
603
28
      else
604
28
        fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported block indicator %02x in gif image", p[0]);
605
559
    }
606
607
20
    gif_mask_transparency(ctx, info);
608
20
    fz_premultiply_pixmap(ctx, info->pix);
609
20
  }
610
108
  fz_always(ctx)
611
54
  {
612
54
    fz_free(ctx, info->mask);
613
54
    fz_free(ctx, info->lct);
614
54
    fz_free(ctx, info->gct);
615
54
  }
616
54
  fz_catch(ctx)
617
54
  {
618
54
    fz_drop_pixmap(ctx, info->pix);
619
54
    fz_rethrow(ctx);
620
54
  }
621
622
18.4E
  return info->pix;
623
21
}
624
625
fz_pixmap *
626
fz_load_gif(fz_context *ctx, const unsigned char *p, size_t total)
627
54
{
628
54
  fz_pixmap *image;
629
54
  struct info gif;
630
631
54
  image = gif_read_image(ctx, &gif, p, total, 0);
632
54
  image->xres = gif.xres;
633
54
  image->yres = gif.yres;
634
635
54
  return image;
636
54
}
637
638
void
639
fz_load_gif_info(fz_context *ctx, const unsigned char *p, size_t total, int *wp, int *hp, int *xresp, int *yresp, fz_colorspace **cspacep)
640
55
{
641
55
  struct info gif;
642
643
55
  gif_read_image(ctx, &gif, p, total, 1);
644
55
  *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
645
55
  *wp = gif.width;
646
55
  *hp = gif.height;
647
55
  *xresp = gif.xres;
648
55
  *yresp = gif.yres;
649
55
}