Coverage Report

Created: 2026-10-13 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/pdf/pdf-stream.c
Line
Count
Source
1
// Copyright (C) 2004-2026 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
#include "mupdf/pdf.h"
25
26
#include <string.h>
27
28
int
29
pdf_obj_num_is_stream(fz_context *ctx, pdf_document *doc, int num)
30
11.5k
{
31
11.5k
  pdf_xref_entry *entry;
32
33
11.5k
  if (num <= 0 || num >= pdf_xref_len(ctx, doc))
34
0
    return 0;
35
36
23.1k
  fz_try(ctx)
37
23.1k
  {
38
11.5k
    entry = pdf_get_xref_entry(ctx, doc, num);
39
11.5k
    if (entry && entry->type == 'n')
40
11.5k
      entry = pdf_cache_object(ctx, doc, num);
41
11.5k
  }
42
23.1k
  fz_catch(ctx)
43
211
  {
44
211
    fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
45
211
    fz_rethrow_if(ctx, FZ_ERROR_SYSTEM);
46
211
    fz_report_error(ctx);
47
211
    return 0;
48
211
  }
49
50
11.3k
  if (entry)
51
11.3k
    return entry->type == 'n' && (entry->stm_ofs != 0 || entry->stm_buf);
52
0
  return 0;
53
11.3k
}
54
55
int
56
pdf_is_stream(fz_context *ctx, pdf_obj *ref)
57
10.2k
{
58
10.2k
  pdf_document *doc = pdf_get_bound_document(ctx, ref);
59
10.2k
  if (doc)
60
9.62k
    return pdf_obj_num_is_stream(ctx, doc, pdf_to_num(ctx, ref));
61
635
  return 0;
62
10.2k
}
63
64
int pdf_is_stream_external(fz_context *ctx, pdf_obj *obj)
65
6.93k
{
66
6.93k
  pdf_obj *f = pdf_dict_get(ctx, obj, PDF_NAME(F));
67
68
6.93k
  return (pdf_is_string(ctx, f) || pdf_is_filespec(ctx, f));
69
6.93k
}
70
71
static int64_t
72
pdf_stream_length(fz_context *ctx, pdf_document *doc, pdf_obj *dict)
73
16.2k
{
74
  /* Return sanity-checked stream length: cannot be negative or larger than the file. */
75
16.2k
  int64_t len = pdf_dict_get_int64(ctx, dict, PDF_NAME(Length));
76
16.2k
  if (len < 0 || len > doc->file_size)
77
410
    len = 0;
78
16.2k
  return len;
79
16.2k
}
80
81
/*
82
 * Scan stream dictionary for an explicit /Crypt filter
83
 */
84
static int
85
pdf_stream_has_crypt(fz_context *ctx, pdf_obj *stm)
86
12.4k
{
87
12.4k
  pdf_obj *filters;
88
12.4k
  pdf_obj *obj;
89
12.4k
  int i;
90
91
12.4k
  filters = pdf_dict_geta(ctx, stm, PDF_NAME(Filter), PDF_NAME(F));
92
12.4k
  if (filters)
93
11.9k
  {
94
11.9k
    if (pdf_name_eq(ctx, filters, PDF_NAME(Crypt)))
95
0
      return 1;
96
11.9k
    if (pdf_is_array(ctx, filters))
97
8
    {
98
8
      int n = pdf_array_len(ctx, filters);
99
18
      for (i = 0; i < n; i++)
100
10
      {
101
10
        obj = pdf_array_get(ctx, filters, i);
102
10
        if (pdf_name_eq(ctx, obj, PDF_NAME(Crypt)))
103
0
          return 1;
104
10
      }
105
8
    }
106
11.9k
  }
107
12.4k
  return 0;
108
12.4k
}
109
110
static fz_jbig2_globals *
111
pdf_load_jbig2_globals(fz_context *ctx, pdf_obj *dict)
112
0
{
113
0
  fz_jbig2_globals *globals;
114
0
  fz_buffer *buf = NULL;
115
116
0
  fz_var(buf);
117
118
0
  if ((globals = pdf_find_item(ctx, fz_drop_jbig2_globals_imp, dict)) != NULL)
119
0
    return globals;
120
121
0
  if (pdf_mark_obj(ctx, dict))
122
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "cyclic reference when loading JBIG2 globals");
123
124
0
  fz_try(ctx)
125
0
  {
126
0
    buf = pdf_load_stream(ctx, dict);
127
0
    globals = fz_load_jbig2_globals(ctx, buf);
128
0
    if (globals)
129
0
      pdf_store_item(ctx, dict, globals, fz_buffer_storage(ctx, buf, NULL));
130
0
  }
131
0
  fz_always(ctx)
132
0
  {
133
0
    fz_drop_buffer(ctx, buf);
134
0
    pdf_unmark_obj(ctx, dict);
135
0
  }
136
0
  fz_catch(ctx)
137
0
  {
138
0
    fz_rethrow(ctx);
139
0
  }
140
141
0
  return globals;
