Coverage Report

Created: 2025-11-07 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/fitz/load-gif.c
Line
Count
Source
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
2
{
128
2
  int len;
129
130
2
  do
131
4.09k
  {
132
4.09k
    if (end - p < 1)
133
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblocks in gif image");
134
4.09k
    len = *p;
135
4.09k
    p += 1;
136
137
4.09k
    if (len > 0)
138
4.09k
    {
139
4.09k
      if (end - p < len)
140
1
        fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in data subblock in gif image");
141
4.09k
      if (buf)
142
4.09k
        fz_append_data(ctx, buf, p, len);
143
4.09k
      p += len;
144
4.09k
    }
145
4.09k
  } while (len > 0);
146
147
1
  return p;
148
2
}
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
2
{
153
2
  if (end - p < 6)
154
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in header in gif image");
155
156
2
  if (memcmp(&p[0], "GIF", 3))
157
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "invalid signature in gif image");
158
2
  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
2
  info->gif89a = !memcmp(p, "GIF89a", 6);
162
163
2
  return p + 6;
164
2
}
165
166
/* coverity[-tainted_data_return] */
167
static unsigned int
168
safe_load_u16(const unsigned char *p)
169
4
{
170
4
  return p[1] << 8 | p[0];
171
4
}
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
2
{
176
2
  if (end - p < 7)
177
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in logical screen descriptor in gif image");
178
179
2
  info->width = safe_load_u16(p);
180
2
  info->height = safe_load_u16(p+2);
181
2
  if (info->width <= 0)
182
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "image width must be > 0");
183
2
  if (info->height <= 0)
184
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "image height must be > 0");
185
2
  if (info->height > UINT_MAX / info->width / 3 /* components */)
186
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "image dimensions might overflow");
187
188
2
  info->has_gct = (p[4] >> 7) & 0x1;
189
2
  if (info->has_gct)
190
2
  {
191
2
    info->gct_entries = 1 << ((p[4] & 0x7) + 1);
192
2
    info->gct_background = fz_clampi(p[5], 0, info->gct_entries - 1);
193
2
  }
194
2
  info->aspect = p[6];
195
196
2
  info->xres = 96;
197
2
  info->yres = 96;
198
2
  if (info->aspect > 0)
199
2
    info->yres = (((float) info->aspect + 15) / 64) * 96;
200
201
2
  return p + 7;
