1#include "mupdf/fitz.h"
2#include "mupdf/pdf.h"
3
4#include <string.h>
5
6/*
7 * Check if an object is a stream or not.
8 */
9int
10pdf_obj_num_is_stream(fz_context *ctx, pdf_document *doc, int num)
11{
12 pdf_xref_entry *entry;
13
14 if (num <= 0 || num >= pdf_xref_len(ctx, doc))
15 return 0;
16
17 fz_try(ctx)
18 entry = pdf_cache_object(ctx, doc, num);
19 fz_catch(ctx)
20 {
21 fz_rethrow_if(ctx, FZ_ERROR_TRYLATER);
22 return 0;
23 }
24
25 return entry->stm_ofs != 0 || entry->stm_buf;
26}
27
28int
29pdf_is_stream(fz_context *ctx, pdf_obj *ref)
30{
31 pdf_document *doc = pdf_get_indirect_document(ctx, ref);
32 if (doc)
33 return pdf_obj_num_is_stream(ctx, doc, pdf_to_num(ctx, ref));
34 return 0;
35}
36
37/*
38 * Scan stream dictionary for an explicit /Crypt filter
39 */
40static int
41pdf_stream_has_crypt(fz_context *ctx, pdf_obj *stm)
42{
43 pdf_obj *filters;
44 pdf_obj *obj;
45 int i;
46
47 filters = pdf_dict_geta(ctx, stm, PDF_NAME(Filter), PDF_NAME(F));
48 if (filters)
49 {
50 if (pdf_name_eq(ctx, filters, PDF_NAME(Crypt)))
51 return 1;
52 if (pdf_is_array(ctx, filters))
53 {
54 int n = pdf_array_len(ctx, filters);
55 for (i = 0; i < n; i++)
56 {
57 obj = pdf_array_get(ctx, filters, i);
58 if (pdf_name_eq(ctx, obj, PDF_NAME(Crypt)))
59 return 1;
60 }
61 }
62 }
63 return 0;
64}
65
66static fz_jbig2_globals *
67pdf_load_jbig2_globals(fz_context *ctx, pdf_obj *dict)
68{
69 fz_jbig2_globals *globals;
70 fz_buffer *buf = NULL;
71
72 fz_var(buf);
73
74 if ((globals = pdf_find_item(ctx, fz_drop_jbig2_globals_imp, dict)) != NULL)
75 return globals;
76
77 if (pdf_mark_obj(ctx, dict))
78 fz_throw(ctx, FZ_ERROR_GENERIC, "cyclic reference when loading JBIG2 globals");
79
80 fz_try(ctx)
81 {
82 buf = pdf_load_stream(ctx, dict);
83 globals = fz_load_jbig2_globals(ctx, buf);
84 pdf_store_item(ctx, dict, globals, fz_buffer_storage(ctx, buf, NULL));
85 }
86 fz_always(ctx)
87 {
88 fz_drop_buffer(ctx, buf);
89 pdf_unmark_obj(ctx, dict);
90 }
91 fz_catch(ctx)
92 {
93 fz_rethrow(ctx);
94 }
95
96 return globals;
97}
98
99static void
100build_compression_params(fz_context *ctx, pdf_obj *f, pdf_obj *p, fz_compression_params *params)
101{
102 int predictor = pdf_dict_get_int(ctx, p, PDF_NAME(Predictor));
103 pdf_obj *columns_obj = pdf_dict_get(ctx, p, PDF_NAME(Columns));
104 int columns = pdf_to_int(ctx, columns_obj);
105 int colors = pdf_dict_get_int(ctx, p, PDF_NAME(Colors));
106 int bpc = pdf_dict_get_int(ctx, p, PDF_NAME(BitsPerComponent));
107
108 params->type = FZ_IMAGE_RAW;
109
110 if (pdf_name_eq(ctx, f, PDF_NAME(CCITTFaxDecode)) || pdf_name_eq(ctx, f, PDF_NAME(CCF)))
111 {
112 pdf_obj *k = pdf_dict_get(ctx, p, PDF_NAME(K));
113 pdf_obj *eol = pdf_dict_get(ctx, p, PDF_NAME(EndOfLine));
114 pdf_obj *eba = pdf_dict_get(ctx, p, PDF_NAME(EncodedByteAlign));
115 pdf_obj *rows = pdf_dict_get(ctx, p, PDF_NAME(Rows));
116 pdf_obj *eob = pdf_dict_get(ctx, p, PDF_NAME(EndOfBlock));
117 pdf_obj *bi1 = pdf_dict_get(ctx, p, PDF_NAME(BlackIs1));
118
119 params->type = FZ_IMAGE_FAX;
120 params->u.fax.k = (k ? pdf_to_int(ctx, k) : 0);
121 params->u.fax.end_of_line = (eol ? pdf_to_bool(ctx, eol) : 0);
122 params->u.fax.encoded_byte_align = (eba ? pdf_to_bool(ctx, eba) : 0);
123 params->u.fax.columns = (columns_obj ? columns : 1728);
124 params->u.fax.rows = (rows ? pdf_to_int(ctx, rows) : 0);
125 params->u.fax.end_of_block = (eob ? pdf_to_bool(ctx, eob) : 1);
126 params->u.fax.black_is_1 = (bi1 ? pdf_to_bool(ctx, bi1) : 0);
127 }
128 else if (pdf_name_eq(ctx, f, PDF_NAME(DCTDecode)) || pdf_name_eq(ctx, f, PDF_NAME(DCT)))
129 {
130 pdf_obj *ct = pdf_dict_get(ctx, p, PDF_NAME(ColorTransform));
131
132 params->type = FZ_IMAGE_JPEG;
133 params->u.jpeg.color_transform = (ct ? pdf_to_int(ctx, ct) : -1);
134 }
135 else if (pdf_name_eq(ctx, f, PDF_NAME(RunLengthDecode)) || pdf_name_eq(ctx, f, PDF_NAME(RL)))
136 {
137 params->type = FZ_IMAGE_RLD;
138 }
139 else if (pdf_name_eq(ctx, f, PDF_NAME(FlateDecode)) || pdf_name_eq(ctx, f, PDF_NAME(Fl)))
140 {
141 params->type = FZ_IMAGE_FLATE;
142 params->u.flate.predictor = predictor;
143 params->u.flate.columns = columns;
144 params->u.flate.colors = colors;
145 params->u.flate.bpc = bpc;
146 }
147 else if (pdf_name_eq(ctx, f, PDF_NAME(LZWDecode)) || pdf_name_eq(ctx, f, PDF_NAME(LZW)))
148 {
149 pdf_obj *ec = pdf_dict_get(ctx, p, PDF_NAME(EarlyChange));
150
151 params->type = FZ_IMAGE_LZW;
152 params->u.lzw.predictor = predictor;
153 params->u.lzw.columns = columns;
154 params->u.lzw.colors = colors;
155 params->u.lzw.bpc = bpc;
156 params->u.lzw.early_change = (ec ? pdf_to_int(ctx, ec) : 1);
157 }
158 else if (pdf_name_eq(ctx, f, PDF_NAME(JBIG2Decode)))
159 {
160 pdf_obj *g = pdf_dict_get(ctx, p, PDF_NAME(JBIG2Globals));
161
162 params->type = FZ_IMAGE_JBIG2;
163 params->u.jbig2.globals = NULL;
164 if (g)
165 {
166 if (!pdf_is_stream(ctx, g))
167 fz_warn(ctx, "jbig2 globals is not a stream, skipping globals");
168 else
169 params->u.jbig2.globals = pdf_load_jbig2_globals(ctx, g);
170 }
171 }
172}
173
174/*
175 * Create a filter given a name and param dictionary.
176 */
177static fz_stream *
178build_filter(fz_context *ctx, fz_stream *chain, pdf_document *doc, pdf_obj *f, pdf_obj *p, int num, int gen, fz_compression_params *params)
179{
180 fz_compression_params local_params;
181
182 local_params.u.jbig2.globals = NULL;
183 if (params == NULL)
184 params = &local_params;
185
186 build_compression_params(ctx, f, p, params);
187
188 /* If we were using params we were passed in, and we successfully
189 * recognised the image type, we can use the existing filter and
190 * shortstop here. */
191 if (params != &local_params && params->type != FZ_IMAGE_RAW)
192 return fz_keep_stream(ctx, chain); /* nothing to do */
193
194 else if (params->type == FZ_IMAGE_JBIG2)
195 {
196 fz_stream *stm;
197 fz_try(ctx)
198 stm = fz_open_image_decomp_stream(ctx, chain, params, NULL);
199 fz_always(ctx)
200 fz_drop_jbig2_globals(ctx, local_params.u.jbig2.globals);
201 fz_catch(ctx)
202 fz_rethrow(ctx);
203 return stm;
204 }
205
206 else if (params->type != FZ_IMAGE_RAW)
207 return fz_open_image_decomp_stream(ctx, chain, params, NULL);
208
209 else if (pdf_name_eq(ctx, f, PDF_NAME(ASCIIHexDecode)) || pdf_name_eq(ctx, f, PDF_NAME(AHx)))
210 return fz_open_ahxd(ctx, chain);
211
212 else if (pdf_name_eq(ctx, f, PDF_NAME(ASCII85Decode)) || pdf_name_eq(ctx, f, PDF_NAME(A85)))
213 return fz_open_a85d(ctx, chain);
214
215 else if (pdf_name_eq(ctx, f, PDF_NAME(JPXDecode)))
216 return fz_keep_stream(ctx, chain); /* JPX decoding is special cased in the image loading code */
217
218 else if (pdf_name_eq(ctx, f, PDF_NAME(Crypt)))
219 {
220 if (!doc->crypt)
221 fz_warn(ctx, "crypt filter in unencrypted document");
222 else
223 {
224 pdf_obj *name = pdf_dict_get(ctx, p, PDF_NAME(Name));
225 if (pdf_is_name(ctx, name))
226 return pdf_open_crypt_with_filter(ctx, chain, doc->crypt, name, num, gen);
227 }
228 }
229
230 else
231 fz_warn(ctx, "unknown filter name (%s)", pdf_to_name(ctx, f));
232
233 return fz_keep_stream(ctx, chain);
234}
235
236/* Build filter, and assume ownership of chain */
237static fz_stream *
238build_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)
239{
240 fz_stream *head;
241 fz_try(ctx)
242 head = build_filter(ctx, tail, doc, f, p, num, gen, params);
243 fz_always(ctx)
244 fz_drop_stream(ctx, tail);
245 fz_catch(ctx)
246 fz_rethrow(ctx);
247 return head;
248}
249
250/*
251 * Build a chain of filters given filter names and param dicts.
252 * If chain is given, start filter chain with it.
253 * Assume ownership of chain.
254 */
255static fz_stream *
256build_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)
257{
258 fz_var(chain);
259 fz_try(ctx)
260 {
261 int i, n = pdf_array_len(ctx, fs);
262 for (i = 0; i < n; i++)
263 {
264 pdf_obj *f = pdf_array_get(ctx, fs, i);
265 pdf_obj *p = pdf_array_get(ctx, ps, i);
266 chain = build_filter_drop(ctx, chain, doc, f, p, num, gen, (i == n-1 ? params : NULL));
267 }
268 }
269 fz_catch(ctx)
270 fz_rethrow(ctx);
271 return chain;
272}
273
274static fz_stream *
275build_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)
276{
277 return build_filter_chain_drop(ctx, fz_keep_stream(ctx, chain), doc, fs, ps, num, gen, params);
278}
279
280/*
281 * Build a filter for reading raw stream data.
282 * This is a null filter to constrain reading to the stream length (and to
283 * allow for other people accessing the file), followed by a decryption
284 * filter.
285 *
286 * orig_num and orig_gen are used purely to seed the encryption.
287 */
288static fz_stream *
289pdf_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)
290{
291 pdf_xref_entry *x = NULL;
292 fz_stream *null_stm, *crypt_stm;
293 int hascrypt;
294 int len;
295
296 if (num > 0 && num < pdf_xref_len(ctx, doc))
297 {
298 x = pdf_get_xref_entry(ctx, doc, num);
299 *orig_num = x->num;
300 *orig_gen = x->gen;
301 if (x->stm_buf)
302 return fz_open_buffer(ctx, x->stm_buf);
303 }
304 else
305 {
306 /* We only end up here when called from pdf_open_stream_with_offset to parse new format XRef sections. */
307 /* New style XRef sections must have generation number 0. */
308 *orig_num = num;
309 *orig_gen = 0;
310 }
311
312 hascrypt = pdf_stream_has_crypt(ctx, stmobj);
313 len = pdf_dict_get_int(ctx, stmobj, PDF_NAME(Length));
314 null_stm = fz_open_endstream_filter(ctx, file_stm, len, offset);
315 if (doc->crypt && !hascrypt)
316 {
317 fz_try(ctx)
318 crypt_stm = pdf_open_crypt(ctx, null_stm, doc->crypt, *orig_num, *orig_gen);
319 fz_always(ctx)
320 fz_drop_stream(ctx, null_stm);
321 fz_catch(ctx)
322 fz_rethrow(ctx);
323 return crypt_stm;
324 }
325 return null_stm;
326}
327
328/*
329 * Construct a filter to decode a stream, constraining
330 * to stream length and decrypting.
331 */
332static fz_stream *
333pdf_open_filter(fz_context *ctx, pdf_document *doc, fz_stream *file_stm, pdf_obj *stmobj, int num, int64_t offset, fz_compression_params *imparams)
334{
335 pdf_obj *filters = pdf_dict_geta(ctx, stmobj, PDF_NAME(Filter), PDF_NAME(F));
336 pdf_obj *params = pdf_dict_geta(ctx, stmobj, PDF_NAME(DecodeParms), PDF_NAME(DP));
337 int orig_num, orig_gen;
338 fz_stream *rstm, *fstm;
339
340 rstm = pdf_open_raw_filter(ctx, file_stm, doc, stmobj, num, &orig_num, &orig_gen, offset);
341 fz_try(ctx)
342 {
343 if (pdf_is_name(ctx, filters))
344 fstm = build_filter(ctx, rstm, doc, filters, params, orig_num, orig_gen, imparams);
345 else if (pdf_array_len(ctx, filters) > 0)
346 fstm = build_filter_chain(ctx, rstm, doc, filters, params, orig_num, orig_gen, imparams);
347 else
348 fstm = fz_keep_stream(ctx, rstm);
349 }
350 fz_always(ctx)
351 fz_drop_stream(ctx, rstm);
352 fz_catch(ctx)
353 fz_rethrow(ctx);
354
355 return fstm;
356}
357
358/*
359 * Construct a filter to decode a stream, without
360 * constraining to stream length, and without decryption.
361 */
362fz_stream *
363pdf_open_inline_stream(fz_context *ctx, pdf_document *doc, pdf_obj *stmobj, int length, fz_stream *file_stm, fz_compression_params *imparams)
364{
365 pdf_obj *filters = pdf_dict_geta(ctx, stmobj, PDF_NAME(Filter), PDF_NAME(F));
366 pdf_obj *params = pdf_dict_geta(ctx, stmobj, PDF_NAME(DecodeParms), PDF_NAME(DP));
367
368 if (pdf_is_name(ctx, filters))
369 return build_filter(ctx, file_stm, doc, filters, params, 0, 0, imparams);
370 else if (pdf_array_len(ctx, filters) > 0)
371 return build_filter_chain(ctx, file_stm, doc, filters, params, 0, 0, imparams);
372
373 if (imparams)
374 imparams->type = FZ_IMAGE_RAW;
375 return fz_open_null_filter(ctx, file_stm, length, fz_tell(ctx, file_stm));
376}
377
378void
379pdf_load_compressed_inline_image(fz_context *ctx, pdf_document *doc, pdf_obj *dict, int length, fz_stream *file_stm, int indexed, fz_compressed_image *image)
380{
381 fz_stream *istm = NULL, *leech = NULL, *decomp = NULL;
382 fz_pixmap *pixmap = NULL;
383 fz_compressed_buffer *bc;
384 int dummy_l2factor = 0;
385
386 fz_var(istm);
387 fz_var(leech);
388 fz_var(decomp);
389 fz_var(pixmap);
390
391 bc = fz_malloc_struct(ctx, fz_compressed_buffer);
392 fz_try(ctx)
393 {
394 bc->buffer = fz_new_buffer(ctx, 1024);
395 istm = pdf_open_inline_stream(ctx, doc, dict, length, file_stm, &bc->params);
396 leech = fz_open_leecher(ctx, istm, bc->buffer);
397 decomp = fz_open_image_decomp_stream(ctx, leech, &bc->params, &dummy_l2factor);
398 pixmap = fz_decomp_image_from_stream(ctx, decomp, image, NULL, indexed, 0);
399 fz_set_compressed_image_tile(ctx, image, pixmap);
400 fz_set_compressed_image_buffer(ctx, image, bc);
401 }
402 fz_always(ctx)
403 {
404 fz_drop_stream(ctx, istm);
405 fz_drop_stream(ctx, leech);
406 fz_drop_stream(ctx, decomp);
407 fz_drop_pixmap(ctx, pixmap);
408 }
409 fz_catch(ctx)
410 {
411 fz_drop_compressed_buffer(ctx, bc);
412 fz_rethrow(ctx);
413 }
414}
415
416/*
417 * Open a stream for reading the raw (compressed but decrypted) data.
418 */
419fz_stream *
420pdf_open_raw_stream_number(fz_context *ctx, pdf_document *doc, int num)
421{
422 pdf_xref_entry *x;
423 int orig_num, orig_gen;
424
425 if (num <= 0 || num >= pdf_xref_len(ctx, doc))
426 fz_throw(ctx, FZ_ERROR_GENERIC, "object id out of range (%d 0 R)", num);
427
428 x = pdf_cache_object(ctx, doc, num);
429 if (x->stm_ofs == 0)
430 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
431
432 return pdf_open_raw_filter(ctx, doc->file, doc, x->obj, num, &orig_num, &orig_gen, x->stm_ofs);
433}
434
435static fz_stream *
436pdf_open_image_stream(fz_context *ctx, pdf_document *doc, int num, fz_compression_params *params)
437{
438 pdf_xref_entry *x;
439
440 if (num <= 0 || num >= pdf_xref_len(ctx, doc))
441 fz_throw(ctx, FZ_ERROR_GENERIC, "object id out of range (%d 0 R)", num);
442
443 x = pdf_cache_object(ctx, doc, num);
444 if (x->stm_ofs == 0 && x->stm_buf == NULL)
445 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
446
447 return pdf_open_filter(ctx, doc, doc->file, x->obj, num, x->stm_ofs, params);
448}
449
450/*
451 * Open a stream for reading uncompressed data.
452 * Put the opened file in doc->stream.
453 * Using doc->file while a stream is open is a Bad idea.
454 */
455fz_stream *
456pdf_open_stream_number(fz_context *ctx, pdf_document *doc, int num)
457{
458 return pdf_open_image_stream(ctx, doc, num, NULL);
459}
460
461fz_stream *
462pdf_open_stream_with_offset(fz_context *ctx, pdf_document *doc, int num, pdf_obj *dict, int64_t stm_ofs)
463{
464 if (stm_ofs == 0)
465 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
466 return pdf_open_filter(ctx, doc, doc->file, dict, num, stm_ofs, NULL);
467}
468
469/*
470 * Load raw (compressed but decrypted) contents of a stream into buf.
471 */
472fz_buffer *
473pdf_load_raw_stream_number(fz_context *ctx, pdf_document *doc, int num)
474{
475 fz_stream *stm;
476 pdf_obj *dict;
477 int len;
478 fz_buffer *buf = NULL;
479 pdf_xref_entry *x;
480
481 if (num > 0 && num < pdf_xref_len(ctx, doc))
482 {
483 x = pdf_get_xref_entry(ctx, doc, num);
484 if (x->stm_buf)
485 return fz_keep_buffer(ctx, x->stm_buf);
486 }
487
488 dict = pdf_load_object(ctx, doc, num);
489
490 fz_try(ctx)
491 len = pdf_dict_get_int(ctx, dict, PDF_NAME(Length));
492 fz_always(ctx)
493 pdf_drop_obj(ctx, dict);
494 fz_catch(ctx)
495 fz_rethrow(ctx);
496
497 stm = pdf_open_raw_stream_number(ctx, doc, num);
498
499 fz_try(ctx)
500 buf = fz_read_all(ctx, stm, len);
501 fz_always(ctx)
502 fz_drop_stream(ctx, stm);
503 fz_catch(ctx)
504 fz_rethrow(ctx);
505
506 return buf;
507}
508
509static int
510pdf_guess_filter_length(int len, const char *filter)
511{
512 if (!strcmp(filter, "ASCIIHexDecode"))
513 return len / 2;
514 if (!strcmp(filter, "ASCII85Decode"))
515 return len * 4 / 5;
516 if (!strcmp(filter, "FlateDecode"))
517 return len * 3;
518 if (!strcmp(filter, "RunLengthDecode"))
519 return len * 3;
520 if (!strcmp(filter, "LZWDecode"))
521 return len * 2;
522 return len;
523}
524
525/* Check if an entry has a cached stream and return whether it is directly
526 * reusable. A buffer is directly reusable only if the stream is
527 * uncompressed, or if it is compressed purely a compression method we can
528 * return details of in fz_compression_params.
529 *
530 * If the stream is reusable return 1, and set params as required, otherwise
531 * return 0. */
532static int
533can_reuse_buffer(fz_context *ctx, pdf_xref_entry *entry, fz_compression_params *params)
534{
535 pdf_obj *f;
536 pdf_obj *p;
537
538 if (!entry || !entry->obj || !entry->stm_buf)
539 return 0;
540
541 if (params)
542 params->type = FZ_IMAGE_RAW;
543
544 f = pdf_dict_geta(ctx, entry->obj, PDF_NAME(Filter), PDF_NAME(F));
545 /* If there are no filters, it's uncompressed, and we can use it */
546 if (!f)
547 return 1;
548
549 p = pdf_dict_geta(ctx, entry->obj, PDF_NAME(DecodeParms), PDF_NAME(DP));
550 if (pdf_is_array(ctx, f))
551 {
552 int len = pdf_array_len(ctx, f);
553
554 /* Empty array of filters. Its uncompressed. We can cope. */
555 if (len == 0)
556 return 1;
557 /* 1 filter is the most we can hope to cope with - if more,*/
558 if (len != 1)
559 return 0;
560 p = pdf_array_get(ctx, p, 0);
561 }
562 if (pdf_is_null(ctx, f))
563 return 1; /* Null filter is uncompressed */
564 if (!pdf_is_name(ctx, f))
565 return 0;
566
567 /* There are filters, so unless we have the option of shortstopping,
568 * we can't use the existing buffer. */
569 if (!params)
570 return 0;
571
572 build_compression_params(ctx, f, p, params);
573
574 return (params->type == FZ_IMAGE_RAW) ? 0 : 1;
575}
576
577static fz_buffer *
578pdf_load_image_stream(fz_context *ctx, pdf_document *doc, int num, fz_compression_params *params, int *truncated)
579{
580 fz_stream *stm = NULL;
581 pdf_obj *dict, *obj;
582 int i, len, n;
583 fz_buffer *buf;
584
585 fz_var(buf);
586
587 if (num > 0 && num < pdf_xref_len(ctx, doc))
588 {
589 pdf_xref_entry *entry = pdf_get_xref_entry(ctx, doc, num);
590 /* Return ref to existing buffer, but only if uncompressed,
591 * or shortstoppable */
592 if (can_reuse_buffer(ctx, entry, params))
593 return fz_keep_buffer(ctx, entry->stm_buf);
594 }
595
596 dict = pdf_load_object(ctx, doc, num);
597 fz_try(ctx)
598 {
599 len = pdf_dict_get_int(ctx, dict, PDF_NAME(Length));
600 obj = pdf_dict_get(ctx, dict, PDF_NAME(Filter));
601 len = pdf_guess_filter_length(len, pdf_to_name(ctx, obj));
602 n = pdf_array_len(ctx, obj);
603 for (i = 0; i < n; i++)
604 len = pdf_guess_filter_length(len, pdf_to_name(ctx, pdf_array_get(ctx, obj, i)));
605 }
606 fz_always(ctx)
607 {
608 pdf_drop_obj(ctx, dict);
609 }
610 fz_catch(ctx)
611 {
612 fz_rethrow(ctx);
613 }
614
615 stm = pdf_open_image_stream(ctx, doc, num, params);
616
617 fz_try(ctx)
618 {
619 if (truncated)
620 buf = fz_read_best(ctx, stm, len, truncated);
621 else
622 buf = fz_read_all(ctx, stm, len);
623 }
624 fz_always(ctx)
625 {
626 fz_drop_stream(ctx, stm);
627 }
628 fz_catch(ctx)
629 {
630 fz_rethrow(ctx);
631 }
632
633 return buf;
634}
635
636/*
637 * Load uncompressed contents of a stream into buf.
638 */
639fz_buffer *
640pdf_load_stream_number(fz_context *ctx, pdf_document *doc, int num)
641{
642 return pdf_load_image_stream(ctx, doc, num, NULL, NULL);
643}
644
645fz_compressed_buffer *
646pdf_load_compressed_stream(fz_context *ctx, pdf_document *doc, int num)
647{
648 fz_compressed_buffer *bc = fz_malloc_struct(ctx, fz_compressed_buffer);
649
650 fz_try(ctx)
651 {
652 bc->buffer = pdf_load_image_stream(ctx, doc, num, &bc->params, NULL);
653 }
654 fz_catch(ctx)
655 {
656 fz_free(ctx, bc);
657 fz_rethrow(ctx);
658 }
659 return bc;
660}
661
662static fz_stream *
663pdf_open_object_array(fz_context *ctx, pdf_document *doc, pdf_obj *list)
664{
665 fz_stream *stm;
666 int i, n;
667
668 n = pdf_array_len(ctx, list);
669 stm = fz_open_concat(ctx, n, 1);
670
671 for (i = 0; i < n; i++)
672 {
673 pdf_obj *obj = pdf_array_get(ctx, list, i);
674 fz_try(ctx)
675 fz_concat_push_drop(ctx, stm, pdf_open_stream(ctx, obj));
676 fz_catch(ctx)
677 {
678 if (fz_caught(ctx) == FZ_ERROR_TRYLATER)
679 {
680 fz_drop_stream(ctx, stm);
681 fz_rethrow(ctx);
682 }
683 fz_warn(ctx, "cannot load content stream part %d/%d", i + 1, n);
684 }
685 }
686
687 return stm;
688}
689
690fz_stream *
691pdf_open_contents_stream(fz_context *ctx, pdf_document *doc, pdf_obj *obj)
692{
693 int num;
694
695 if (pdf_is_array(ctx, obj))
696 return pdf_open_object_array(ctx, doc, obj);
697
698 num = pdf_to_num(ctx, obj);
699 if (pdf_is_stream(ctx, obj))
700 return pdf_open_image_stream(ctx, doc, num, NULL);
701
702 fz_warn(ctx, "content stream is not a stream (%d 0 R)", num);
703 return fz_open_memory(ctx, (unsigned char *)"", 0);
704}
705
706fz_buffer *pdf_load_raw_stream(fz_context *ctx, pdf_obj *ref)
707{
708 if (pdf_is_stream(ctx, ref))
709 return pdf_load_raw_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
710 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
711}
712
713fz_buffer *pdf_load_stream(fz_context *ctx, pdf_obj *ref)
714{
715 if (pdf_is_stream(ctx, ref))
716 return pdf_load_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
717 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
718}
719
720fz_stream *pdf_open_raw_stream(fz_context *ctx, pdf_obj *ref)
721{
722 if (pdf_is_stream(ctx, ref))
723 return pdf_open_raw_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
724 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
725}
726
727fz_stream *pdf_open_stream(fz_context *ctx, pdf_obj *ref)
728{
729 if (pdf_is_stream(ctx, ref))
730 return pdf_open_stream_number(ctx, pdf_get_indirect_document(ctx, ref), pdf_to_num(ctx, ref));
731 fz_throw(ctx, FZ_ERROR_GENERIC, "object is not a stream");
732}
733