142
0
}
143
144
static void
145
build_compression_params(fz_context *ctx, pdf_obj *f, pdf_obj *p, fz_compression_params *params)
146
11.9k
{
147
11.9k
  params->type = FZ_IMAGE_RAW;
148
149
11.9k
  if (pdf_name_eq(ctx, f, PDF_NAME(CCITTFaxDecode)) || pdf_name_eq(ctx, f, PDF_NAME(CCF)))
150
0
  {
151
0
    params->type = FZ_IMAGE_FAX;
152
0
    params->u.fax.k = pdf_dict_get_int_default(ctx, p, PDF_NAME(K), 0);
153
0
    params->u.fax.end_of_line = pdf_dict_get_bool_default(ctx, p, PDF_NAME(EndOfLine), 0);
154
0
    params->u.fax.encoded_byte_align = pdf_dict_get_bool_default(ctx, p, PDF_NAME(EncodedByteAlign), 0);
155
0
    params->u.fax.columns = pdf_dict_get_int_default(ctx, p, PDF_NAME(Columns), 1728);
156
0
    params->u.fax.rows = pdf_dict_get_int_default(ctx, p, PDF_NAME(Rows), 0);
157
0
    params->u.fax.end_of_block = pdf_dict_get_bool_default(ctx, p, PDF_NAME(EndOfBlock), 1);
158
0
    params->u.fax.black_is_1 = pdf_dict_get_bool_default(ctx, p, PDF_NAME(BlackIs1), 0);
159
0
  }
160
11.9k
  else if (pdf_name_eq(ctx, f, PDF_NAME(DCTDecode)) || pdf_name_eq(ctx, f, PDF_NAME(DCT)))
161
24
  {
162
24
    params->type = FZ_IMAGE_JPEG;
163
24
    params->u.jpeg.color_transform = pdf_dict_get_int_default(ctx, p, PDF_NAME(ColorTransform), -1);
164
24
    params->u.jpeg.invert_cmyk = 0;
165
24
  }
166
11.9k
  else if (pdf_name_eq(ctx, f, PDF_NAME(RunLengthDecode)) || pdf_name_eq(ctx, f, PDF_NAME(RL)))
167
0
  {
168
0
    params->type = FZ_IMAGE_RLD;
169
0
  }
170
11.9k
  else if (pdf_name_eq(ctx, f, PDF_NAME(FlateDecode)) || pdf_name_eq(ctx, f, PDF_NAME(Fl)))
171
11.9k
  {
172
11.9k
    params->type = FZ_IMAGE_FLATE;
173
11.9k
    params->u.flate.predictor = pdf_dict_get_int_default(ctx, p, PDF_NAME(Predictor), 1);
174
11.9k
    params->u.flate.columns = pdf_dict_get_int_default(ctx, p, PDF_NAME(Columns), 1);
175
11.9k
    params->u.flate.colors = pdf_dict_get_int_default(ctx, p, PDF_NAME(Colors), 1);
176
11.9k
    params->u.flate.bpc = pdf_dict_get_int_default(ctx, p, PDF_NAME(BitsPerComponent), 8);
177
11.9k
  }
178
4
  else if (pdf_name_eq(ctx, f, PDF_NAME(BrotliDecode)) || pdf_name_eq(ctx, f, PDF_NAME(Br)))
179
0
  {
180
0
    params->type = FZ_IMAGE_BROTLI;
181
0
    params->u.brotli.predictor = pdf_dict_get_int_default(ctx, p, PDF_NAME(Predictor), 1);
182
0
    params->u.brotli.columns = pdf_dict_get_int_default(ctx, p, PDF_NAME(Columns), 1);
183
0
    params->u.brotli.colors = pdf_dict_get_int_default(ctx, p, PDF_NAME(Colors), 1);
184
0
    params->u.brotli.bpc = pdf_dict_get_int_default(ctx, p, PDF_NAME(BitsPerComponent), 8);
185
0
  }
186
4
  else if (pdf_name_eq(ctx, f, PDF_NAME(LZWDecode)) || pdf_name_eq(ctx, f, PDF_NAME(LZW)))
187
0
  {
188
0
    params->type = FZ_IMAGE_LZW;
189
0
    params->u.lzw.predictor = pdf_dict_get_int_default(ctx, p, PDF_NAME(Predictor), 1);
190
0
    params->u.lzw.columns = pdf_dict_get_int_default(ctx, p, PDF_NAME(Columns), 1);
191
0
    params->u.lzw.colors = pdf_dict_get_int_default(ctx, p, PDF_NAME(Colors), 1);
192
0
    params->u.lzw.bpc = pdf_dict_get_int_default(ctx, p, PDF_NAME(BitsPerComponent), 8);
193
0
    params->u.lzw.early_change = pdf_dict_get_int_default(ctx, p, PDF_NAME(EarlyChange), 1);
194
0
  }
195
4
  else if (pdf_name_eq(ctx, f, PDF_NAME(JBIG2Decode)))
196
0
  {
197
0
    pdf_obj *g = pdf_dict_get(ctx, p, PDF_NAME(JBIG2Globals));
198
199
0
    params->type = FZ_IMAGE_JBIG2;
200
0
    params->u.jbig2.globals = NULL;
201
0
    params->u.jbig2.embedded = 1; /* jbig2 streams are always embedded without file headers */
202
0
    if (g)
203
0
    {
204
0
      if (!pdf_is_stream(ctx, g))
205
0
        fz_warn(ctx, "jbig2 globals is not a stream, skipping globals");
206
0
      else
207
0
        params->u.jbig2.globals = pdf_load_jbig2_globals(ctx, g);
208
0
    }
209
0
  }
210
4
  else if (pdf_name_eq(ctx, f, PDF_NAME(JPXDecode)))
211
3
  {
212
3
    params->type = FZ_IMAGE_JPX;
213
3
    params->u.jpx.smask_in_data = pdf_dict_get_bool_default(ctx, p, PDF_NAME(SMaskInData), 0);
214
3
  }
215
11.9k
}
216
217
/*
218
 * Create a filter given a name and param dictionary.
219
 */