202
2
}
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
1
{
207
1
  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
1
  info->gct = Memento_label(fz_malloc(ctx, info->gct_entries * 3), "gif_gct");
211
1
  memmove(info->gct, p, info->gct_entries * 3);
212
213
1
  return p + info->gct_entries * 3;
214
1
}
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
1
{
219
1
  if (end - p < 10)
220
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in image descriptor in gif image");
221
222
1
  info->image_left = p[2] << 8 | p[1];
223
1
  info->image_top = p[4] << 8 | p[3];
224
1
  info->image_width = p[6] << 8 | p[5];
225
1
  info->image_height = p[8] << 8 | p[7];
226
1
  info->has_lct = (p[9] >> 7) & 0x1;
227
1
  info->image_interlaced = (p[9] >> 6) & 0x1;
228
229
1
  if (info->has_lct)
230
0
    info->lct_entries = 1 << ((p[9] & 0x7) + 1);
231
232
1
  return p + 10;
233
1
}
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
0
{
238
0
  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
0
  info->lct = Memento_label(fz_malloc(ctx, info->lct_entries * 3), "gif_lct");
242
0
  memmove(info->lct, p, info->lct_entries * 3);
243
244
0
  return p + info->lct_entries * 3;
245
0
}
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
0
{
250
0
  unsigned int index = (info->image_top + y) * info->width + info->image_left;
251
0
  unsigned char *samples = fz_pixmap_samples(ctx, info->pix);
252
0
  unsigned char *dp = &samples[index * 4];
253
0
  unsigned char *mp = &info->mask[index];
254
0
  unsigned int x, k;
255
256
0
  if (info->image_top + y >= info->height)
257
0
    return;
258
259
0
  for (x = 0; x < info->image_width && info->image_left + x < info->width; x++, sp++, mp++, dp += 4)
260
0
    if (!info->has_transparency || *sp != info->transparent)
261
0
    {
262
0
      *mp = 0x02;
263
0
      for (k = 0; k < 3; k++)
264
0
        dp[k] = ct[fz_clampi(*sp, 0, ct_entries - 1) * 3 + k];
265
0
      dp[3] = 255;
266
0
    }
267
0
    else if (*mp == 0x01)
268
0
      *mp = 0x00;
269
0
}
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
1
{
274
1
  fz_stream *stm = NULL, *lzwstm = NULL;
275
1
  unsigned int mincodesize, y;
276
1
  fz_buffer *compressed = NULL, *uncompressed = NULL;
277
1
  const unsigned char *ct;
278
1
  unsigned char *sp;
279
1
  int ct_entries;
280
281
1
  if (end - p < 1)
282
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in table based image data in gif image");
283
284
1
  mincodesize = *p;
285
286
  /* if there is no overlap, avoid pasting image data, just consume it */
287
1
  if (info->image_top >= info->height || info->image_left >= info->width)
288
0
  {
289
0
    p = gif_read_subblocks(ctx, info, p + 1, end, NULL);
290
0
    return p;
291
0
  }
292
293
1
  fz_var(compressed);
294
1
  fz_var(lzwstm);
295
1
  fz_var(stm);
296
1
  fz_var(uncompressed);
297
298
2
  fz_try(ctx)
299
2
  {
300
1
    compressed = fz_new_buffer(ctx, 0);
301
1
    p = gif_read_subblocks(ctx, info, p + 1, end, compressed);
302
303
1
    stm = fz_open_buffer(ctx, compressed);
304
1
    lzwstm = fz_open_lzwd(ctx, stm, 0, mincodesize + 1, 1, 1);
305
306
1
    uncompressed = fz_read_all(ctx, lzwstm, 0);
307
1
    if (uncompressed->len < (size_t)info->image_width * info->image_height)
308
0
    {
309
0
      fz_warn(ctx, "premature end in compressed table based image data in gif image");
310
0
      while (uncompressed->len < (size_t)info->image_width * info->image_height)
311
0
        fz_append_byte(ctx, uncompressed, 0x00);
312
0
    }
313
314
1
    if (info->has_lct)
315
0
    {
316
0
      ct = info->lct;
317
0
      ct_entries = info->lct_entries;
318
0
    }
319
1
    else if (info->has_gct)
320
0
    {
321
0
      ct = info->gct;
322
0
      ct_entries = info->gct_entries;
323
0
    }
324
1
    else
325
1
    {
326
1
      ct = dct;
327
1
      ct_entries = 256;
328
1
    }
329
330
1
    sp = uncompressed->data;
331
1
    if (info->image_interlaced)
332
0
    {
333
0
      for (y = 0; y < info->image_height; y += 8, sp += info->image_width)
334
0
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
335
0
      for (y = 4; y < info->image_height; y += 8, sp += info->image_width)
336
0
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
337
0
      for (y = 2; y < info->image_height; y += 4, sp += info->image_width)
338
0
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
339
0
      for (y = 1; y < info->image_height; y += 2, sp += info->image_width)
340
0
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
341
0
    }
342
1
    else
343
1
      for (y = 0; y < info->image_height; y++, sp += info->image_width)
344
0
        gif_read_line(ctx, info, ct_entries, ct, y, sp);
345
1
  }
346
2
  fz_always(ctx)
347
1
  {
348
1
    fz_drop_buffer(ctx, uncompressed);
349
1
    fz_drop_buffer(ctx, compressed);
350
1
    fz_drop_stream(ctx, lzwstm);
351
1
    fz_drop_stream(ctx, stm);
352
1
  }
353
1
  fz_catch(ctx)
354
1
  {
355
1
    fz_rethrow(ctx);
356
1
  }
357
358
0
  return p;
359
1
}
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
1
{
364
1
  if (end - p < 8)
365
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in graphic control extension in gif image");
366
1
  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
1
  info->has_transparency = p[3] & 0x1;
370
1
  if (info->has_transparency)
371
0
    info->transparent = p[6];
372
373
1
  return p + 8;
374
1
}
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
0
{
379
0
  return gif_read_subblocks(ctx, info, p + 2, end, NULL);
380
0
}
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
0
{
395
0
#if FZ_ENABLE_ICC
396
0
  fz_colorspace *icc = NULL;
397
0
  fz_buffer *buf = NULL;
398
399
0
  fz_var(p);
400
401
0
  buf = fz_new_buffer(ctx, 0);
402
0
  fz_try(ctx)
403
0
  {
404
0
    p = gif_read_subblocks(ctx, info, p, end, buf);
405
0
    icc = fz_new_icc_colorspace(ctx, FZ_COLORSPACE_RGB, 0, NULL, buf);
406
0
    fz_drop_colorspace(ctx, info->pix->colorspace);
407
0
    info->pix->colorspace = icc;
408
0
  }
409
0
  fz_always(ctx)
410
0
    fz_drop_buffer(ctx, buf);
411
0
  fz_catch(ctx)
412
0
  {
413
0
    fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
414
0
    fz_report_error(ctx);
415
0
    fz_warn(ctx, "ignoring embedded ICC profile in GIF");
416
0
  }
417
418
0
  return p;
419
#else
420
  return gif_read_subblocks(ctx, info, p, end, NULL);
421
#endif
422
0
}
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
1
{
452
1
  static char *ignorable[] = {
453
1
    "NETSACPE2.0", "ANIMEXTS1.0", "XMP DataXMP",
454
1
    "ZGATEXTI5\0\0", "ZGATILEI5\0\0", "ZGANPIMGI5\0", "ZGACTRLI5\0\0",
455
1
    "ZGAVECTI5\0\0", "ZGAALPHAI5\0", "ZGATITLE4.0", "ZGATEXTI4.0",
456
1
  };
457
1
  int i, ignored;
458
459
1
  if (end - p < 14)
460
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in application extension in gif image");
461
1
  if (p[2] != 0x0b)
462
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "out of range application extension block size in gif image");
463
464
1
  ignored = 0;
