Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | #include "mupdf.h" |
||
3 | |||
4 | /* |
||
5 | * Check if an object is a stream or not. |
||
6 | */ |
||
7 | int |
||
8 | pdf_is_stream(pdf_xref *xref, int num, int gen) |
||
9 | { |
||
10 | fz_error error; |
||
11 | |||
12 | if (num < 0 || num >= xref->len) |
||
13 | return 0; |
||
14 | |||
15 | error = pdf_cache_object(xref, num, gen); |
||
16 | if (error) |
||
17 | { |
||
18 | fz_catch(error, "cannot load object, ignoring error"); |
||
19 | return 0; |
||
20 | } |
||
21 | |||
22 | return xref->table[num].stm_ofs > 0; |
||
23 | } |
||
24 | |||
25 | /* |
||
26 | * Scan stream dictionary for an explicit /Crypt filter |
||
27 | */ |
||
28 | static int |
||
29 | pdf_stream_has_crypt(fz_obj *stm) |
||
30 | { |
||
31 | fz_obj *filters; |
||
32 | fz_obj *obj; |
||
33 | int i; |
||
34 | |||
35 | filters = fz_dict_getsa(stm, "Filter", "F"); |
||
36 | if (filters) |
||
37 | { |
||
38 | if (!strcmp(fz_to_name(filters), "Crypt")) |
||
39 | return 1; |
||
40 | if (fz_is_array(filters)) |
||
41 | { |
||
42 | for (i = 0; i < fz_array_len(filters); i++) |
||
43 | { |
||
44 | obj = fz_array_get(filters, i); |
||
45 | if (!strcmp(fz_to_name(obj), "Crypt")) |
||
46 | return 1; |
||
47 | } |
||
48 | } |
||
49 | } |
||
50 | return 0; |
||
51 | } |
||
52 | |||
53 | /* |
||
54 | * Create a filter given a name and param dictionary. |
||
55 | */ |
||
56 | static fz_stream * |
||
57 | build_filter(fz_stream *chain, pdf_xref * xref, fz_obj * f, fz_obj * p, int num, int gen) |
||
58 | { |
||
59 | fz_error error; |
||
60 | char *s; |
||
61 | |||
62 | s = fz_to_name(f); |
||
63 | |||
64 | if (!strcmp(s, "ASCIIHexDecode") || !strcmp(s, "AHx")) |
||
65 | return fz_open_ahxd(chain); |
||
66 | |||
67 | else if (!strcmp(s, "ASCII85Decode") || !strcmp(s, "A85")) |
||
68 | return fz_open_a85d(chain); |
||
69 | |||
70 | else if (!strcmp(s, "CCITTFaxDecode") || !strcmp(s, "CCF")) |
||
71 | return fz_open_faxd(chain, p); |
||
72 | |||
73 | else if (!strcmp(s, "DCTDecode") || !strcmp(s, "DCT")) |
||
74 | return fz_open_dctd(chain, p); |
||
75 | |||
76 | else if (!strcmp(s, "RunLengthDecode") || !strcmp(s, "RL")) |
||
77 | return fz_open_rld(chain); |
||
78 | |||
79 | else if (!strcmp(s, "FlateDecode") || !strcmp(s, "Fl")) |
||
80 | { |
||
81 | fz_obj *obj = fz_dict_gets(p, "Predictor"); |
||
82 | if (fz_to_int(obj) > 1) |
||
83 | return fz_open_predict(fz_open_flated(chain), p); |
||
84 | return fz_open_flated(chain); |
||
85 | } |
||
86 | |||
87 | else if (!strcmp(s, "LZWDecode") || !strcmp(s, "LZW")) |
||
88 | { |
||
89 | fz_obj *obj = fz_dict_gets(p, "Predictor"); |
||
90 | if (fz_to_int(obj) > 1) |
||
91 | return fz_open_predict(fz_open_lzwd(chain, p), p); |
||
92 | return fz_open_lzwd(chain, p); |
||
93 | } |
||
94 | |||
95 | else if (!strcmp(s, "JBIG2Decode")) |
||
96 | { |
||
97 | fz_obj *obj = fz_dict_gets(p, "JBIG2Globals"); |
||
98 | if (obj) |
||
99 | { |
||
100 | fz_buffer *globals; |
||
101 | error = pdf_load_stream(&globals, xref, fz_to_num(obj), fz_to_gen(obj)); |
||
102 | if (error) |
||
103 | fz_catch(error, "cannot load jbig2 global segments"); |
||
104 | chain = fz_open_jbig2d(chain, globals); |
||
105 | fz_drop_buffer(globals); |
||
106 | return chain; |
||
107 | } |
||
108 | return fz_open_jbig2d(chain, NULL); |
||
109 | } |
||
110 | |||
111 | else if (!strcmp(s, "JPXDecode")) |
||
112 | return chain; /* JPX decoding is special cased in the image loading code */ |
||
113 | |||
114 | else if (!strcmp(s, "Crypt")) |
||
115 | { |
||
116 | fz_obj *name; |
||
117 | |||
118 | if (!xref->crypt) |
||
119 | { |
||
120 | fz_warn("crypt filter in unencrypted document"); |
||
121 | return chain; |
||
122 | } |
||
123 | |||
124 | name = fz_dict_gets(p, "Name"); |
||
125 | if (fz_is_name(name)) |
||
126 | return pdf_open_crypt_with_filter(chain, xref->crypt, fz_to_name(name), num, gen); |
||
127 | |||
128 | return chain; |
||
129 | } |
||
130 | |||
131 | fz_warn("unknown filter name (%s)", s); |
||
132 | return chain; |
||
133 | } |
||
134 | |||
135 | /* |
||
136 | * Build a chain of filters given filter names and param dicts. |
||
137 | * If head is given, start filter chain with it. |
||
138 | * Assume ownership of head. |
||
139 | */ |
||
140 | static fz_stream * |
||
141 | build_filter_chain(fz_stream *chain, pdf_xref *xref, fz_obj *fs, fz_obj *ps, int num, int gen) |
||
142 | { |
||
143 | fz_obj *f; |
||
144 | fz_obj *p; |
||
145 | int i; |
||
146 | |||
147 | for (i = 0; i < fz_array_len(fs); i++) |
||
148 | { |
||
149 | f = fz_array_get(fs, i); |
||
150 | p = fz_array_get(ps, i); |
||
151 | chain = build_filter(chain, xref, f, p, num, gen); |
||
152 | } |
||
153 | |||
154 | return chain; |
||
155 | } |
||
156 | |||
157 | /* |
||
158 | * Build a filter for reading raw stream data. |
||
159 | * This is a null filter to constrain reading to the |
||
160 | * stream length, followed by a decryption filter. |
||
161 | */ |
||
162 | static fz_stream * |
||
163 | pdf_open_raw_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen) |
||
164 | { |
||
165 | int hascrypt; |
||
166 | int len; |
||
167 | |||
168 | /* don't close chain when we close this filter */ |
||
169 | fz_keep_stream(chain); |
||
170 | |||
171 | len = fz_to_int(fz_dict_gets(stmobj, "Length")); |
||
172 | chain = fz_open_null(chain, len); |
||
173 | |||
174 | hascrypt = pdf_stream_has_crypt(stmobj); |
||
175 | if (xref->crypt && !hascrypt) |
||
176 | chain = pdf_open_crypt(chain, xref->crypt, num, gen); |
||
177 | |||
178 | return chain; |
||
179 | } |
||
180 | |||
181 | /* |
||
182 | * Construct a filter to decode a stream, constraining |
||
183 | * to stream length and decrypting. |
||
184 | */ |
||
185 | static fz_stream * |
||
186 | pdf_open_filter(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int num, int gen) |
||
187 | { |
||
188 | fz_obj *filters; |
||
189 | fz_obj *params; |
||
190 | |||
191 | filters = fz_dict_getsa(stmobj, "Filter", "F"); |
||
192 | params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); |
||
193 | |||
194 | chain = pdf_open_raw_filter(chain, xref, stmobj, num, gen); |
||
195 | |||
196 | if (fz_is_name(filters)) |
||
197 | return build_filter(chain, xref, filters, params, num, gen); |
||
198 | if (fz_array_len(filters) > 0) |
||
199 | return build_filter_chain(chain, xref, filters, params, num, gen); |
||
200 | |||
201 | return chain; |
||
202 | } |
||
203 | |||
204 | /* |
||
205 | * Construct a filter to decode a stream, without |
||
206 | * constraining to stream length, and without decryption. |
||
207 | */ |
||
208 | fz_stream * |
||
209 | pdf_open_inline_stream(fz_stream *chain, pdf_xref *xref, fz_obj *stmobj, int length) |
||
210 | { |
||
211 | fz_obj *filters; |
||
212 | fz_obj *params; |
||
213 | |||
214 | filters = fz_dict_getsa(stmobj, "Filter", "F"); |
||
215 | params = fz_dict_getsa(stmobj, "DecodeParms", "DP"); |
||
216 | |||
217 | /* don't close chain when we close this filter */ |
||
218 | fz_keep_stream(chain); |
||
219 | |||
220 | if (fz_is_name(filters)) |
||
221 | return build_filter(chain, xref, filters, params, 0, 0); |
||
222 | if (fz_array_len(filters) > 0) |
||
223 | return build_filter_chain(chain, xref, filters, params, 0, 0); |
||
224 | |||
225 | return fz_open_null(chain, length); |
||
226 | } |
||
227 | |||
228 | /* |
||
229 | * Open a stream for reading the raw (compressed but decrypted) data. |
||
230 | * Using xref->file while this is open is a bad idea. |
||
231 | */ |
||
232 | fz_error |
||
233 | pdf_open_raw_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen) |
||
234 | { |
||
235 | pdf_xref_entry *x; |
||
236 | fz_error error; |
||
237 | |||
238 | if (num < 0 || num >= xref->len) |
||
239 | return fz_throw("object id out of range (%d %d R)", num, gen); |
||
240 | |||
241 | x = xref->table + num; |
||
242 | |||
243 | error = pdf_cache_object(xref, num, gen); |
||
244 | if (error) |
||
245 | return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen); |
||
246 | |||
247 | if (x->stm_ofs) |
||
248 | { |
||
249 | *stmp = pdf_open_raw_filter(xref->file, xref, x->obj, num, gen); |
||
250 | fz_seek(xref->file, x->stm_ofs, 0); |
||
251 | return fz_okay; |
||
252 | } |
||
253 | |||
254 | return fz_throw("object is not a stream"); |
||
255 | } |
||
256 | |||
257 | /* |
||
258 | * Open a stream for reading uncompressed data. |
||
259 | * Put the opened file in xref->stream. |
||
260 | * Using xref->file while a stream is open is a Bad idea. |
||
261 | */ |
||
262 | fz_error |
||
263 | pdf_open_stream(fz_stream **stmp, pdf_xref *xref, int num, int gen) |
||
264 | { |
||
265 | pdf_xref_entry *x; |
||
266 | fz_error error; |
||
267 | |||
268 | if (num < 0 || num >= xref->len) |
||
269 | return fz_throw("object id out of range (%d %d R)", num, gen); |
||
270 | |||
271 | x = xref->table + num; |
||
272 | |||
273 | error = pdf_cache_object(xref, num, gen); |
||
274 | if (error) |
||
275 | return fz_rethrow(error, "cannot load stream object (%d %d R)", num, gen); |
||
276 | |||
277 | if (x->stm_ofs) |
||
278 | { |
||
279 | *stmp = pdf_open_filter(xref->file, xref, x->obj, num, gen); |
||
280 | fz_seek(xref->file, x->stm_ofs, 0); |
||
281 | return fz_okay; |
||
282 | } |
||
283 | |||
284 | return fz_throw("object is not a stream"); |
||
285 | } |
||
286 | |||
287 | fz_error |
||
288 | pdf_open_stream_at(fz_stream **stmp, pdf_xref *xref, int num, int gen, fz_obj *dict, int stm_ofs) |
||
289 | { |
||
290 | if (stm_ofs) |
||
291 | { |
||
292 | *stmp = pdf_open_filter(xref->file, xref, dict, num, gen); |
||
293 | fz_seek(xref->file, stm_ofs, 0); |
||
294 | return fz_okay; |
||
295 | } |
||
296 | return fz_throw("object is not a stream"); |
||
297 | } |
||
298 | |||
299 | /* |
||
300 | * Load raw (compressed but decrypted) contents of a stream into buf. |
||
301 | */ |
||
302 | fz_error |
||
303 | pdf_load_raw_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen) |
||
304 | { |
||
305 | fz_error error; |
||
306 | fz_stream *stm; |
||
307 | fz_obj *dict; |
||
308 | int len; |
||
309 | |||
310 | error = pdf_load_object(&dict, xref, num, gen); |
||
311 | if (error) |
||
312 | return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen); |
||
313 | |||
314 | len = fz_to_int(fz_dict_gets(dict, "Length")); |
||
315 | |||
316 | fz_drop_obj(dict); |
||
317 | |||
318 | error = pdf_open_raw_stream(&stm, xref, num, gen); |
||
319 | if (error) |
||
320 | return fz_rethrow(error, "cannot open raw stream (%d %d R)", num, gen); |
||
321 | |||
322 | error = fz_read_all(bufp, stm, len); |
||
323 | if (error) |
||
324 | { |
||
325 | fz_close(stm); |
||
326 | return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen); |
||
327 | } |
||
328 | |||
329 | fz_close(stm); |
||
330 | return fz_okay; |
||
331 | } |
||
332 | |||
333 | static int |
||
334 | pdf_guess_filter_length(int len, char *filter) |
||
335 | { |
||
336 | if (!strcmp(filter, "ASCIIHexDecode")) |
||
337 | return len / 2; |
||
338 | if (!strcmp(filter, "ASCII85Decode")) |
||
339 | return len * 4 / 5; |
||
340 | if (!strcmp(filter, "FlateDecode")) |
||
341 | return len * 3; |
||
342 | if (!strcmp(filter, "RunLengthDecode")) |
||
343 | return len * 3; |
||
344 | if (!strcmp(filter, "LZWDecode")) |
||
345 | return len * 2; |
||
346 | return len; |
||
347 | } |
||
348 | |||
349 | /* |
||
350 | * Load uncompressed contents of a stream into buf. |
||
351 | */ |
||
352 | fz_error |
||
353 | pdf_load_stream(fz_buffer **bufp, pdf_xref *xref, int num, int gen) |
||
354 | { |
||
355 | fz_error error; |
||
356 | fz_stream *stm; |
||
357 | fz_obj *dict, *obj; |
||
358 | int i, len; |
||
359 | |||
360 | error = pdf_open_stream(&stm, xref, num, gen); |
||
361 | if (error) |
||
362 | return fz_rethrow(error, "cannot open stream (%d %d R)", num, gen); |
||
363 | |||
364 | error = pdf_load_object(&dict, xref, num, gen); |
||
365 | if (error) |
||
366 | return fz_rethrow(error, "cannot load stream dictionary (%d %d R)", num, gen); |
||
367 | |||
368 | len = fz_to_int(fz_dict_gets(dict, "Length")); |
||
369 | obj = fz_dict_gets(dict, "Filter"); |
||
370 | len = pdf_guess_filter_length(len, fz_to_name(obj)); |
||
371 | for (i = 0; i < fz_array_len(obj); i++) |
||
372 | len = pdf_guess_filter_length(len, fz_to_name(fz_array_get(obj, i))); |
||
373 | |||
374 | fz_drop_obj(dict); |
||
375 | |||
376 | error = fz_read_all(bufp, stm, len); |
||
377 | if (error) |
||
378 | { |
||
379 | fz_close(stm); |
||
380 | return fz_rethrow(error, "cannot read raw stream (%d %d R)", num, gen); |
||
381 | } |
||
382 | |||
383 | fz_close(stm); |
||
384 | return fz_okay; |
||
385 | }>>>>>> |