220
static fz_stream *
221
build_filter(fz_context *ctx, fz_stream *chain, pdf_document *doc, pdf_obj *f, pdf_obj *p, int num, int gen, fz_compression_params *params, int might_be_image)
222
11.9k
{
223
11.9k
  fz_compression_params local_params;
224
225
11.9k
  local_params.u.jbig2.globals = NULL;
226
11.9k
  if (params == NULL)
227
8.88k
    params = &local_params;
228
229
11.9k
  if (!might_be_image &&
230
6.09k
    (pdf_name_eq(ctx, f, PDF_NAME(CCITTFaxDecode)) ||
231
6.09k
      pdf_name_eq(ctx, f, PDF_NAME(CCF)) ||
232
6.09k
      pdf_name_eq(ctx, f, PDF_NAME(DCTDecode)) ||
233
6.09k
      pdf_name_eq(ctx, f, PDF_NAME(DCT)) ||
234
6.09k
      pdf_name_eq(ctx, f, PDF_NAME(JBIG2Decode)) ||
235
6.09k
      pdf_name_eq(ctx, f, PDF_NAME(JPXDecode))))
236
0
  {
237
0
    fz_warn(ctx, "Can't open image only stream for non-image purposes");
238
0
    return fz_open_memory(ctx, (unsigned char *)"", 0);
239
0
  }
240
241
11.9k
  build_compression_params(ctx, f, p, params);
242
243
  /* If we were using params we were passed in, and we successfully
244
   * recognised the image type, we can use the existing filter and
245
   * shortstop here. */
246
11.9k
  if (params != &local_params && params->type != FZ_IMAGE_RAW)
247
3.06k
    return fz_keep_stream(ctx, chain); /* nothing to do */
248
249
8.88k
  else if (params->type == FZ_IMAGE_JBIG2)
250
0
  {
251
0
    fz_stream *stm;
252
0
    fz_try(ctx)
253
0
      stm = fz_open_image_decomp_stream(ctx, chain, params, NULL);
254
0
    fz_always(ctx)
255
0
      fz_drop_jbig2_globals(ctx, local_params.u.jbig2.globals);
256
0
    fz_catch(ctx)
257
0
      fz_rethrow(ctx);
258
0
    return stm;
259
0
  }
260
261
8.88k
  else if (params->type != FZ_IMAGE_RAW)
262
8.87k
    return fz_open_image_decomp_stream(ctx, chain, params, NULL);
263
264
1
  else if (pdf_name_eq(ctx, f, PDF_NAME(ASCIIHexDecode)) || pdf_name_eq(ctx, f, PDF_NAME(AHx)))
265
0
    return fz_open_ahxd(ctx, chain);
266
267
1
  else if (pdf_name_eq(ctx, f, PDF_NAME(ASCII85Decode)) || pdf_name_eq(ctx, f, PDF_NAME(A85)))
268
0
    return fz_open_a85d(ctx, chain);
269
270
1
  else if (pdf_name_eq(ctx, f, PDF_NAME(JPXDecode)))
271
0
    return fz_keep_stream(ctx, chain); /* JPX decoding is special cased in the image loading code */
272
273
1
  else if (pdf_name_eq(ctx, f, PDF_NAME(Crypt)))
274
0
  {
275
0
    if (!doc->crypt)
276
0
      fz_warn(ctx, "crypt filter in unencrypted document");
277
0
    else if (num == 0)
278
0
      fz_warn(ctx, "crypt filter in external stream (or illegal object)");
279
0
    else
280
0
    {
281
0
      pdf_obj *name = pdf_dict_get(ctx, p, PDF_NAME(Name));
282
0
      if (pdf_is_name(ctx, name))
283
0
        return pdf_open_crypt_with_filter(ctx, chain, doc->crypt, name, num, gen);
284
0
    }
285
0
  }
286
287
1
  else
288
1
    fz_warn(ctx, "unknown filter name (%s)", pdf_to_name(ctx, f));
289
290
1
  return fz_keep_stream(ctx, chain);
291
11.9k
}
292
293
/* Build filter, and assume ownership of chain */
294
static fz_stream *
295
build_filter_drop(fz_context *ctx, fz_stream *tail, pdf_document *doc, pdf_obj *f, pdf_obj *p, int num, int gen, fz_compression_params *params, int might_be_image)
296
10
{
297
10
  fz_stream *head;
298
20
  fz_try(ctx)
299
20
    head = build_filter(ctx, tail, doc, f, p, num, gen, params, might_be_image);
300
20
  fz_always(ctx)
301
10
    fz_drop_stream(ctx, tail);
302
10
  fz_catch(ctx)
303
0
    fz_rethrow(ctx);
304
10
  return head;
305
10
}
306
307
/*
308
 * Build a chain of filters given filter names and param dicts.
309
 * If chain is given, start filter chain with it.
310
 * Assume ownership of chain.
311
 */