465
12
  for (i = 0; i < (int)nelem(ignorable); i++)
466
11
    ignored |= memcmp(&p[3], ignorable[i], 8 + 3);
467
1
  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
1
  if (!memcmp(&p[3], "ICCRGBG1012", 11))
476
0
    return gif_read_icc(ctx, info, p + 14, end);
477
478
1
  return gif_read_subblocks(ctx, info, p + 14, end, NULL);
479
1
}
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
2
{
497
2
  const unsigned char *end = p + total;
498
499
2
  memset(info, 0x00, sizeof (*info));
500
501
  /* Read header */
502
2
  p = gif_read_header(ctx, info, p, end);
503
504
  /* Read logical screen descriptor */
505
2
  p = gif_read_lsd(ctx, info, p, end);
506
507
2
  if (only_metadata)
508
1
    return NULL;
509
510
1
  info->pix = fz_new_pixmap(ctx, fz_device_rgb(ctx), info->width, info->height, NULL, 1);
511
512
2
  fz_try(ctx)
513
2
  {
514
1
    info->mask = fz_calloc(ctx, (size_t)info->width * info->height, 1);
515
516
    /* Read optional global color table */
517
1
    if (info->has_gct)
518
1
    {
519
1
      unsigned char *bp, *dp = fz_pixmap_samples(ctx, info->pix);
520
1
      unsigned int x, y, k;
521
522
1
      p = gif_read_gct(ctx, info, p, end);
523
1
      bp = &info->gct[info->gct_background * 3];
524
525
1
      memset(info->mask, 0x01, (size_t)info->width * info->height);
526
527
1.08k
      for (y = 0; y < info->height; y++)
528
2.07M
        for (x = 0; x < info->width; x++, dp += 4)
529
2.07M
        {
530
8.29M
          for (k = 0; k < 3; k++)
531
6.22M
            dp[k] = bp[k];
532
2.07M
          dp[3] = 255;
533
2.07M
        }
534
1
    }
535
536
4
    while (1)
537
3
    {
538
      /* Read block indicator */
539
3
      if (end - p < 1)
540
0
        fz_throw(ctx, FZ_ERROR_FORMAT, "premature end of block indicator in gif image");
541
542
      /* Read trailer */
543
3
      if (p[0] == 0x3b)
544
0
      {
545
0
        break;
546
0
      }
547
      /* Read extension */
548
3
      else if (p[0] == 0x21)
549
2
      {
550
        /* Read extension label */
551
2
        if (end - p < 2)
552
0
          fz_throw(ctx, FZ_ERROR_FORMAT, "premature end in extension label in gif image");
553
554
2
        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
2
        else if (p[1] == 0xf9 && info->gif89a)
564
          /* Read graphic control extension */
565
1
          p = gif_read_gce(ctx, info, p, end);
566
1
        else if (p[1] == 0xfe && info->gif89a)
567
          /* Read comment extension */
568
0
          p = gif_read_ce(ctx, info, p, end);
569
1
        else if (p[1] == 0xff && info->gif89a)
570
          /* Read application extension */
571
1
          p = gif_read_ae(ctx, info, p, end);
572
0
        else
573
0
        {
574
0
          fz_warn(ctx, "ignoring unsupported extension label %02x in gif image", p[1]);
575
0
          p = gif_read_subblocks(ctx, info, p + 2, end, NULL);
576
0
        }
577
2
      }
578
      /* Read image descriptor */
579
1
      else if (p[0] == 0x2c)
580
1
      {
581
1
        p = gif_read_id(ctx, info, p, end);
582
583
1
        if (info->has_lct)
584
          /* Read local color table */
585
0
          p = gif_read_lct(ctx, info, p, end);
586
587
        /* Read table based image data */
588
1
        p = gif_read_tbid(ctx, info, p, end);
589
590
        /* Graphic control extension applies only to the graphic rendering block following it */
591
1
        info->transparent = 0;
592
1
        info->has_transparency = 0;
593
594
        /* Image descriptor applies only to the table based image data following it */
595
1
        info->image_left = info->image_top = 0;
596
1
        info->image_width = info->width;
597
1
        info->image_height = info->height;
598
1
        info->image_interlaced = 0;
599
1
        fz_free(ctx, info->lct);
600
1
        info->lct = NULL;
601
1
        info->has_lct = 0;
602
1
      }
603
0
      else
604
0
        fz_throw(ctx, FZ_ERROR_FORMAT, "unsupported block indicator %02x in gif image", p[0]);
605
3
    }
606
607
1
    gif_mask_transparency(ctx, info);
608
1
    fz_premultiply_pixmap(ctx, info->pix);
609
1
  }
610
2
  fz_always(ctx)
611
1
  {
612
1
    fz_free(ctx, info->mask);
613
1
    fz_free(ctx, info->lct);
614
1
    fz_free(ctx, info->gct);
615
1
  }
616
1
  fz_catch(ctx)
617
1
  {
618
1
    fz_drop_pixmap(ctx, info->pix);
619
1
    fz_rethrow(ctx);
620
1
  }
621
622
0
  return info->pix;
623
1
}
624
625
fz_pixmap *
626
fz_load_gif(fz_context *ctx, const unsigned char *p, size_t total)
627
1
{
628
1
  fz_pixmap *image;
629
1
  struct info gif;
630
631
1
  image = gif_read_image(ctx, &gif, p, total, 0);
632
1
  image->xres = gif.xres;
633
1
  image->yres = gif.yres;
634
635
1
  return image;
636
1
}
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
1
{
641
1
  struct info gif;
642
643
1
  gif_read_image(ctx, &gif, p, total, 1);
644
1
  *cspacep = fz_keep_colorspace(ctx, fz_device_rgb(ctx));
645
1
  *wp = gif.width;
646
1
  *hp = gif.height;
647
1
  *xresp = gif.xres;
648
1
  *yresp = gif.yres;
649
1
}