312
static fz_stream *
313
build_filter_chain_drop(fz_context *ctx, fz_stream *chain, pdf_document *doc, pdf_obj *fs, pdf_obj *ps, int num, int gen, fz_compression_params *params, int might_be_image)
314
8
{
315
8
  fz_var(chain);
316
16
  fz_try(ctx)
317
16
  {
318
8
    int i, n = pdf_array_len(ctx, fs);
319
18
    for (i = 0; i < n; i++)
320
10
    {
321
10
      pdf_obj *f = pdf_array_get(ctx, fs, i);
322
10
      pdf_obj *p = pdf_array_get(ctx, ps, i);
323
10
      chain = build_filter_drop(ctx, chain, doc, f, p, num, gen, (i == n-1 ? params : NULL), might_be_image);
324
10
    }
325
8
  }
326
16
  fz_catch(ctx)
327
0
    fz_rethrow(ctx);
328
8
  return chain;
329
8
}
330
331
static fz_stream *
332
build_filter_chain(fz_context *ctx, fz_stream *chain, pdf_document *doc, pdf_obj *fs, pdf_obj *ps, int num, int gen, fz_compression_params *params, int might_be_image)
333
8
{
334
8
  return build_filter_chain_drop(ctx, fz_keep_stream(ctx, chain), doc, fs, ps, num, gen, params, might_be_image);
335
8
}
336
337
/*
338
 * Build a filter for reading raw stream data.
339
 * This is a null filter to constrain reading to the stream length (and to
340
 * allow for other people accessing the file), followed by a decryption
341
 * filter.
342
 *
343
 * orig_num and orig_gen are used purely to seed the encryption.
344
 */
345
static fz_stream *
346
pdf_open_raw_filter(fz_context *ctx, fz_stream *file_stm, pdf_document *doc, pdf_obj *stmobj, int num, int *orig_num, int *orig_gen, int64_t offset)
347
12.6k
{
348
12.6k
  pdf_xref_entry *x = NULL;
349
12.6k
  fz_stream *null_stm, *crypt_stm;
350
12.6k
  int hascrypt;
351
12.6k
  int64_t len;
352
353
12.6k
  if (num > 0 && num < pdf_xref_len(ctx, doc))
354
12.6k
  {
355
12.6k
    x = pdf_get_xref_entry(ctx, doc, num);
356
12.6k
  }
357
12.6k
  if (x == NULL)
358
27
  {
359
    /* We only end up here when called from pdf_open_stream_with_offset to parse new format XRef sections. */
360
    /* New style XRef sections must have generation number 0. */
361
27
    *orig_num = num;
362
27
    *orig_gen = 0;
363
27
  }
364
12.5k
  else
365
12.5k
  {
366
12.5k
    *orig_num = x->num;
367
12.5k
    *orig_gen = x->gen;
368
12.5k
    if (x->stm_buf)
369
170
      return fz_open_buffer(ctx, x->stm_buf);
370
12.5k
  }
371
372
12.4k
  hascrypt = pdf_stream_has_crypt(ctx, stmobj);
373
12.4k
  len = pdf_stream_length(ctx, doc, stmobj);
374
12.4k
  null_stm = fz_open_endstream_filter(ctx, file_stm, (uint64_t)len, offset);
375
12.4k
  if (doc->crypt && !hascrypt)
376
0
  {
377
0
    fz_try(ctx)
378
0
      crypt_stm = pdf_open_crypt(ctx, null_stm, doc->crypt, *orig_num, *orig_gen);
379
0
    fz_always(ctx)
380
0
      fz_drop_stream(ctx, null_stm);
381
0
    fz_catch(ctx)
382
0
      fz_rethrow(ctx);
383
0
    return crypt_stm;
384
0
  }
385
12.4k
  return null_stm;
386
12.4k
}
387
388
/*
389
 * Construct a filter to decode a stream, constraining
390
 * to stream length and decrypting.
391
 */
392
static fz_stream *
393
pdf_open_filter(fz_context *ctx, pdf_document *doc, fz_stream *file_stm, pdf_obj *stmobj, int num, int64_t offset, fz_compression_params *imparams, int might_be_image)
394
12.6k
{
395
12.6k
  pdf_obj *filters = pdf_dict_geta(ctx, stmobj, PDF_NAME(Filter), PDF_NAME(F));
396
12.6k
  int orig_num = 0;
397
12.6k
  int orig_gen = 0;
398
12.6k
  fz_stream *rstm, *fstm;
399
12.6k
  const char *filename = NULL;
400
12.6k
  pdf_obj *parm_name = PDF_NAME(DecodeParms);
401
402
12.6k
  if (pdf_is_string(ctx, filters))
403
0
    filename = pdf_to_text_string(ctx, filters);
404
12.6k
  else if (pdf_is_filespec(ctx, filters))
405
0
  {
406
0
    pdf_filespec_params fs;
407
0
    pdf_get_filespec_params(ctx, filters, &fs);
408
0
    filename = fs.filename;
409
0
  }
410
411
12.6k
  if (filename)
412
0
  {
413
0
    if (doc->archive == NULL)
414
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot open external file resource without an archive");
415
416
0
    filters = pdf_dict_get(ctx, stmobj, PDF_NAME(FFilter));
417
0
    parm_name = PDF_NAME(FDecodeParms);
418
0
    rstm = fz_open_archive_entry(ctx, doc->archive, filename);
419
0
  }
420
12.6k
  else
421
12.6k
    rstm = pdf_open_raw_filter(ctx, file_stm, doc, stmobj, num, &orig_num, &orig_gen, offset);
422
423
25.2k
  fz_try(ctx)
424
25.2k
  {
425
12.6k
    pdf_obj *params = pdf_dict_geta(ctx, stmobj, parm_name, PDF_NAME(DP));
426
12.6k
    if (pdf_is_name(ctx, filters))
427
11.9k
      fstm = build_filter(ctx, rstm, doc, filters, params, orig_num, orig_gen, imparams, might_be_image);
428
686
    else if (pdf_array_len(ctx, filters) > 0)
429
8
      fstm = build_filter_chain(ctx, rstm, doc, filters, params, orig_num, orig_gen, imparams, might_be_image);
430
678
    else
431
678
    {
432
678
      if (imparams)
433
0
        imparams->type = FZ_IMAGE_RAW;
434
678
      fstm = fz_keep_stream(ctx, rstm);
435
678
    }
436
12.6k
  }
437
25.2k
  fz_always(ctx)
438
12.6k
    fz_drop_stream(ctx, rstm);
439
12.6k
  fz_catch(ctx)
440
0
    fz_rethrow(ctx);
441
442
12.6k
  return fstm;
443
12.6k
}
444
445
fz_stream *
446
pdf_open_inline_stream(fz_context *ctx, pdf_document *doc, pdf_obj *stmobj, size_t length, fz_stream *file_stm, fz_compression_params *imparams)
447
0
{
448
0
  pdf_obj *filters = pdf_dict_geta(ctx, stmobj, PDF_NAME(Filter), PDF_NAME(F));
449
0
  pdf_obj *params = pdf_dict_geta(ctx, stmobj, PDF_NAME(DecodeParms), PDF_NAME(DP));
450
451
0
  if (pdf_is_name(ctx, filters))
452
0
    return build_filter(ctx, file_stm, doc, filters, params, 0, 0, imparams, 1);
453
0
  else if (pdf_array_len(ctx, filters) > 0)
454
0
    return build_filter_chain(ctx, file_stm, doc, filters, params, 0, 0, imparams, 1);
455
456
0
  if (imparams)
457
0
    imparams->type = FZ_IMAGE_RAW;
458
0
  return fz_open_null_filter(ctx, file_stm, length, fz_tell(ctx, file_stm));
459
0
}
460
461
void
462
pdf_load_compressed_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict, size_t length, fz_stream *file_stm, int indexed, fz_compressed_image *image)
463
0
{
464
0
  fz_stream *istm = NULL, *leech = NULL, *decomp = NULL;
465
0
  fz_pixmap *pixmap = NULL;
466
0
  fz_compressed_buffer *bc;
467
0
  int dummy_l2factor = 0;
468
469
0
  fz_var(istm);
470
0
  fz_var(leech);
471
0
  fz_var(decomp);
472
0
  fz_var(pixmap);
473
474
0
  bc = fz_new_compressed_buffer(ctx);
475
0
  fz_try(ctx)
476
0
  {
477
0
    bc->buffer = fz_new_buffer(ctx, 1024);
478
0
    istm = pdf_open_inline_stream(ctx, doc, dict, length, file_stm, &bc->params);
479
0
    leech = fz_open_leecher(ctx, istm, bc->buffer);
480
0
    decomp = fz_open_image_decomp_stream(ctx, leech, &bc->params, &dummy_l2factor);
481
0
    pixmap = fz_decomp_image_from_stream(ctx, decomp, image, NULL, indexed, 0, NULL);
482
0
    fz_set_compressed_image_buffer(ctx, image, bc);
483
0
  }
484
0
  fz_always(ctx)
485
0
  {
486
0
    fz_drop_stream(ctx, istm);
487
0
    fz_drop_stream(ctx, leech);
488
0
    fz_drop_stream(ctx, decomp);
489
0
    fz_drop_pixmap(ctx, pixmap);
490
0
  }
491
0
  fz_catch(ctx)
492
0
  {
493
0
    fz_drop_compressed_buffer(ctx, bc);
494
0
    fz_rethrow(ctx);
495
0
  }
496
0
}
497
498
fz_stream *
499
pdf_open_raw_stream_number(fz_context *ctx, pdf_document *doc, int num)
500
0
{
501
0
  pdf_xref_entry *x;
502
0
  int orig_num, orig_gen;
503
504
0
  x = pdf_cache_object(ctx, doc, num);
505
0
  if (!x || x->stm_ofs == 0)
506
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
507
508
0
  return pdf_open_raw_filter(ctx, doc->file, doc, x->obj, num, &orig_num, &orig_gen, x->stm_ofs);
509
0
}
510
511
static fz_stream *
512
pdf_open_image_stream(fz_context *ctx, pdf_document *doc, int num, fz_compression_params *params, int might_be_image)
513
12.5k
{
514
12.5k
  pdf_xref_entry *x;
515
516
12.5k
  x = pdf_cache_object(ctx, doc, num);
517
12.5k
  if (!x || (x->stm_ofs == 0 && x->stm_buf == NULL))
518
3
    fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
519
520
12.5k
  return pdf_open_filter(ctx, doc, doc->file, x->obj, num, x->stm_ofs, params, might_be_image);
521
12.5k
}
522
523
fz_stream *
524
pdf_open_stream_number(fz_context *ctx, pdf_document *doc, int num)
525
2.30k
{
526
2.30k
  return pdf_open_image_stream(ctx, doc, num, NULL, 1);
527
2.30k
}
528
529
fz_stream *
530
pdf_open_stream_with_offset(fz_context *ctx, pdf_document *doc, int num, pdf_obj *dict, int64_t stm_ofs)
531
27
{
532
27
  if (stm_ofs == 0)
533
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
534
27
  return pdf_open_filter(ctx, doc, doc->file, dict, num, stm_ofs, NULL, 1);
535
27
}
536
537
void
538
pdf_internalize_external_stream(fz_context *ctx, pdf_document *doc, int num)
539
0
{
540
0
  fz_stream *stm = NULL;
541
0
  pdf_obj *dict, *f;
542
0
  fz_buffer *buf = NULL;
543
0
  pdf_xref_entry *x = NULL;
544
0
  const char *filename = NULL;
545
546
0
  if (num <= 0 || num >= pdf_xref_len(ctx, doc))
547
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Object number ouf of range");
548
549
0
  x = pdf_get_xref_entry_no_null(ctx, doc, num);
550
0
  if (x->stm_buf)
551
0
    return;
552
553
0
  dict = pdf_load_object(ctx, doc, num);
554
555
0
  fz_var(stm);
556
557
0
  fz_try(ctx)
558
0
  {
559
0
    f = pdf_dict_get(ctx, dict, PDF_NAME(F));
560
0
    if (pdf_is_string(ctx, f))
561
0
      filename = pdf_to_text_string(ctx, f);
562
0
    else if (pdf_is_filespec(ctx, f))
563
0
    {
564
0
      pdf_filespec_params fs;
565
0
      pdf_get_filespec_params(ctx, f, &fs);
566
0
      filename = fs.filename;
567
0
    }
568
0
    else
569
0
      fz_throw(ctx, FZ_ERROR_ARGUMENT, "Not an external stream");
570
571
0
    if (doc->archive == NULL)
572
0
    {
573
0
      fz_warn(ctx, "Cannot open external file resource without an archive");
574
0
      break;
575
0
    }
576
0
    stm = fz_open_archive_entry(ctx, doc->archive, filename);
577
578
0
    x->stm_buf = buf = fz_read_all(ctx, stm, 1024);
579
580
0
    f = pdf_dict_get(ctx, dict, PDF_NAME(FFilter));
581
0
    if (f == NULL)
582
0
      pdf_dict_del(ctx, dict, PDF_NAME(Filter));
583
0
    else
584
0
      pdf_dict_put(ctx, dict, PDF_NAME(Filter), f);
585
0
    pdf_dict_del(ctx, dict, PDF_NAME(FFilter));
586
0
    f = pdf_dict_get(ctx, dict, PDF_NAME(FDecodeParms));
587
0
    if (f == NULL)
588
0
      pdf_dict_del(ctx, dict, PDF_NAME(DecodeParms));
589
0
    else
590
0
      pdf_dict_put(ctx, dict, PDF_NAME(DecodeParms), f);
591
0
    pdf_dict_del(ctx, dict, PDF_NAME(FDecodeParms));
592
0
    pdf_dict_del(ctx, dict, PDF_NAME(F));
593
0
  }
594
0
  fz_always(ctx)
595
0
  {
596
0
    fz_drop_stream(ctx, stm);
597
0
    pdf_drop_obj(ctx, dict);
598
0
  }
599
0
  fz_catch(ctx)
600
0
    fz_rethrow(ctx);
601
0
}
602
603
fz_buffer *
604
pdf_load_raw_stream_number(fz_context *ctx, pdf_document *doc, int num)
605
0
{
606
0
  fz_stream *stm;
607
0
  pdf_obj *dict;
608
0
  int64_t len;
609
0
  fz_buffer *buf = NULL;
610
0
  pdf_xref_entry *x;
611
612
0
  if (num > 0 && num < pdf_xref_len(ctx, doc))
613
0
  {
614
0
    x = pdf_get_xref_entry_no_null(ctx, doc, num);
615
0
    if (x->stm_buf)
616
0
      return fz_keep_buffer(ctx, x->stm_buf);
617
0
  }
618
619
0
  dict = pdf_load_object(ctx, doc, num);
620
621
0
  fz_try(ctx)
622
0
    len = pdf_stream_length(ctx, doc, dict);
623
0
  fz_always(ctx)
624
0
    pdf_drop_obj(ctx, dict);
625
0
  fz_catch(ctx)
626
0
    fz_rethrow(ctx);
627
628
0
  stm = pdf_open_raw_stream_number(ctx, doc, num);
629
630
0
  fz_try(ctx)
631
0
    buf = fz_read_all(ctx, stm, (size_t)len);
632
0
  fz_always(ctx)
633
0
    fz_drop_stream(ctx, stm);
634
0
  fz_catch(ctx)
635
0
    fz_rethrow(ctx);
636
637
0
  return buf;
638
0
}
639
640
static size_t
641
pdf_guess_filter_length(size_t len, const char *filter)
642
3.76k
{
643
3.76k
  size_t nlen = len;
644
645
  /* First ones get smaller, no overflow check required. */
646
3.76k
  if (!strcmp(filter, "ASCIIHexDecode"))
647
0
    return len / 2;
648
3.76k
  else if (!strcmp(filter, "ASCII85Decode"))
649
0
    return len * 4 / 5;
650
651
3.76k
  if (!strcmp(filter, "FlateDecode"))
652
3.64k
    nlen = len * 3;
653
125
  else if (!strcmp(filter, "BrotliDecode"))
654
0
    nlen = len * 4;
655
125
  else if (!strcmp(filter, "RunLengthDecode"))
656
0
    nlen = len * 3;
657
125
  else if (!strcmp(filter, "LZWDecode"))
658
0
    nlen = len * 2;
659
660
  /* Live with a bad estimate - we'll malloc up as we go, but
661
   * it's probably destined to fail anyway. */
662
3.76k
  if (nlen < len)
663
0
    return len;
664
665
3.76k
  return nlen;
666
3.76k
}
667
668
/* Check if an entry has a cached stream and return whether it is directly
669
 * reusable. A buffer is directly reusable only if the stream is
670
 * uncompressed, or if it is compressed purely a compression method we can
671
 * return details of in fz_compression_params.
672
 *
673
 * If the stream is reusable return 1, and set params as required, otherwise
674
 * return 0. */
675
static int
676
can_reuse_buffer(fz_context *ctx, pdf_xref_entry *entry, fz_compression_params *params)
677
3.76k
{
678
3.76k
  pdf_obj *f;
679
3.76k
  pdf_obj *p;
680
681
3.76k
  if (!entry || !entry->obj || !entry->stm_buf)
682
3.76k
    return 0;
683
684
0
  if (params)
685
0
    params->type = FZ_IMAGE_RAW;
686
687
0
  f = pdf_dict_geta(ctx, entry->obj, PDF_NAME(Filter), PDF_NAME(F));
688
  /* If there are no filters, it's uncompressed, and we can use it */
689
0
  if (!f)
690
0
    return 1;
691
692
0
  p = pdf_dict_geta(ctx, entry->obj, PDF_NAME(DecodeParms), PDF_NAME(DP));
693
0
  if (pdf_is_array(ctx, f))
694
0
  {
695
0
    int len = pdf_array_len(ctx, f);
696
697
    /* Empty array of filters. Its uncompressed. We can cope. */
698
0
    if (len == 0)
699
0
      return 1;
700
    /* 1 filter is the most we can hope to cope with - if more,*/
701
0
    if (len != 1)
702
0
      return 0;
703
0
    p = pdf_array_get(ctx, p, 0);
704
0
  }
705
0
  if (pdf_is_null(ctx, f))
706
0
    return 1; /* Null filter is uncompressed */
707
0
  if (!pdf_is_name(ctx, f))
708
0
    return 0;
709
710
  /* There are filters, so unless we have the option of shortstopping,
711
   * we can't use the existing buffer. */
712
0
  if (!params)
713
0
    return 0;
714
715
0
  build_compression_params(ctx, f, p, params);
716
717
0
  return (params->type == FZ_IMAGE_RAW) ? 0 : 1;
718
0
}
719
720
fz_buffer *
721
pdf_load_image_stream(fz_context *ctx, pdf_document *doc, int num, fz_compression_params *params, int *truncated, size_t worst_case)
722
3.76k
{
723
3.76k
  fz_stream *stm = NULL;
724
3.76k
  pdf_obj *dict, *obj;
725
3.76k
  int i, n;
726
3.76k
  size_t len;
727
3.76k
  fz_buffer *buf;
728
729
3.76k
  fz_var(buf);
730
731
3.76k
  if (num > 0 && num < pdf_xref_len(ctx, doc))
732
3.76k
  {
733
3.76k
    pdf_xref_entry *entry = pdf_get_xref_entry(ctx, doc, num);
734
    /* Return ref to existing buffer, but only if uncompressed,
735
     * or shortstoppable */
736
3.76k
    if (can_reuse_buffer(ctx, entry, params))
737
0
      return fz_keep_buffer(ctx, entry->stm_buf);
738
3.76k
  }
739
740
3.76k
  dict = pdf_load_object(ctx, doc, num);
741
7.52k
  fz_try(ctx)
742
7.52k
  {
743
3.76k
    int64_t ilen = pdf_stream_length(ctx, doc, dict);
744
745
    /* In 32 bit builds, we might find a length being too large for a size_t. */
746
3.76k
    len = (size_t)ilen;
747
3.76k
    if ((int64_t)len != ilen)
748
0
      fz_throw(ctx, FZ_ERROR_LIMIT, "stream is too large for 32-bit systems");
749
750
3.76k
    if (pdf_is_stream_external(ctx, dict))
751
0
      obj = pdf_dict_get(ctx, dict, PDF_NAME(FFilter));
752
3.76k
    else
753
3.76k
      obj = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
754
3.76k
    len = pdf_guess_filter_length(len, pdf_to_name(ctx, obj));
755
3.76k
    n = pdf_array_len(ctx, obj);
756
3.76k
    for (i = 0; i < n; i++)
757
5
      len = pdf_guess_filter_length(len, pdf_array_get_name(ctx, obj, i));
758
3.76k
    if (worst_case == 0 && pdf_name_eq(ctx, pdf_dict_get(ctx, dict, PDF_NAME(Subtype)), PDF_NAME(Image)))
759
4
    {
760
4
      int64_t w = pdf_dict_get_int64(ctx, dict, PDF_NAME(Width));
761
4
      int64_t h = pdf_dict_get_int64(ctx, dict, PDF_NAME(Height));
762
4
      int bpc = pdf_dict_get_int_default(ctx, dict, PDF_NAME(BitsPerComponent), 8);
763
4
      int nc = pdf_guess_colorspace_components(ctx, pdf_dict_get(ctx, dict, PDF_NAME(ColorSpace)));
764
4
      if (w > 0 && h > 0 && bpc > 0 && nc > 0)
765
1
      {
766
1
        worst_case = (size_t)(((w * nc * bpc + 7) >> 3) * h);
767
1
        if (worst_case < len)
768
1
          worst_case = len;
769
1
      }
770
4
    }
771
3.76k
  }
772
7.52k
  fz_always(ctx)
773
3.76k
  {
774
3.76k
    pdf_drop_obj(ctx, dict);
775
3.76k
  }
776
3.76k
  fz_catch(ctx)
777
0
  {
778
0
    fz_rethrow(ctx);
779
0
  }
780
781
3.76k
  stm = pdf_open_image_stream(ctx, doc, num, params, 1);
782
783
7.52k
  fz_try(ctx)
784
7.52k
  {
785
3.76k
    buf = fz_read_best(ctx, stm, len, truncated, worst_case);
786
3.76k
  }
787
7.52k
  fz_always(ctx)
788
3.76k
  {
789
3.76k
    fz_drop_stream(ctx, stm);
790
3.76k
  }
791
3.76k
  fz_catch(ctx)
792
0
  {
793
0
    fz_rethrow(ctx);
794
0
  }
795
796
3.76k
  return buf;
797
3.76k
}
798
799
fz_buffer *
800
pdf_load_stream_number(fz_context *ctx, pdf_document *doc, int num)
801
700
{
802
700
  return pdf_load_image_stream(ctx, doc, num, NULL, NULL, 0);
803
700
}
804
805
fz_compressed_buffer *
806
pdf_load_compressed_stream(fz_context *ctx, pdf_document *doc, int num, size_t worst_case)
807
3.06k
{
808
3.06k
  fz_compressed_buffer *bc = fz_new_compressed_buffer(ctx);
809
810
6.12k
  fz_try(ctx)
811
6.12k
  {
812
3.06k
    bc->buffer = pdf_load_image_stream(ctx, doc, num, &bc->params, NULL, worst_case);
813
3.06k
  }
814
6.12k
  fz_catch(ctx)
815
0
  {
816
0
    fz_free(ctx, bc);
817
0
    fz_rethrow(ctx);
818
0
  }
819
3.06k
  return bc;
820
3.06k
}
821
822
static fz_stream *
823
pdf_open_object_array(fz_context *ctx, pdf_document *doc, pdf_obj *list)
824
12
{
825
12
  fz_stream *stm;
826
12
  int i, n;
827
828
12
  n = pdf_array_len(ctx, list);
829
12
  stm = fz_open_concat(ctx, n, 1);
830
831
94
  for (i = 0; i < n; i++)
832
82
  {
833
82
    pdf_obj *obj = pdf_array_get(ctx, list, i);
834
164
    fz_try(ctx)
835
164
      fz_concat_push_drop(ctx, stm, pdf_open_image_stream(ctx, doc, pdf_to_num(ctx, obj), NULL, 0));
836
164
    fz_catch(ctx)
837
3
    {
838
3
      if (fz_caught(ctx) == FZ_ERROR_TRYLATER || fz_caught(ctx) == FZ_ERROR_SYSTEM)
839
0
      {
840
0
        fz_drop_stream(ctx, stm);
841
0
        fz_rethrow(ctx);
842
0
      }
843
3
      fz_report_error(ctx);
844
3
      fz_warn(ctx, "cannot load content stream part %d/%d", i + 1, n);
845
3
    }
846
82
  }
847
848
12
  return stm;
849
12
}
850
851
fz_stream *
852
pdf_open_contents_stream(fz_context *ctx, pdf_document *doc, pdf_obj *obj)
853
6.46k
{
854
6.46k
  int num;
855
856
6.46k
  if (pdf_is_array(ctx, obj))
857
12
    return pdf_open_object_array(ctx, doc, obj);
858
859
6.45k
  num = pdf_to_num(ctx, obj);
860
6.45k
  if (pdf_is_stream(ctx, obj))
861
6.44k
    return pdf_open_image_stream(ctx, doc, num, NULL, 0);
862
863
4
  fz_warn(ctx, "content stream is not a stream (%d 0 R)", num);
864
4
  return fz_open_memory(ctx, (unsigned char *)"", 0);
865
6.45k
}
866
867
fz_buffer *pdf_load_raw_stream(fz_context *ctx, pdf_obj *ref)
868
0
{
869
0
  if (pdf_is_stream(ctx, ref))
870
0
    return pdf_load_raw_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
871
0
  fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
872
0
}
873
874
fz_buffer *pdf_load_stream(fz_context *ctx, pdf_obj *ref)
875
919
{
876
919
  if (pdf_is_stream(ctx, ref))
877
700
    return pdf_load_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
878
219
  fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
879
919
}
880
881
fz_stream *pdf_open_raw_stream(fz_context *ctx, pdf_obj *ref)
882
0
{
883
0
  if (pdf_is_stream(ctx, ref))
884
0
    return pdf_open_raw_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
885
0
  fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
886
0
}
887
888
fz_stream *pdf_open_stream(fz_context *ctx, pdf_obj *ref)
889
2.05k
{
890
2.05k
  if (pdf_is_stream(ctx, ref))
891
2.05k
    return pdf_open_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
892
2
  fz_throw(ctx, FZ_ERROR_FORMAT, "object is not a stream");
893
2.05k
}