/src/ghostpdl/pdf/pdf_file.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2018-2022 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, for further information. |
14 | | */ |
15 | | |
16 | | #include "ghostpdf.h" |
17 | | #include "pdf_types.h" |
18 | | #include "pdf_stack.h" |
19 | | #include "pdf_dict.h" |
20 | | #include "pdf_file.h" |
21 | | #include "pdf_int.h" |
22 | | #include "pdf_array.h" |
23 | | #include "pdf_misc.h" |
24 | | #include "pdf_sec.h" |
25 | | #include "stream.h" |
26 | | #include "strimpl.h" |
27 | | #include "strmio.h" |
28 | | #include "gpmisc.h" |
29 | | #include "simscale.h" /* SIMScaleDecode */ |
30 | | #include "szlibx.h" /* Flate */ |
31 | | #include "spngpx.h" /* PNG Predictor */ |
32 | | #include "spdiffx.h" /* Horizontal differencing predictor */ |
33 | | #include "slzwx.h" /* LZW ZLib */ |
34 | | #include "sstring.h" /* ASCIIHexDecode */ |
35 | | #include "sa85d.h" /* ASCII85Decode */ |
36 | | #include "scfx.h" /* CCITTFaxDecode */ |
37 | | #include "srlx.h" /* RunLengthDecode */ |
38 | | #include "jpeglib_.h" |
39 | | #include "sdct.h" /* DCTDecode */ |
40 | | #include "sjpeg.h" |
41 | | #include "sfilter.h" /* SubFileDecode and PFBDecode */ |
42 | | #include "sarc4.h" /* Arc4Decode */ |
43 | | #include "saes.h" /* AESDecode */ |
44 | | #include "ssha2.h" /* SHA256Encode */ |
45 | | #include "gxdevsop.h" /* For special ops */ |
46 | | |
47 | | #ifdef USE_LDF_JB2 |
48 | | #include "sjbig2_luratech.h" |
49 | | #else |
50 | | #include "sjbig2.h" |
51 | | #endif |
52 | | #if defined(USE_LWF_JP2) |
53 | | # include "sjpx_luratech.h" |
54 | | #elif defined(USE_OPENJPEG_JP2) |
55 | | # include "sjpx_openjpeg.h" |
56 | | #else |
57 | | # include "sjpx.h" |
58 | | #endif |
59 | | |
60 | | extern const uint file_default_buffer_size; |
61 | | |
62 | | static void pdfi_close_filter_chain(pdf_context *ctx, stream *s, stream *target); |
63 | | |
64 | | /* Utility routine to create a pdf_c_stream object */ |
65 | | static int pdfi_alloc_stream(pdf_context *ctx, stream *source, stream *original, pdf_c_stream **new_stream) |
66 | 6.06M | { |
67 | 6.06M | *new_stream = NULL; |
68 | 6.06M | *new_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "pdfi_alloc_stream"); |
69 | 6.06M | if (*new_stream == NULL) |
70 | 0 | return_error(gs_error_VMerror); |
71 | 6.06M | memset(*new_stream, 0x00, sizeof(pdf_c_stream)); |
72 | 6.06M | (*new_stream)->eof = false; |
73 | 6.06M | ((pdf_c_stream *)(*new_stream))->s = source; |
74 | 6.06M | ((pdf_c_stream *)(*new_stream))->original = original; |
75 | 6.06M | return 0; |
76 | 6.06M | } |
77 | | |
78 | | /***********************************************************************************/ |
79 | | /* Decompression filters. */ |
80 | | |
81 | | static int |
82 | | pdfi_filter_report_error(stream_state * st, const char *str) |
83 | 1.40k | { |
84 | 1.40k | if_debug1m('s', st->memory, "[s]stream error: %s\n", str); |
85 | 1.40k | strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING); |
86 | | /* Ensure null termination. */ |
87 | 1.40k | st->error_string[STREAM_MAX_ERROR_STRING] = 0; |
88 | 1.40k | return 0; |
89 | 1.40k | } |
90 | | |
91 | | /* Open a file stream for a filter. */ |
92 | | static int |
93 | | pdfi_filter_open(uint buffer_size, |
94 | | const stream_procs * procs, const stream_template * templat, |
95 | | const stream_state * st, gs_memory_t *mem, stream **new_stream) |
96 | 5.84M | { |
97 | 5.84M | stream *s; |
98 | 5.84M | uint ssize = gs_struct_type_size(templat->stype); |
99 | 5.84M | stream_state *sst = NULL; |
100 | 5.84M | int code; |
101 | | |
102 | 5.84M | if (templat->stype != &st_stream_state) { |
103 | 5.84M | sst = s_alloc_state(mem, templat->stype, "pdfi_filter_open(stream_state)"); |
104 | 5.84M | if (sst == NULL) |
105 | 0 | return_error(gs_error_VMerror); |
106 | 5.84M | } |
107 | 5.84M | if (buffer_size < 128) |
108 | 13.5k | buffer_size = file_default_buffer_size; |
109 | | |
110 | 5.84M | code = file_open_stream((char *)0, 0, "r", buffer_size, &s, |
111 | 5.84M | (gx_io_device *)0, (iodev_proc_fopen_t)0, mem); |
112 | 5.84M | if (code < 0) { |
113 | 0 | gs_free_object(mem, sst, "pdfi_filter_open(stream_state)"); |
114 | 0 | return code; |
115 | 0 | } |
116 | 5.84M | s_std_init(s, s->cbuf, s->bsize, procs, s_mode_read); |
117 | 5.84M | s->procs.process = templat->process; |
118 | 5.84M | s->save_close = s->procs.close; |
119 | 5.84M | s->procs.close = file_close_file; |
120 | 5.84M | s->close_at_eod = 0; |
121 | 5.84M | if (sst == NULL) { |
122 | | /* This stream doesn't have any state of its own. */ |
123 | | /* Hack: use the stream itself as the state. */ |
124 | 0 | sst = (stream_state *) s; |
125 | 5.84M | } else if (st != NULL) /* might not have client parameters */ |
126 | 5.84M | memcpy(sst, st, ssize); |
127 | 5.84M | s->state = sst; |
128 | 5.84M | s_init_state(sst, templat, mem); |
129 | 5.84M | sst->report_error = pdfi_filter_report_error; |
130 | | |
131 | 5.84M | if (templat->init != NULL) { |
132 | 5.84M | code = (*templat->init)(sst); |
133 | 5.84M | if (code < 0) { |
134 | 0 | gs_free_object(mem, sst, "filter_open(stream_state)"); |
135 | 0 | gs_free_object(mem, s->cbuf, "filter_open(buffer)"); |
136 | 0 | gs_free_object(mem, s, "filter_open(stream)"); |
137 | 0 | return code; |
138 | 0 | } |
139 | 5.84M | } |
140 | 5.84M | *new_stream = s; |
141 | 5.84M | return 0; |
142 | 5.84M | } |
143 | | |
144 | | static int pdfi_Predictor_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
145 | 14.0k | { |
146 | 14.0k | int code; |
147 | 14.0k | int64_t Predictor, Colors, BPC, Columns; |
148 | 14.0k | uint min_size; |
149 | 14.0k | stream_PNGP_state pps; |
150 | 14.0k | stream_PDiff_state ppds; |
151 | | /* NOTE: 'max_min_left=1' is a horribly named definition from stream.h */ |
152 | | |
153 | 14.0k | code = pdfi_dict_get_int_def(ctx, d, "Predictor", &Predictor, 1); |
154 | 14.0k | if (code < 0) |
155 | 0 | return code; |
156 | | |
157 | | /* Predictor values 0,1 are identity (use the existing stream). |
158 | | * The other values need to be cascaded. |
159 | | */ |
160 | 14.0k | switch(Predictor) { |
161 | 0 | case 0: |
162 | 0 | Predictor = 1; |
163 | 0 | break; |
164 | 244 | case 1: |
165 | 244 | break; |
166 | 2 | case 2: |
167 | 2 | case 10: |
168 | 3 | case 11: |
169 | 5.97k | case 12: |
170 | 5.97k | case 13: |
171 | 5.97k | case 14: |
172 | 13.7k | case 15: |
173 | | /* grab values common to both kinds of predictors */ |
174 | 13.7k | min_size = s_zlibD_template.min_out_size + max_min_left; |
175 | 13.7k | code = pdfi_dict_get_int_def(ctx, d, "Colors", &Colors, 1); |
176 | 13.7k | if (code < 0) |
177 | 2 | return code; |
178 | 13.7k | if (Colors < 1 || Colors > s_PNG_max_Colors) |
179 | 224 | return_error(gs_error_rangecheck); |
180 | | |
181 | 13.5k | code = pdfi_dict_get_int_def(ctx, d, "BitsPerComponent", &BPC, 8); |
182 | 13.5k | if (code < 0) |
183 | 0 | return code; |
184 | | /* tests for 1-16, powers of 2 */ |
185 | 13.5k | if (BPC < 1 || BPC > 16 || (BPC & (BPC - 1)) != 0) |
186 | 7 | return_error(gs_error_rangecheck); |
187 | | |
188 | 13.5k | code = pdfi_dict_get_int_def(ctx, d, "Columns", &Columns, 1); |
189 | 13.5k | if (code < 0) |
190 | 0 | return code; |
191 | 13.5k | if (Columns < 1) |
192 | 2 | return_error(gs_error_rangecheck); |
193 | 13.5k | break; |
194 | 13.5k | default: |
195 | 50 | return_error(gs_error_rangecheck); |
196 | 14.0k | } |
197 | | |
198 | 13.7k | switch(Predictor) { |
199 | 244 | case 1: |
200 | 244 | *new_stream = source; |
201 | 244 | break; |
202 | 2 | case 2: |
203 | | /* zpd_setup, componentwise horizontal differencing */ |
204 | 2 | ppds.Colors = (int)Colors; |
205 | 2 | ppds.BitsPerComponent = (int)BPC; |
206 | 2 | ppds.Columns = (int)Columns; |
207 | 2 | code = pdfi_filter_open(min_size, &s_filter_read_procs, |
208 | 2 | (const stream_template *)&s_PDiffD_template, |
209 | 2 | (const stream_state *)&ppds, ctx->memory->non_gc_memory, new_stream); |
210 | 2 | if (code < 0) |
211 | 0 | return code; |
212 | | |
213 | 2 | (*new_stream)->strm = source; |
214 | 2 | break; |
215 | 13.5k | default: |
216 | | /* zpp_setup, PNG predictor */ |
217 | 13.5k | pps.Colors = (int)Colors; |
218 | 13.5k | pps.BitsPerComponent = (int)BPC; |
219 | 13.5k | pps.Columns = (uint)Columns; |
220 | 13.5k | pps.Predictor = Predictor; |
221 | 13.5k | code = pdfi_filter_open(min_size, &s_filter_read_procs, |
222 | 13.5k | (const stream_template *)&s_PNGPD_template, |
223 | 13.5k | (const stream_state *)&pps, ctx->memory->non_gc_memory, new_stream); |
224 | 13.5k | if (code < 0) |
225 | 0 | return code; |
226 | | |
227 | 13.5k | (*new_stream)->strm = source; |
228 | 13.5k | break; |
229 | 13.7k | } |
230 | 13.7k | return 0; |
231 | 13.7k | } |
232 | | |
233 | | int pdfi_apply_Arc4_filter(pdf_context *ctx, pdf_string *Key, pdf_c_stream *source, pdf_c_stream **new_stream) |
234 | 2.97k | { |
235 | 2.97k | int code = 0; |
236 | 2.97k | stream_arcfour_state state; |
237 | 2.97k | stream *new_s; |
238 | 2.97k | int min_size = 2048; |
239 | | |
240 | 2.97k | s_arcfour_set_key(&state, (const unsigned char *)Key->data, Key->length); /* lgtm [cpp/weak-cryptographic-algorithm] */ |
241 | | |
242 | 2.97k | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_arcfour_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s); |
243 | 2.97k | if (code < 0) |
244 | 0 | return code; |
245 | | |
246 | 2.97k | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
247 | 2.97k | new_s->strm = source->s; |
248 | 2.97k | return code; |
249 | 2.97k | } |
250 | | |
251 | | int pdfi_apply_AES_filter(pdf_context *ctx, pdf_string *Key, bool use_padding, pdf_c_stream *source, pdf_c_stream **new_stream) |
252 | 5.25k | { |
253 | 5.25k | stream_aes_state state; |
254 | 5.25k | uint min_size = 2048; |
255 | 5.25k | int code = 0; |
256 | 5.25k | stream *new_s; |
257 | | |
258 | 5.25k | s_aes_set_key(&state, Key->data, Key->length); |
259 | 5.25k | s_aes_set_padding(&state, use_padding); |
260 | | |
261 | 5.25k | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_aes_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s); |
262 | | |
263 | 5.25k | if (code < 0) |
264 | 0 | return code; |
265 | | |
266 | 5.25k | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
267 | 5.25k | new_s->strm = source->s; |
268 | 5.25k | return code; |
269 | 5.25k | } |
270 | | |
271 | | #ifdef UNUSED_FILTER |
272 | | int pdfi_apply_SHA256_filter(pdf_context *ctx, pdf_c_stream *source, pdf_c_stream **new_stream) |
273 | | { |
274 | | stream_SHA256E_state state; |
275 | | uint min_size = 2048; |
276 | | int code = 0; |
277 | | stream *new_s; |
278 | | |
279 | | pSHA256_Init(&state.sha256); |
280 | | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_SHA256E_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s); |
281 | | |
282 | | if (code < 0) |
283 | | return code; |
284 | | |
285 | | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
286 | | new_s->strm = source->s; |
287 | | return code; |
288 | | } |
289 | | #endif |
290 | | |
291 | | int pdfi_apply_imscale_filter(pdf_context *ctx, pdf_string *Key, int width, int height, pdf_c_stream *source, pdf_c_stream **new_stream) |
292 | 0 | { |
293 | 0 | int code = 0; |
294 | 0 | stream_imscale_state state; |
295 | 0 | stream *new_s; |
296 | |
|
297 | 0 | state.params.spp_decode = 1; |
298 | 0 | state.params.spp_interp = 1; |
299 | 0 | state.params.BitsPerComponentIn = 1; |
300 | 0 | state.params.MaxValueIn = 1; |
301 | 0 | state.params.WidthIn = width; |
302 | 0 | state.params.HeightIn = height; |
303 | 0 | state.params.BitsPerComponentOut = 1; |
304 | 0 | state.params.MaxValueOut = 1; |
305 | 0 | state.params.WidthOut = width << 2; |
306 | 0 | state.params.HeightOut = height << 2; |
307 | |
|
308 | 0 | code = pdfi_filter_open(2048, &s_filter_read_procs, (const stream_template *)&s_imscale_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s); |
309 | |
|
310 | 0 | if (code < 0) |
311 | 0 | return code; |
312 | | |
313 | 0 | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
314 | 0 | new_s->strm = source->s; |
315 | 0 | return code; |
316 | 0 | } |
317 | | |
318 | | static int pdfi_Flate_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
319 | 2.17M | { |
320 | 2.17M | stream_zlib_state zls; |
321 | 2.17M | uint min_size = 2048; |
322 | 2.17M | int code; |
323 | 2.17M | stream *Flate_source = NULL; |
324 | | |
325 | 2.17M | memset(&zls, 0, sizeof(zls)); |
326 | | |
327 | | /* s_zlibD_template defined in base/szlibd.c */ |
328 | 2.17M | (*s_zlibD_template.set_defaults)((stream_state *)&zls); |
329 | | |
330 | 2.17M | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_zlibD_template, (const stream_state *)&zls, ctx->memory->non_gc_memory, new_stream); |
331 | 2.17M | if (code < 0) |
332 | 0 | return code; |
333 | | |
334 | 2.17M | (*new_stream)->strm = source; |
335 | 2.17M | source = *new_stream; |
336 | | |
337 | 2.17M | if (d && pdfi_type_of(d) == PDF_DICT) { |
338 | 14.0k | Flate_source = (*new_stream)->strm; |
339 | 14.0k | code = pdfi_Predictor_filter(ctx, d, source, new_stream); |
340 | 14.0k | if (code < 0) |
341 | 285 | pdfi_close_filter_chain(ctx, source, Flate_source); |
342 | 14.0k | } |
343 | 2.17M | return code; |
344 | 2.17M | } |
345 | | |
346 | | static int |
347 | | pdfi_JBIG2Decode_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode, |
348 | | stream *source, stream **new_stream) |
349 | 64 | { |
350 | 64 | stream_jbig2decode_state state; |
351 | 64 | uint min_size = s_jbig2decode_template.min_out_size; |
352 | 64 | int code; |
353 | 64 | pdf_stream *Globals = NULL; |
354 | 64 | byte *buf = NULL; |
355 | 64 | int64_t buflen = 0; |
356 | 64 | void *globalctx; |
357 | | |
358 | 64 | s_jbig2decode_set_global_data((stream_state*)&state, NULL, NULL); |
359 | | |
360 | 64 | if (decode) { |
361 | 0 | code = pdfi_dict_knownget_type(ctx, decode, "JBIG2Globals", PDF_STREAM, |
362 | 0 | (pdf_obj **)&Globals); |
363 | 0 | if (code < 0) { |
364 | 0 | goto cleanupExit; |
365 | 0 | } |
366 | | |
367 | | /* read in the globals from stream */ |
368 | 0 | if (code > 0) { |
369 | 0 | code = pdfi_stream_to_buffer(ctx, Globals, &buf, &buflen); |
370 | 0 | if (code == 0) { |
371 | 0 | code = s_jbig2decode_make_global_data(ctx->memory->non_gc_memory, |
372 | 0 | buf, buflen, &globalctx); |
373 | 0 | if (code < 0) |
374 | 0 | goto cleanupExit; |
375 | | |
376 | 0 | s_jbig2decode_set_global_data((stream_state*)&state, NULL, globalctx); |
377 | 0 | } |
378 | 0 | } |
379 | 0 | } |
380 | | |
381 | 64 | code = pdfi_filter_open(min_size, &s_filter_read_procs, |
382 | 64 | (const stream_template *)&s_jbig2decode_template, |
383 | 64 | (const stream_state *)&state, ctx->memory->non_gc_memory, new_stream); |
384 | 64 | if (code < 0) |
385 | 0 | goto cleanupExit; |
386 | | |
387 | 64 | (*new_stream)->strm = source; |
388 | 64 | code = 0; |
389 | | |
390 | 64 | cleanupExit: |
391 | 64 | gs_free_object(ctx->memory, buf, "pdfi_JBIG2Decode_filter (Globals buf)"); |
392 | 64 | pdfi_countdown(Globals); |
393 | 64 | return code; |
394 | 64 | } |
395 | | |
396 | | static int pdfi_LZW_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
397 | 26 | { |
398 | 26 | stream_LZW_state lzs; |
399 | 26 | uint min_size = 2048; |
400 | 26 | int code; |
401 | 26 | int64_t i; |
402 | | |
403 | | /* s_zlibD_template defined in base/szlibd.c */ |
404 | 26 | s_LZW_set_defaults_inline(&lzs); |
405 | | |
406 | 26 | if (d && pdfi_type_of(d) == PDF_DICT) { |
407 | 0 | code = pdfi_dict_get_int(ctx, d, "EarlyChange", &i); |
408 | 0 | if (code < 0 && code != gs_error_undefined) |
409 | 0 | return code; |
410 | 0 | if (code == 0) { |
411 | 0 | if (i == 0) |
412 | 0 | lzs.EarlyChange = false; |
413 | 0 | else |
414 | 0 | lzs.EarlyChange = true; |
415 | 0 | } |
416 | 0 | } |
417 | | |
418 | 26 | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_LZWD_template, (const stream_state *)&lzs, ctx->memory->non_gc_memory, new_stream); |
419 | 26 | if (code < 0) |
420 | 0 | return code; |
421 | 26 | (*new_stream)->strm = source; |
422 | 26 | source = *new_stream; |
423 | | |
424 | 26 | if (d && pdfi_type_of(d) == PDF_DICT) |
425 | 0 | pdfi_Predictor_filter(ctx, d, source, new_stream); |
426 | 26 | return 0; |
427 | 26 | } |
428 | | |
429 | | static int PS_JPXD_PassThrough(void *d, byte *Buffer, int Size) |
430 | 24.0k | { |
431 | 24.0k | gx_device *dev = (gx_device *)d; |
432 | | |
433 | 24.0k | if (Buffer == NULL) { |
434 | 520 | if (Size == 0) |
435 | 260 | dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_end, NULL, 0); |
436 | 260 | else |
437 | 260 | dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_begin, NULL, 0); |
438 | 23.5k | } else { |
439 | 23.5k | dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_data, Buffer, Size); |
440 | 23.5k | } |
441 | 24.0k | return 0; |
442 | 24.0k | } |
443 | | |
444 | | /* |
445 | | * dict -- the dict that contained the decoder (i.e. the image dict) |
446 | | * decode -- the decoder dict |
447 | | */ |
448 | | static int |
449 | | pdfi_JPX_filter(pdf_context *ctx, pdf_dict *dict, pdf_dict *decode, |
450 | | stream *source, stream **new_stream) |
451 | 2.44k | { |
452 | 2.44k | stream_jpxd_state state; |
453 | 2.44k | uint min_size = s_jpxd_template.min_out_size; |
454 | 2.44k | int code; |
455 | 2.44k | pdf_obj *csobj = NULL; |
456 | 2.44k | pdf_name *csname = NULL; |
457 | 2.44k | bool alpha; |
458 | 2.44k | gx_device *dev = gs_currentdevice(ctx->pgs); |
459 | | |
460 | 2.44k | state.memory = ctx->memory->non_gc_memory; |
461 | 2.44k | if (s_jpxd_template.set_defaults) |
462 | 2.44k | (*s_jpxd_template.set_defaults)((stream_state *)&state); |
463 | | |
464 | | /* Pull some extra params out of the image dict */ |
465 | 2.44k | if (dict) { |
466 | | /* This Alpha is a thing that gs code uses to tell that we |
467 | | * are doing an SMask. It's a bit of a hack, but |
468 | | * I guess we can do the same. |
469 | | */ |
470 | 2.44k | code = pdfi_dict_get_bool(ctx, dict, "Alpha", &alpha); |
471 | 2.44k | if (code == 0) |
472 | 0 | state.alpha = alpha; |
473 | 2.44k | } |
474 | 2.44k | if (dict && pdfi_dict_get(ctx, dict, "ColorSpace", &csobj) == 0) { |
475 | | /* parse the value */ |
476 | 1.20k | switch (pdfi_type_of(csobj)) { |
477 | 0 | case PDF_ARRAY: |
478 | | /* assume it's the first array element */ |
479 | 0 | code = pdfi_array_get(ctx, (pdf_array *)csobj, (uint64_t)0, (pdf_obj **)&csname); |
480 | 0 | if (code < 0) { |
481 | 0 | pdfi_countdown(csobj); |
482 | 0 | return code; |
483 | 0 | } |
484 | 0 | break; |
485 | 1.20k | case PDF_NAME: |
486 | | /* use the name directly */ |
487 | 1.20k | csname = (pdf_name *)csobj; |
488 | 1.20k | csobj = NULL; /* To keep ref counting straight */ |
489 | 1.20k | break; |
490 | 0 | default: |
491 | 0 | dmprintf(ctx->memory, "warning: JPX ColorSpace value is an unhandled type!\n"); |
492 | 0 | break; |
493 | 1.20k | } |
494 | 1.20k | if (csname != NULL && pdfi_type_of(csname) == PDF_NAME) { |
495 | | /* request raw index values if the colorspace is /Indexed */ |
496 | 1.20k | if (pdfi_name_is(csname, "Indexed")) |
497 | 0 | state.colorspace = gs_jpx_cs_indexed; |
498 | | /* tell the filter what output we want for other spaces */ |
499 | 1.20k | else if (pdfi_name_is(csname, "DeviceGray")) |
500 | 501 | state.colorspace = gs_jpx_cs_gray; |
501 | 702 | else if (pdfi_name_is(csname, "DeviceRGB")) |
502 | 702 | state.colorspace = gs_jpx_cs_rgb; |
503 | 0 | else if (pdfi_name_is(csname, "DeviceCMYK")) |
504 | 0 | state.colorspace = gs_jpx_cs_cmyk; |
505 | 0 | else if (pdfi_name_is(csname, "ICCBased")) { |
506 | | /* TODO: I don't think this even happens without PS wrapper code? */ |
507 | | #if 0 |
508 | | /* The second array element should be the profile's |
509 | | stream dict */ |
510 | | ref *csdict = csobj->value.refs + 1; |
511 | | ref *nref; |
512 | | ref altname; |
513 | | if (r_is_array(csobj) && (r_size(csobj) > 1) && |
514 | | r_has_type(csdict, t_dictionary)) { |
515 | | check_dict_read(*csdict); |
516 | | /* try to look up the alternate space */ |
517 | | if (dict_find_string(csdict, "Alternate", &nref) > 0) { |
518 | | name_string_ref(imemory, csname, &altname); |
519 | | if (pdfi_name_is(&altname, "DeviceGray")) |
520 | | state.colorspace = gs_jpx_cs_gray; |
521 | | else if (pdfi_name_is(&altname, "DeviceRGB")) |
522 | | state.colorspace = gs_jpx_cs_rgb; |
523 | | else if (pdfi_name_is(&altname, "DeviceCMYK")) |
524 | | state.colorspace = gs_jpx_cs_cmyk; |
525 | | } |
526 | | /* else guess based on the number of components */ |
527 | | if (state.colorspace == gs_jpx_cs_unset && |
528 | | dict_find_string(csdict, "N", &nref) > 0) { |
529 | | if_debug1m('w', imemory, "[w] JPX image has an external %"PRIpsint |
530 | | " channel colorspace\n", nref->value.intval); |
531 | | switch (nref->value.intval) { |
532 | | case 1: state.colorspace = gs_jpx_cs_gray; |
533 | | break; |
534 | | case 3: state.colorspace = gs_jpx_cs_rgb; |
535 | | break; |
536 | | case 4: state.colorspace = gs_jpx_cs_cmyk; |
537 | | break; |
538 | | } |
539 | | } |
540 | | } |
541 | | #endif |
542 | 0 | } |
543 | 1.20k | } |
544 | 1.20k | } |
545 | | |
546 | 2.44k | if (csobj) |
547 | 0 | pdfi_countdown(csobj); |
548 | 2.44k | if (csname) |
549 | 1.20k | pdfi_countdown(csname); |
550 | | |
551 | | |
552 | 2.44k | if (dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_query, NULL, 0) > 0) { |
553 | 266 | state.StartedPassThrough = 0; |
554 | 266 | state.PassThrough = 1; |
555 | 266 | state.PassThroughfn = (PS_JPXD_PassThrough); |
556 | 266 | state.device = (void *)dev; |
557 | 266 | } |
558 | 2.17k | else { |
559 | 2.17k | state.PassThrough = 0; |
560 | 2.17k | state.device = (void *)NULL; |
561 | 2.17k | } |
562 | | |
563 | 2.44k | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_jpxd_template, |
564 | 2.44k | (const stream_state *)&state, ctx->memory->non_gc_memory, new_stream); |
565 | 2.44k | if (code < 0) |
566 | 0 | return code; |
567 | 2.44k | (*new_stream)->strm = source; |
568 | 2.44k | source = *new_stream; |
569 | | |
570 | 2.44k | return 0; |
571 | 2.44k | } |
572 | | |
573 | | private_st_jpeg_decompress_data(); |
574 | | |
575 | | static int PDF_DCTD_PassThrough(void *d, byte *Buffer, int Size) |
576 | 142k | { |
577 | 142k | gx_device *dev = (gx_device *)d; |
578 | | |
579 | 142k | if (Buffer == NULL) { |
580 | 3.33k | if (Size == 0) |
581 | 1.67k | dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_end, NULL, 0); |
582 | 1.66k | else |
583 | 1.66k | dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_begin, NULL, 0); |
584 | 139k | } else { |
585 | 139k | dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_data, Buffer, Size); |
586 | 139k | } |
587 | 142k | return 0; |
588 | 142k | } |
589 | | |
590 | | static int pdfi_DCT_filter(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *decode, |
591 | | stream *source, stream **new_stream) |
592 | 6.44k | { |
593 | 6.44k | stream_DCT_state dcts; |
594 | 6.44k | uint min_size = s_DCTD_template.min_out_size; |
595 | 6.44k | int code; |
596 | 6.44k | int64_t i; |
597 | 6.44k | jpeg_decompress_data *jddp; |
598 | 6.44k | gx_device *dev = gs_currentdevice_inline(ctx->pgs); |
599 | 6.44k | double Height = 0; |
600 | | |
601 | 6.44k | dcts.memory = ctx->memory; |
602 | | /* First allocate space for IJG parameters. */ |
603 | 6.44k | jddp = gs_alloc_struct_immovable(ctx->memory, jpeg_decompress_data, |
604 | 6.44k | &st_jpeg_decompress_data, "pdfi_DCT"); |
605 | 6.44k | if (jddp == 0) |
606 | 0 | return_error(gs_error_VMerror); |
607 | 6.44k | if (s_DCTD_template.set_defaults) |
608 | 6.44k | (*s_DCTD_template.set_defaults) ((stream_state *) & dcts); |
609 | | |
610 | 6.44k | dcts.data.decompress = jddp; |
611 | 6.44k | jddp->memory = dcts.jpeg_memory = ctx->memory; /* set now for allocation */ |
612 | 6.44k | jddp->scanline_buffer = NULL; /* set this early for safe error exit */ |
613 | 6.44k | dcts.report_error = pdfi_filter_report_error; /* in case create fails */ |
614 | 6.44k | if ((code = gs_jpeg_create_decompress(&dcts)) < 0) { |
615 | 1 | gs_jpeg_destroy(&dcts); |
616 | 1 | gs_free_object(ctx->memory, jddp, "zDCTD fail"); |
617 | 1 | return code; |
618 | 1 | } |
619 | | |
620 | 6.44k | if (decode && pdfi_type_of(decode) == PDF_DICT) { |
621 | | /* TODO: Why is this here? 'i' never gets used? */ |
622 | 199 | code = pdfi_dict_get_int(ctx, decode, "ColorTransform", &i); |
623 | 199 | if (code < 0 && code != gs_error_undefined) |
624 | 0 | return code; |
625 | 199 | } |
626 | | |
627 | 6.44k | if (dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_query, NULL, 0) > 0) { |
628 | 1.67k | jddp->StartedPassThrough = 0; |
629 | 1.67k | jddp->PassThrough = 1; |
630 | 1.67k | jddp->PassThroughfn = (PDF_DCTD_PassThrough); |
631 | 1.67k | jddp->device = (void *)dev; |
632 | 1.67k | } |
633 | 4.77k | else { |
634 | 4.77k | jddp->PassThrough = 0; |
635 | 4.77k | jddp->device = (void *)NULL; |
636 | 4.77k | } |
637 | | |
638 | | /* Hack for Bug695112.pdf to grab a height in case it is missing from the JPEG data */ |
639 | 6.44k | code = pdfi_dict_knownget_number(ctx, stream_dict, "Height", &Height); |
640 | 6.44k | if (code < 0) |
641 | 0 | return code; |
642 | 6.44k | jddp->Height = (int)floor(Height); |
643 | | |
644 | 6.44k | jddp->templat = s_DCTD_template; |
645 | | |
646 | 6.44k | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&jddp->templat, (const stream_state *)&dcts, ctx->memory->non_gc_memory, new_stream); |
647 | 6.44k | if (code < 0) |
648 | 0 | return code; |
649 | 6.44k | (*new_stream)->strm = source; |
650 | 6.44k | source = *new_stream; |
651 | | |
652 | 6.44k | return 0; |
653 | 6.44k | } |
654 | | |
655 | | static int pdfi_ASCII85_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
656 | 225 | { |
657 | 225 | stream_A85D_state ss; |
658 | 225 | uint min_size = 2048; |
659 | 225 | int code; |
660 | | |
661 | 225 | ss.pdf_rules = true; |
662 | | |
663 | 225 | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_A85D_template, (const stream_state *)&ss, ctx->memory->non_gc_memory, new_stream); |
664 | 225 | if (code < 0) |
665 | 0 | return code; |
666 | | |
667 | 225 | (*new_stream)->strm = source; |
668 | 225 | return 0; |
669 | 225 | } |
670 | | |
671 | | static int pdfi_CCITTFax_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
672 | 509 | { |
673 | 509 | stream_CFD_state ss; |
674 | 509 | uint min_size = 2048; |
675 | 509 | bool bval; |
676 | 509 | int code; |
677 | 509 | int64_t i; |
678 | | |
679 | 509 | s_CF_set_defaults_inline(&ss); |
680 | | |
681 | 509 | if (d && pdfi_type_of(d) == PDF_DICT) { |
682 | 498 | code = pdfi_dict_get_int(ctx, d, "K", &i); |
683 | 498 | if (code < 0 && code != gs_error_undefined) |
684 | 0 | return code; |
685 | 498 | if (code == 0) |
686 | 483 | ss.K = i; |
687 | | |
688 | 498 | code = pdfi_dict_get_bool(ctx, d, "EndOfLine", &bval); |
689 | 498 | if (code < 0 && code != gs_error_undefined) |
690 | 0 | return code; |
691 | 498 | if (code == 0) |
692 | 0 | ss.EndOfLine = bval ? 1 : 0; |
693 | | |
694 | 498 | code = pdfi_dict_get_bool(ctx, d, "EncodedByteAlign", &bval); |
695 | 498 | if (code < 0 && code != gs_error_undefined) |
696 | 0 | return code; |
697 | 498 | if (code == 0) |
698 | 0 | ss.EncodedByteAlign = bval ? 1 : 0; |
699 | | |
700 | 498 | code = pdfi_dict_get_bool(ctx, d, "EndOfBlock", &bval); |
701 | 498 | if (code < 0 && code != gs_error_undefined) |
702 | 0 | return code; |
703 | 498 | if (code == 0) |
704 | 113 | ss.EndOfBlock = bval ? 1 : 0; |
705 | | |
706 | 498 | code = pdfi_dict_get_bool(ctx, d, "BlackIs1", &bval); |
707 | 498 | if (code < 0 && code != gs_error_undefined) |
708 | 0 | return code; |
709 | 498 | if (code == 0) |
710 | 10 | ss.BlackIs1 = bval ? 1 : 0; |
711 | | |
712 | 498 | code = pdfi_dict_get_int(ctx, d, "Columns", &i); |
713 | 498 | if (code < 0 && code != gs_error_undefined) |
714 | 0 | return code; |
715 | 498 | if (code == 0) |
716 | 494 | ss.Columns = i; |
717 | | |
718 | 498 | code = pdfi_dict_get_int(ctx, d, "Rows", &i); |
719 | 498 | if (code < 0 && code != gs_error_undefined) |
720 | 0 | return code; |
721 | 498 | if (code == 0) |
722 | 243 | ss.Rows = i; |
723 | | |
724 | 498 | code = pdfi_dict_get_int(ctx, d, "DamagedRowsBeforeError", &i); |
725 | 498 | if (code < 0 && code != gs_error_undefined) |
726 | 0 | return code; |
727 | 498 | if (code == 0) |
728 | 0 | ss.DamagedRowsBeforeError = i; |
729 | | |
730 | 498 | } |
731 | | |
732 | 509 | code = pdfi_filter_open(min_size, &s_filter_read_procs, |
733 | 509 | (const stream_template *)&s_CFD_template, |
734 | 509 | (const stream_state *)&ss, |
735 | 509 | ctx->memory->non_gc_memory, new_stream); |
736 | 509 | if (code < 0) |
737 | 0 | return code; |
738 | | |
739 | 509 | (*new_stream)->strm = source; |
740 | 509 | return 0; |
741 | 509 | } |
742 | | |
743 | | static int pdfi_RunLength_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream) |
744 | 0 | { |
745 | 0 | stream_RLD_state ss; |
746 | 0 | uint min_size = 2048; |
747 | 0 | int code; |
748 | |
|
749 | 0 | if (s_RLD_template.set_defaults) |
750 | 0 | (*s_RLD_template.set_defaults) ((stream_state *) & ss); |
751 | |
|
752 | 0 | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_RLD_template, (const stream_state *)&ss, ctx->memory->non_gc_memory, new_stream); |
753 | 0 | if (code < 0) |
754 | 0 | return code; |
755 | | |
756 | 0 | (*new_stream)->strm = source; |
757 | 0 | return 0; |
758 | 0 | } |
759 | | |
760 | | static int pdfi_simple_filter(pdf_context *ctx, const stream_template *tmplate, stream *source, stream **new_stream) |
761 | 405 | { |
762 | 405 | uint min_size = 2048; |
763 | 405 | int code; |
764 | | |
765 | 405 | code = pdfi_filter_open(min_size, &s_filter_read_procs, tmplate, NULL, ctx->memory->non_gc_memory, new_stream); |
766 | 405 | if (code < 0) |
767 | 0 | return code; |
768 | | |
769 | 405 | (*new_stream)->strm = source; |
770 | 405 | return 0; |
771 | 405 | } |
772 | | |
773 | | static int pdfi_apply_filter(pdf_context *ctx, pdf_dict *dict, pdf_name *n, pdf_dict *decode, |
774 | | stream *source, stream **new_stream, bool inline_image) |
775 | 2.18M | { |
776 | 2.18M | int code; |
777 | | |
778 | 2.18M | if (ctx->args.pdfdebug) |
779 | 0 | { |
780 | 0 | char str[100]; |
781 | 0 | memcpy(str, (const char *)n->data, n->length); |
782 | 0 | str[n->length] = '\0'; |
783 | 0 | dmprintf1(ctx->memory, "FILTER NAME:%s\n", str); |
784 | 0 | } |
785 | | |
786 | 2.18M | if (pdfi_name_is(n, "RunLengthDecode")) { |
787 | 0 | code = pdfi_RunLength_filter(ctx, decode, source, new_stream); |
788 | 0 | return code; |
789 | 0 | } |
790 | 2.18M | if (pdfi_name_is(n, "CCITTFaxDecode")) { |
791 | 291 | code = pdfi_CCITTFax_filter(ctx, decode, source, new_stream); |
792 | 291 | return code; |
793 | 291 | } |
794 | 2.18M | if (pdfi_name_is(n, "ASCIIHexDecode")) { |
795 | 252 | code = pdfi_simple_filter(ctx, &s_AXD_template, source, new_stream); |
796 | 252 | return code; |
797 | 252 | } |
798 | 2.18M | if (pdfi_name_is(n, "ASCII85Decode")) { |
799 | 137 | code = pdfi_ASCII85_filter(ctx, decode, source, new_stream); |
800 | 137 | return code; |
801 | 137 | } |
802 | 2.18M | if (pdfi_name_is(n, "SubFileDecode")) { |
803 | 0 | code = pdfi_simple_filter(ctx, &s_SFD_template, source, new_stream); |
804 | 0 | return code; |
805 | 0 | } |
806 | 2.18M | if (pdfi_name_is(n, "FlateDecode")) { |
807 | 2.17M | code = pdfi_Flate_filter(ctx, decode, source, new_stream); |
808 | 2.17M | return code; |
809 | 2.17M | } |
810 | 10.1k | if (pdfi_name_is(n, "JBIG2Decode")) { |
811 | 64 | code = pdfi_JBIG2Decode_filter(ctx, dict, decode, source, new_stream); |
812 | 64 | return code; |
813 | 64 | } |
814 | 10.0k | if (pdfi_name_is(n, "LZWDecode")) { |
815 | 26 | code = pdfi_LZW_filter(ctx, decode, source, new_stream); |
816 | 26 | return code; |
817 | 26 | } |
818 | 10.0k | if (pdfi_name_is(n, "DCTDecode")) { |
819 | 6.43k | code = pdfi_DCT_filter(ctx, dict, decode, source, new_stream); |
820 | 6.43k | return code; |
821 | 6.43k | } |
822 | 3.61k | if (pdfi_name_is(n, "JPXDecode")) { |
823 | 2.44k | code = pdfi_JPX_filter(ctx, dict, decode, source, new_stream); |
824 | 2.44k | return code; |
825 | 2.44k | } |
826 | | |
827 | 1.17k | if (pdfi_name_is(n, "AHx")) { |
828 | 153 | if (!inline_image) { |
829 | 42 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
830 | 42 | if (ctx->args.pdfstoponwarning) |
831 | 0 | return_error(gs_error_syntaxerror); |
832 | 42 | } |
833 | 153 | code = pdfi_simple_filter(ctx, &s_AXD_template, source, new_stream); |
834 | 153 | return code; |
835 | 153 | } |
836 | 1.02k | if (pdfi_name_is(n, "A85")) { |
837 | 88 | if (!inline_image) { |
838 | 67 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
839 | 67 | if (ctx->args.pdfstoponwarning) |
840 | 0 | return_error(gs_error_syntaxerror); |
841 | 67 | } |
842 | 88 | code = pdfi_ASCII85_filter(ctx, decode, source, new_stream); |
843 | 88 | return code; |
844 | 88 | } |
845 | 938 | if (pdfi_name_is(n, "LZW")) { |
846 | 0 | if (!inline_image) { |
847 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
848 | 0 | if (ctx->args.pdfstoponwarning) |
849 | 0 | return_error(gs_error_syntaxerror); |
850 | 0 | } |
851 | 0 | code = pdfi_LZW_filter(ctx, decode, source, new_stream); |
852 | 0 | return code; |
853 | 0 | } |
854 | 938 | if (pdfi_name_is(n, "CCF")) { |
855 | 218 | if (!inline_image) { |
856 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
857 | 0 | if (ctx->args.pdfstoponwarning) |
858 | 0 | return_error(gs_error_syntaxerror); |
859 | 0 | } |
860 | 218 | code = pdfi_CCITTFax_filter(ctx, decode, source, new_stream); |
861 | 218 | return code; |
862 | 218 | } |
863 | 720 | if (pdfi_name_is(n, "DCT")) { |
864 | 18 | if (!inline_image) { |
865 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
866 | 0 | if (ctx->args.pdfstoponwarning) |
867 | 0 | return_error(gs_error_syntaxerror); |
868 | 0 | } |
869 | 18 | code = pdfi_DCT_filter(ctx, dict, decode, source, new_stream); |
870 | 18 | return code; |
871 | 18 | } |
872 | 702 | if (pdfi_name_is(n, "Fl")) { |
873 | 35 | if (!inline_image) { |
874 | 2 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
875 | 2 | if (ctx->args.pdfstoponwarning) |
876 | 0 | return_error(gs_error_syntaxerror); |
877 | 2 | } |
878 | 35 | code = pdfi_Flate_filter(ctx, decode, source, new_stream); |
879 | 35 | return code; |
880 | 35 | } |
881 | 667 | if (pdfi_name_is(n, "RL")) { |
882 | 0 | if (!inline_image) { |
883 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_BAD_INLINEFILTER, "pdfi_apply_filter", NULL); |
884 | 0 | if (ctx->args.pdfstoponwarning) |
885 | 0 | return_error(gs_error_syntaxerror); |
886 | 0 | } |
887 | 0 | code = pdfi_RunLength_filter(ctx, decode, source, new_stream); |
888 | 0 | return code; |
889 | 0 | } |
890 | | |
891 | 667 | pdfi_set_error(ctx, 0, NULL, E_PDF_UNKNOWNFILTER, "pdfi_apply_filter", NULL); |
892 | 667 | return_error(gs_error_undefined); |
893 | 667 | } |
894 | | |
895 | | int pdfi_filter_no_decryption(pdf_context *ctx, pdf_stream *stream_obj, |
896 | | pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image) |
897 | 2.25M | { |
898 | 2.25M | pdf_obj *o = NULL, *o1 = NULL; |
899 | 2.25M | pdf_obj *decode = NULL; |
900 | 2.25M | pdf_obj *Filter = NULL; |
901 | 2.25M | pdf_dict *stream_dict = NULL; |
902 | 2.25M | pdf_array *DecodeParams = NULL; |
903 | 2.25M | int code; |
904 | 2.25M | int64_t i, j, duplicates; |
905 | 2.25M | stream *s = source->s, *new_s = NULL; |
906 | | |
907 | 2.25M | *new_stream = NULL; |
908 | | |
909 | 2.25M | if (ctx->args.pdfdebug) { |
910 | 0 | gs_offset_t stream_offset = pdfi_stream_offset(ctx, stream_obj); |
911 | 0 | dmprintf2(ctx->memory, "Filter: offset %ld(0x%lx)\n", stream_offset, stream_offset); |
912 | 0 | } |
913 | | |
914 | 2.25M | code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict); |
915 | 2.25M | if (code < 0) |
916 | 0 | goto exit; |
917 | | |
918 | 2.25M | code = pdfi_dict_knownget(ctx, stream_dict, "Filter", &Filter); |
919 | 2.25M | if (code == 0 && inline_image) |
920 | 6.98k | code = pdfi_dict_knownget(ctx, stream_dict, "F", &Filter); |
921 | 2.25M | if (code < 0) |
922 | 0 | goto exit; |
923 | 2.25M | if (code == 0) { |
924 | | /* No filter, just open the stream */ |
925 | 78.6k | code = pdfi_alloc_stream(ctx, s, source->s, new_stream); |
926 | 78.6k | goto exit; |
927 | 78.6k | } |
928 | | |
929 | 2.18M | switch (pdfi_type_of(Filter)) { |
930 | 1 | default: |
931 | 1 | code = gs_note_error(gs_error_typecheck); |
932 | 1 | goto exit; |
933 | 2.16M | case PDF_NAME: |
934 | 2.16M | code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", &decode); |
935 | 2.16M | if (code == 0 && inline_image) |
936 | 235 | code = pdfi_dict_knownget(ctx, stream_dict, "DP", &decode); |
937 | 2.16M | if (code < 0) |
938 | 4 | goto exit; |
939 | | |
940 | 2.16M | code = pdfi_apply_filter(ctx, stream_dict, (pdf_name *)Filter, |
941 | 2.16M | (pdf_dict *)decode, s, &new_s, inline_image); |
942 | 2.16M | if (code < 0) |
943 | 941 | goto exit; |
944 | | |
945 | 2.16M | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
946 | 2.16M | break; |
947 | 14.1k | case PDF_ARRAY: |
948 | 14.1k | { |
949 | 14.1k | pdf_array *filter_array = (pdf_array *)Filter; |
950 | | |
951 | 14.1k | code = pdfi_dict_knownget_type(ctx, stream_dict, "DecodeParms", PDF_ARRAY, (pdf_obj **)&DecodeParams); |
952 | 14.1k | if (code == 0 && inline_image) |
953 | 164 | code = pdfi_dict_knownget_type(ctx, stream_dict, "DP", PDF_ARRAY, (pdf_obj **)&DecodeParams); |
954 | 14.1k | if (code < 0) |
955 | 0 | goto exit; |
956 | | |
957 | 14.1k | if (DecodeParams != NULL) { |
958 | 1.83k | if (pdfi_array_size(DecodeParams) == 0 || pdfi_array_size(DecodeParams) != pdfi_array_size(filter_array)) { |
959 | 8 | pdfi_countdown(DecodeParams); |
960 | 8 | DecodeParams = NULL; |
961 | 8 | pdfi_set_warning(ctx, 0, NULL, W_PDF_STREAM_BAD_DECODEPARMS, "pdfi_filter_no_decryption", NULL); |
962 | 1.83k | } else { |
963 | 1.83k | if (pdfi_array_size(DecodeParams) != pdfi_array_size(filter_array)) { |
964 | 0 | code = gs_note_error(gs_error_typecheck); |
965 | 0 | goto exit; |
966 | 0 | } |
967 | 1.83k | } |
968 | 1.83k | } |
969 | | |
970 | | /* Check the Filter array to see if we have any duplicates (to prevent filter bombs) |
971 | | * For now we will allow one duplicate (in case people do stupid things like ASCIIEncode |
972 | | * and Flate and ASCIIEncode again or something). |
973 | | */ |
974 | 14.4k | for (i = 0; i < (int)pdfi_array_size(filter_array) - 1;i++) { |
975 | 231 | code = pdfi_array_get_type(ctx, filter_array, i, PDF_NAME, &o); |
976 | 231 | if (code < 0) |
977 | 0 | goto exit; |
978 | 231 | duplicates = 0; |
979 | | |
980 | 461 | for (j = i + 1; j < pdfi_array_size(filter_array);j++) { |
981 | 231 | code = pdfi_array_get_type(ctx, filter_array, j, PDF_NAME, &o1); |
982 | 231 | if (code < 0) { |
983 | 1 | goto exit; |
984 | 1 | } |
985 | 230 | if (((pdf_name *)o)->length == ((pdf_name *)o1)->length) { |
986 | 2 | if (memcmp(((pdf_name *)o)->data, ((pdf_name *)o1)->data, ((pdf_name *)o)->length) == 0) |
987 | 0 | duplicates++; |
988 | 2 | } |
989 | 230 | pdfi_countdown(o1); |
990 | 230 | o1 = NULL; |
991 | 230 | } |
992 | 230 | pdfi_countdown(o); |
993 | 230 | o = NULL; |
994 | 230 | if (duplicates > 2) { |
995 | 0 | pdfi_set_error(ctx, 0, NULL, E_PDF_BADSTREAM, "pdfi_filter_nodecryption", (char *)"**** ERROR Detected possible filter bomb (duplicate Filters). Aborting processing"); |
996 | 0 | code = gs_note_error(gs_error_syntaxerror); |
997 | 0 | goto exit; |
998 | 0 | } |
999 | 230 | } |
1000 | | |
1001 | 28.5k | for (i = 0; i < pdfi_array_size(filter_array);i++) { |
1002 | 14.4k | code = pdfi_array_get_type(ctx, filter_array, i, PDF_NAME, &o); |
1003 | 14.4k | if (code < 0) |
1004 | 0 | goto error; |
1005 | 14.4k | if (DecodeParams != NULL) { |
1006 | 1.97k | code = pdfi_array_get(ctx, DecodeParams, i, &decode); |
1007 | 1.97k | if (code < 0) { |
1008 | 2 | goto error; |
1009 | 2 | } |
1010 | 1.97k | } |
1011 | 14.4k | if (decode && decode != PDF_NULL_OBJ && pdfi_type_of(decode) != PDF_DICT) { |
1012 | 0 | pdfi_countdown(decode); |
1013 | 0 | decode = NULL; |
1014 | 0 | pdfi_set_warning(ctx, 0, NULL, W_PDF_STREAM_BAD_DECODEPARMS, "pdfi_filter_no_decryption", NULL); |
1015 | 0 | } |
1016 | 14.4k | if (decode && decode == PDF_NULL_OBJ) { |
1017 | 182 | pdfi_countdown(decode); |
1018 | 182 | decode = NULL; |
1019 | 182 | } |
1020 | | |
1021 | 14.4k | code = pdfi_apply_filter(ctx, stream_dict, (pdf_name *)o, |
1022 | 14.4k | (pdf_dict *)decode, s, &new_s, inline_image); |
1023 | 14.4k | pdfi_countdown(decode); |
1024 | 14.4k | decode = NULL; |
1025 | 14.4k | pdfi_countdown(o); |
1026 | 14.4k | o = NULL; |
1027 | 14.4k | if (code < 0) |
1028 | 12 | goto error; |
1029 | | |
1030 | 14.3k | s = new_s; |
1031 | 14.3k | } |
1032 | 14.1k | code = pdfi_alloc_stream(ctx, s, source->s, new_stream); |
1033 | 14.1k | } |
1034 | 2.18M | } |
1035 | | |
1036 | 2.25M | exit: |
1037 | 2.25M | pdfi_countdown(o); |
1038 | 2.25M | pdfi_countdown(o1); |
1039 | 2.25M | pdfi_countdown(DecodeParams); |
1040 | 2.25M | pdfi_countdown(decode); |
1041 | 2.25M | pdfi_countdown(Filter); |
1042 | 2.25M | return code; |
1043 | | |
1044 | 14 | error: |
1045 | 14 | if (s) |
1046 | 14 | pdfi_close_filter_chain(ctx, s, source->s); |
1047 | 14 | *new_stream = NULL; |
1048 | 14 | pdfi_countdown(o); |
1049 | 14 | pdfi_countdown(o1); |
1050 | 14 | pdfi_countdown(DecodeParams); |
1051 | 14 | pdfi_countdown(decode); |
1052 | 14 | pdfi_countdown(Filter); |
1053 | 14 | return code; |
1054 | 2.18M | } |
1055 | | |
1056 | | int pdfi_filter(pdf_context *ctx, pdf_stream *stream_obj, pdf_c_stream *source, |
1057 | | pdf_c_stream **new_stream, bool inline_image) |
1058 | 2.25M | { |
1059 | 2.25M | int code; |
1060 | 2.25M | pdf_c_stream *crypt_stream = NULL, *SubFile_stream = NULL; |
1061 | 2.25M | pdf_string *StreamKey = NULL; |
1062 | 2.25M | pdf_dict *stream_dict = NULL; |
1063 | 2.25M | pdf_obj *FileSpec = NULL; |
1064 | 2.25M | pdf_stream *NewStream = NULL; |
1065 | 2.25M | bool known = false; |
1066 | | |
1067 | 2.25M | *new_stream = NULL; |
1068 | | |
1069 | 2.25M | code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict); |
1070 | 2.25M | if (code < 0) |
1071 | 0 | goto error; |
1072 | | |
1073 | | /* Horrifyingly, any stream dictionary can contain a file specification, which means that |
1074 | | * instead of using the stream from the PDF file we must use an external file. |
1075 | | * So much for portability! |
1076 | | * Note: We must not do this for inline images as an inline image dictionary can |
1077 | | * contain the abbreviation /F for the Filter, and an inline image is never a |
1078 | | * separate stream, it is (obviously) contained in the current stream. |
1079 | | */ |
1080 | 2.25M | if (!inline_image) { |
1081 | 2.24M | code = pdfi_dict_known(ctx, stream_dict, "F", &known); |
1082 | 2.24M | if (code >= 0 && known) { |
1083 | 1 | pdf_obj *FS = NULL, *o = NULL; |
1084 | 1 | pdf_dict *dict = NULL; |
1085 | 1 | stream *gstream = NULL; |
1086 | | |
1087 | 1 | code = pdfi_dict_get(ctx, stream_dict, "F", &FileSpec); |
1088 | 1 | if (code < 0) |
1089 | 0 | goto error; |
1090 | 1 | if (pdfi_type_of(FileSpec) == PDF_DICT) { |
1091 | | /* We don't really support FileSpec dictionaries, partly because we |
1092 | | * don't really know which platform to use. If there is a /F string |
1093 | | * then we will use that, just as if we had been given a string in |
1094 | | * the first place. |
1095 | | */ |
1096 | 0 | code = pdfi_dict_knownget(ctx, (pdf_dict *)FileSpec, "F", &FS); |
1097 | 0 | if (code < 0) { |
1098 | 0 | goto error; |
1099 | 0 | } |
1100 | 0 | pdfi_countdown(FileSpec); |
1101 | 0 | FileSpec = FS; |
1102 | 0 | FS = NULL; |
1103 | 0 | } |
1104 | 1 | if (pdfi_type_of(FileSpec) != PDF_STRING) { |
1105 | 1 | code = gs_note_error(gs_error_typecheck); |
1106 | 1 | goto error; |
1107 | 1 | } |
1108 | | /* We should now have a string with the filename (or URL). We need |
1109 | | * to open the file and create a stream, if that succeeds. |
1110 | | */ |
1111 | 0 | gstream = sfopen((const char *)((pdf_string *)FileSpec)->data, "r", ctx->memory); |
1112 | 0 | if (gstream == NULL) { |
1113 | 0 | emprintf1(ctx->memory, "Failed to open file %s\n", (const char *)((pdf_string *)FileSpec)->data); |
1114 | 0 | code = gs_note_error(gs_error_ioerror); |
1115 | 0 | goto error; |
1116 | 0 | } |
1117 | | |
1118 | 0 | source = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "external stream"); |
1119 | 0 | if (source == NULL) { |
1120 | 0 | code = gs_note_error(gs_error_VMerror); |
1121 | 0 | goto error; |
1122 | 0 | } |
1123 | 0 | memset(source, 0x00, sizeof(pdf_c_stream)); |
1124 | 0 | source->s = gstream; |
1125 | |
|
1126 | 0 | code = pdfi_object_alloc(ctx, PDF_STREAM, 0, (pdf_obj **)&NewStream); |
1127 | 0 | if (code < 0) |
1128 | 0 | goto error; |
1129 | 0 | pdfi_countup(NewStream); |
1130 | 0 | code = pdfi_dict_alloc(ctx, 32, &dict); |
1131 | 0 | if (code < 0){ |
1132 | 0 | pdfi_countdown(NewStream); |
1133 | 0 | goto error; |
1134 | 0 | } |
1135 | 0 | pdfi_countup(dict); |
1136 | 0 | NewStream->stream_dict = dict; |
1137 | 0 | code = pdfi_dict_get(ctx, stream_dict, "FFilter", &o); |
1138 | 0 | if (code >= 0) { |
1139 | 0 | code = pdfi_dict_put(ctx, NewStream->stream_dict, "Filter", o); |
1140 | 0 | if (code < 0) { |
1141 | 0 | pdfi_countdown(NewStream); |
1142 | 0 | goto error; |
1143 | 0 | } |
1144 | 0 | } |
1145 | 0 | code = pdfi_dict_get(ctx, stream_dict, "FPredictor", &o); |
1146 | 0 | if (code >= 0) { |
1147 | 0 | code = pdfi_dict_put(ctx, NewStream->stream_dict, "Predictor", o); |
1148 | 0 | if (code < 0) { |
1149 | 0 | pdfi_countdown(NewStream); |
1150 | 0 | goto error; |
1151 | 0 | } |
1152 | 0 | } |
1153 | 0 | pdfi_countup(NewStream->stream_dict); |
1154 | 0 | NewStream->stream_offset = 0; |
1155 | 0 | NewStream->Length = 0; |
1156 | 0 | NewStream->length_valid = 0; |
1157 | 0 | NewStream->stream_written = 0; |
1158 | 0 | NewStream->is_marking = 0; |
1159 | 0 | NewStream->parent_obj = NULL; |
1160 | 0 | stream_obj = NewStream; |
1161 | 0 | stream_dict = NewStream->stream_dict; |
1162 | 0 | } |
1163 | 2.24M | } |
1164 | | |
1165 | | /* If the file isn't encrypted, don't apply encryption. If this is an inline |
1166 | | * image then its in a content stream and will already be decrypted, so don't |
1167 | | * apply decryption again. |
1168 | | */ |
1169 | 2.25M | if (ctx->encryption.is_encrypted && !inline_image) { |
1170 | 3.11k | int64_t Length; |
1171 | | |
1172 | 3.11k | if (ctx->encryption.StmF == CRYPT_IDENTITY) |
1173 | 0 | return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image); |
1174 | | |
1175 | 3.11k | code = pdfi_dict_get_type(ctx, stream_dict, "StreamKey", PDF_STRING, (pdf_obj **)&StreamKey); |
1176 | 3.11k | if (code == gs_error_undefined) { |
1177 | 1.74k | code = pdfi_compute_objkey(ctx, (pdf_obj *)stream_dict, &StreamKey); |
1178 | 1.74k | if (code < 0) |
1179 | 0 | return code; |
1180 | 1.74k | code = pdfi_dict_put(ctx, stream_dict, "StreamKey", (pdf_obj *)StreamKey); |
1181 | 1.74k | if (code < 0) |
1182 | 0 | goto error; |
1183 | 1.74k | } |
1184 | 3.11k | if (code < 0) |
1185 | 0 | return code; |
1186 | | |
1187 | | /* If we are applying a decryption filter we must also apply a SubFileDecode filter. |
1188 | | * This is because the underlying stream may not have a compression filter, if it doesn't |
1189 | | * then we have no way of detecting the end of the data. Normally we would get an 'endstream' |
1190 | | * token but if we have applied a decryption filter then we'll 'decrypt' that token |
1191 | | * and that will corrupt it. So make sure we can't read past the end of the stream |
1192 | | * by applying a SubFileDecode. |
1193 | | * NB applying a SubFileDecode filter with an EODString seems to limit the amount of data |
1194 | | * that the decode filter is prepared to return at any time to the size of the EODString. |
1195 | | * This doesn't play well with other filters (eg the AESDecode filter) which require a |
1196 | | * larger minimum to be returned (16 bytes for AESDecode). So I'm using the filter |
1197 | | * Length here, even though I'd prefer not to..... |
1198 | | */ |
1199 | 3.11k | Length = pdfi_stream_length(ctx, stream_obj); |
1200 | | |
1201 | 3.11k | if (Length <= 0) { |
1202 | | /* Don't treat as an encrypted stream if Length is 0 */ |
1203 | 10 | pdfi_countdown(StreamKey); |
1204 | 10 | return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image); |
1205 | 10 | } |
1206 | | |
1207 | 3.10k | code = pdfi_apply_SubFileDecode_filter(ctx, Length, NULL, source, &SubFile_stream, false); |
1208 | 3.10k | if (code < 0) |
1209 | 0 | goto error; |
1210 | | |
1211 | 3.10k | SubFile_stream->original = source->s; |
1212 | | |
1213 | 3.10k | switch(ctx->encryption.StrF) { |
1214 | 0 | case CRYPT_IDENTITY: |
1215 | | /* Can't happen, handled above */ |
1216 | 0 | break; |
1217 | | /* There are only two possible filters, RC4 or AES, we take care |
1218 | | * of the number of bits in the key by using ctx->Length. |
1219 | | */ |
1220 | 644 | case CRYPT_V1: |
1221 | 644 | case CRYPT_V2: |
1222 | 644 | code = pdfi_apply_Arc4_filter(ctx, StreamKey, SubFile_stream, &crypt_stream); |
1223 | 644 | break; |
1224 | 2.12k | case CRYPT_AESV2: |
1225 | 2.46k | case CRYPT_AESV3: |
1226 | 2.46k | code = pdfi_apply_AES_filter(ctx, StreamKey, 1, SubFile_stream, &crypt_stream); |
1227 | 2.46k | break; |
1228 | 0 | default: |
1229 | 0 | code = gs_error_rangecheck; |
1230 | 3.10k | } |
1231 | 3.10k | if (code < 0) { |
1232 | 0 | pdfi_close_file(ctx, SubFile_stream); |
1233 | 0 | goto error; |
1234 | 0 | } |
1235 | | |
1236 | 3.10k | crypt_stream->original = SubFile_stream->original; |
1237 | 3.10k | gs_free_object(ctx->memory, SubFile_stream, "pdfi_filter"); |
1238 | | |
1239 | 3.10k | code = pdfi_filter_no_decryption(ctx, stream_obj, crypt_stream, new_stream, false); |
1240 | 3.10k | if (code < 0) { |
1241 | 4 | pdfi_close_file(ctx, crypt_stream); |
1242 | 4 | goto error; |
1243 | 4 | } |
1244 | | |
1245 | 3.10k | (*new_stream)->original = source->s; |
1246 | 3.10k | gs_free_object(ctx->memory, crypt_stream, "pdfi_filter"); |
1247 | 2.25M | } else { |
1248 | 2.25M | code = pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image); |
1249 | 2.25M | } |
1250 | 2.25M | error: |
1251 | 2.25M | pdfi_countdown(NewStream); |
1252 | 2.25M | pdfi_countdown(StreamKey); |
1253 | 2.25M | pdfi_countdown(FileSpec); |
1254 | 2.25M | return code; |
1255 | 2.25M | } |
1256 | | |
1257 | | /* This is just a convenience routine. We could use pdfi_filter() above, but because PDF |
1258 | | * doesn't support the SubFileDecode filter that would mean callers having to manufacture |
1259 | | * a dictionary in order to use it. That's excessively convoluted, so just supply a simple |
1260 | | * means to instantiate a SubFileDecode filter. |
1261 | | * |
1262 | | * NB! The EODString can't be tracked by the stream code. The caller is responsible for |
1263 | | * managing the lifetime of this object. It must remain valid until the filter is closed. |
1264 | | */ |
1265 | | int pdfi_apply_SubFileDecode_filter(pdf_context *ctx, int EODCount, const char *EODString, pdf_c_stream *source, pdf_c_stream **new_stream, bool inline_image) |
1266 | 3.64M | { |
1267 | 3.64M | int code; |
1268 | 3.64M | stream_SFD_state state; |
1269 | 3.64M | stream *new_s = NULL; |
1270 | 3.64M | int min_size = 2048; |
1271 | | |
1272 | 3.64M | *new_stream = NULL; |
1273 | | |
1274 | 3.64M | memset(&state, 0, sizeof(state)); |
1275 | | |
1276 | 3.64M | if (s_SFD_template.set_defaults) |
1277 | 3.64M | s_SFD_template.set_defaults((stream_state *)&state); |
1278 | | |
1279 | 3.64M | if (EODString != NULL) { |
1280 | 801k | state.eod.data = (const byte *)EODString; |
1281 | 801k | state.eod.size = strlen(EODString); |
1282 | 801k | } |
1283 | | |
1284 | 3.64M | if (EODCount > 0) |
1285 | 2.84M | state.count = EODCount - source->unread_size; |
1286 | 803k | else |
1287 | 803k | state.count = EODCount; |
1288 | | |
1289 | 3.64M | code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_SFD_template, (const stream_state *)&state, ctx->memory->non_gc_memory, &new_s); |
1290 | 3.64M | if (code < 0) |
1291 | 0 | return code; |
1292 | | |
1293 | 3.64M | code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream); |
1294 | 3.64M | if (code < 0) { |
1295 | 0 | gs_free_object(ctx->memory->non_gc_memory, new_s->state, "pdfi_apply_SubFileDecode_filter"); |
1296 | 0 | gs_free_object(ctx->memory->non_gc_memory, new_s->cbuf, "pdfi_apply_SubFileDecode_filter"); |
1297 | 0 | gs_free_object(ctx->memory->non_gc_memory, new_s, "pdfi_apply_SubFileDecode_filter"); |
1298 | 0 | return code; |
1299 | 0 | } |
1300 | 3.64M | new_s->strm = source->s; |
1301 | 3.64M | if (source->unread_size != 0) { |
1302 | 0 | (*new_stream)->unread_size = source->unread_size; |
1303 | 0 | memcpy((*new_stream)->unget_buffer, source->unget_buffer, source->unread_size); |
1304 | 0 | source->unread_size = 0; |
1305 | 0 | } |
1306 | 3.64M | return code; |
1307 | 3.64M | } |
1308 | | |
1309 | | /* We would really like to use a ReusableStreamDecode filter here, but that filter is defined |
1310 | | * purely in the PostScript interpreter. So instead we make a temporary stream from a |
1311 | | * memory buffer. Its icky (we can end up with the same data in memory multiple times) |
1312 | | * but it works, and is used elsewhere in Ghostscript. |
1313 | | * If retain_ownership is true then the calling function is responsible for buffer pointer lifetime. |
1314 | | * Otherwise the buffer will be freed when the stream is closed. |
1315 | | */ |
1316 | | int pdfi_open_memory_stream_from_stream(pdf_context *ctx, unsigned int size, byte **Buffer, pdf_c_stream *source, pdf_c_stream **new_pdf_stream, bool retain_ownership) |
1317 | 36.4k | { |
1318 | 36.4k | stream *new_stream; |
1319 | 36.4k | int code; |
1320 | | |
1321 | 36.4k | new_stream = file_alloc_stream(ctx->memory, "open memory stream(stream)"); |
1322 | 36.4k | if (new_stream == NULL) |
1323 | 0 | return_error(gs_error_VMerror); |
1324 | | |
1325 | 36.4k | *Buffer = gs_alloc_bytes(ctx->memory, size, "open memory stream (buffer)"); |
1326 | 36.4k | if (*Buffer == NULL) { |
1327 | 0 | gs_free_object(ctx->memory, new_stream, "open memory stream(stream)"); |
1328 | 0 | return_error(gs_error_VMerror); |
1329 | 0 | } |
1330 | 36.4k | code = pdfi_read_bytes(ctx, *Buffer, 1, size, source); |
1331 | 36.4k | if (code < 0) { |
1332 | 0 | gs_free_object(ctx->memory, *Buffer, "open memory stream(buffer)"); |
1333 | 0 | gs_free_object(ctx->memory, new_stream, "open memory stream(stream)"); |
1334 | 0 | return code; |
1335 | 0 | } |
1336 | | |
1337 | 36.4k | if (retain_ownership) |
1338 | 17.5k | sread_string_reusable(new_stream, *Buffer, size); |
1339 | 18.8k | else |
1340 | 18.8k | sread_transient_string_reusable(new_stream, ctx->memory, *Buffer, size); |
1341 | | |
1342 | 36.4k | code = pdfi_alloc_stream(ctx, new_stream, source->s, new_pdf_stream); |
1343 | 36.4k | if (code < 0) { |
1344 | 0 | sclose(new_stream); |
1345 | 0 | gs_free_object(ctx->memory, *Buffer, "open memory stream(buffer)"); |
1346 | 0 | gs_free_object(ctx->memory, new_stream, "open memory stream(stream)"); |
1347 | 0 | } |
1348 | | |
1349 | 36.4k | return code; |
1350 | 36.4k | } |
1351 | | |
1352 | | /* |
1353 | | * Like pdfi_open_memory_stream_from_stream (and makes use of it) this is a way to read from a stream into |
1354 | | * memory, and return a stream which reads from that memory. The difference is that this function takes |
1355 | | * any filters into account, decompressing them. We could layer a decompression stream onto the memory |
1356 | | * stream returned by open_memory_stream_from_stream above instead. |
1357 | | * |
1358 | | * This function returns < 0 for an error, and the length of the uncompressed data on success. |
1359 | | */ |
1360 | | int pdfi_open_memory_stream_from_filtered_stream(pdf_context *ctx, pdf_stream *stream_obj, |
1361 | | unsigned int size, byte **Buffer, pdf_c_stream *source, |
1362 | | pdf_c_stream **new_pdf_stream, bool retain_ownership) |
1363 | 36.4k | { |
1364 | 36.4k | int code; |
1365 | 36.4k | pdf_dict *dict = NULL; |
1366 | 36.4k | int decompressed_length = 0; |
1367 | 36.4k | byte *decompressed_Buffer = NULL; |
1368 | 36.4k | pdf_c_stream *compressed_stream = NULL, *decompressed_stream = NULL; |
1369 | 36.4k | bool known = false; |
1370 | | |
1371 | 36.4k | code = pdfi_open_memory_stream_from_stream(ctx, (unsigned int)size, Buffer, source, new_pdf_stream, retain_ownership); |
1372 | 36.4k | if (code < 0) { |
1373 | 0 | pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream); |
1374 | 0 | *Buffer = NULL; |
1375 | 0 | *new_pdf_stream = NULL; |
1376 | 0 | return code; |
1377 | 0 | } |
1378 | | |
1379 | 36.4k | if (stream_obj == NULL) |
1380 | 0 | return size; |
1381 | | |
1382 | 36.4k | code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &dict); |
1383 | 36.4k | if (code < 0) |
1384 | 0 | return code; |
1385 | | |
1386 | 36.4k | pdfi_dict_known(ctx, dict, "F", &known); |
1387 | 36.4k | if (!known) |
1388 | 36.4k | pdfi_dict_known(ctx, dict, "Filter", &known); |
1389 | | |
1390 | 36.4k | if (!known) |
1391 | 4.32k | return size; |
1392 | | |
1393 | 32.0k | compressed_stream = *new_pdf_stream; |
1394 | | /* This is again complicated by requiring a seekable stream, and the fact that, |
1395 | | * unlike fonts, there is no Length2 key to tell us how large the uncompressed |
1396 | | * stream is. |
1397 | | */ |
1398 | 32.0k | code = pdfi_filter(ctx, stream_obj, compressed_stream, &decompressed_stream, false); |
1399 | 32.0k | if (code < 0) { |
1400 | 126 | pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream); |
1401 | 126 | *Buffer = NULL; |
1402 | 126 | *new_pdf_stream = NULL; |
1403 | 126 | return code; |
1404 | 126 | } |
1405 | 123k | do { |
1406 | 123k | byte b[512]; |
1407 | 123k | code = pdfi_read_bytes(ctx, (byte *)&b, 1, 512, decompressed_stream); |
1408 | 123k | if (code <= 0) |
1409 | 10.1k | break; |
1410 | 113k | decompressed_length+=code; |
1411 | 113k | if (code < 512) |
1412 | 21.8k | break; |
1413 | 113k | } while (true); |
1414 | 0 | pdfi_close_file(ctx, decompressed_stream); |
1415 | | |
1416 | 31.9k | decompressed_Buffer = gs_alloc_bytes(ctx->memory, decompressed_length, "pdfi_open_memory_stream_from_filtered_stream (decompression buffer)"); |
1417 | 31.9k | if (decompressed_Buffer != NULL) { |
1418 | 31.9k | code = srewind(compressed_stream->s); |
1419 | 31.9k | if (code >= 0) { |
1420 | 31.9k | code = pdfi_filter(ctx, stream_obj, compressed_stream, |
1421 | 31.9k | &decompressed_stream, false); |
1422 | 31.9k | if (code >= 0) { |
1423 | 31.9k | code = pdfi_read_bytes(ctx, decompressed_Buffer, 1, decompressed_length, decompressed_stream); |
1424 | 31.9k | pdfi_close_file(ctx, decompressed_stream); |
1425 | 31.9k | code = pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream); |
1426 | 31.9k | if (code >= 0) { |
1427 | 31.9k | *Buffer = decompressed_Buffer; |
1428 | 31.9k | code = pdfi_open_memory_stream_from_memory(ctx, (unsigned int)decompressed_length, |
1429 | 31.9k | *Buffer, new_pdf_stream, retain_ownership); |
1430 | 31.9k | } else { |
1431 | 0 | *Buffer = NULL; |
1432 | 0 | *new_pdf_stream = NULL; |
1433 | 0 | } |
1434 | 31.9k | } |
1435 | 31.9k | } else { |
1436 | 0 | pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream); |
1437 | 0 | gs_free_object(ctx->memory, decompressed_Buffer, "pdfi_open_memory_stream_from_filtered_stream"); |
1438 | 0 | gs_free_object(ctx->memory, Buffer, "pdfi_open_memory_stream_from_filtered_stream"); |
1439 | 0 | *Buffer = NULL; |
1440 | 0 | *new_pdf_stream = NULL; |
1441 | 0 | return code; |
1442 | 0 | } |
1443 | 31.9k | } else { |
1444 | 0 | pdfi_close_memory_stream(ctx, *Buffer, *new_pdf_stream); |
1445 | 0 | gs_free_object(ctx->memory, Buffer, "pdfi_open_memory_stream_from_filtered_stream"); |
1446 | 0 | *Buffer = NULL; |
1447 | 0 | *new_pdf_stream = NULL; |
1448 | 0 | return_error(gs_error_VMerror); |
1449 | 0 | } |
1450 | 31.9k | if (code < 0) { |
1451 | 0 | gs_free_object(ctx->memory, Buffer, "pdfi_build_function_4"); |
1452 | 0 | *Buffer = NULL; |
1453 | 0 | *new_pdf_stream = NULL; |
1454 | 0 | return code; |
1455 | 0 | } |
1456 | 31.9k | return decompressed_length; |
1457 | 31.9k | } |
1458 | | |
1459 | | int pdfi_open_memory_stream_from_memory(pdf_context *ctx, unsigned int size, byte *Buffer, pdf_c_stream **new_pdf_stream, bool retain_ownership) |
1460 | 112k | { |
1461 | 112k | int code; |
1462 | 112k | stream *new_stream; |
1463 | | |
1464 | 112k | new_stream = file_alloc_stream(ctx->memory, "open memory stream from memory(stream)"); |
1465 | 112k | if (new_stream == NULL) |
1466 | 0 | return_error(gs_error_VMerror); |
1467 | 112k | new_stream->close_at_eod = false; |
1468 | 112k | if (retain_ownership) |
1469 | 97.4k | sread_string(new_stream, Buffer, size); |
1470 | 14.7k | else |
1471 | 14.7k | sread_transient_string(new_stream, ctx->memory, Buffer, size); |
1472 | | |
1473 | 112k | code = pdfi_alloc_stream(ctx, new_stream, NULL, new_pdf_stream); |
1474 | 112k | if (code < 0) { |
1475 | 0 | sclose(new_stream); |
1476 | 0 | gs_free_object(ctx->memory, new_stream, "open memory stream from memory(stream)"); |
1477 | 0 | } |
1478 | | |
1479 | 112k | return code; |
1480 | 112k | } |
1481 | | |
1482 | | int pdfi_close_memory_stream(pdf_context *ctx, byte *Buffer, pdf_c_stream *source) |
1483 | 102k | { |
1484 | 102k | gs_free_object(ctx->memory, Buffer, "open memory stream(buffer)"); |
1485 | 102k | if (source != NULL) { |
1486 | 102k | if (source->s != NULL) { |
1487 | 102k | sclose(source->s); |
1488 | 102k | gs_free_object(ctx->memory, source->s, "open memory stream(stream)"); |
1489 | 102k | } |
1490 | 102k | gs_free_object(ctx->memory, source, "open memory stream(pdf_stream)"); |
1491 | 102k | } |
1492 | 102k | return 0; |
1493 | 102k | } |
1494 | | |
1495 | | /***********************************************************************************/ |
1496 | | /* Basic 'file' operations. Because of the need to 'unread' bytes we need our own */ |
1497 | | |
1498 | | static void pdfi_close_filter_chain(pdf_context *ctx, stream *s, stream *target) |
1499 | 5.93M | { |
1500 | 5.93M | stream *next_s = s; |
1501 | | |
1502 | 11.8M | while(next_s && next_s != target){ |
1503 | 5.88M | stream *curr_s = next_s; |
1504 | 5.88M | next_s = next_s->strm; |
1505 | 5.88M | if (curr_s != ctx->main_stream->s) |
1506 | 5.88M | sfclose(curr_s); |
1507 | 5.88M | } |
1508 | 5.93M | } |
1509 | | |
1510 | | void pdfi_close_file(pdf_context *ctx, pdf_c_stream *s) |
1511 | 5.93M | { |
1512 | 5.93M | pdfi_close_filter_chain(ctx, s->s, s->original); |
1513 | | |
1514 | 5.93M | gs_free_object(ctx->memory, s, "closing pdf_file"); |
1515 | 5.93M | } |
1516 | | |
1517 | | int pdfi_seek(pdf_context *ctx, pdf_c_stream *s, gs_offset_t offset, uint32_t origin) |
1518 | 9.10M | { |
1519 | 9.10M | if (origin == SEEK_CUR && s->unread_size != 0) |
1520 | 0 | offset -= s->unread_size; |
1521 | | |
1522 | 9.10M | s->unread_size = 0;; |
1523 | | |
1524 | 9.10M | return (sfseek(s->s, offset, origin)); |
1525 | 9.10M | } |
1526 | | |
1527 | | /* We use 'stell' sometimes to save the position of the underlying file |
1528 | | * when reading a compressed stream, so that we can return to the same |
1529 | | * point in the underlying file after performing some other operation. This |
1530 | | * allows us (for instance) to load a font while interpreting a content stream. |
1531 | | * However, if we've 'unread' any bytes we need to take that into account. |
1532 | | * NOTE! this is only going to be valid when performed on the main stream |
1533 | | * the original PDF file, not any compressed stream! |
1534 | | */ |
1535 | | gs_offset_t pdfi_unread_tell(pdf_context *ctx) |
1536 | 72.7M | { |
1537 | 72.7M | gs_offset_t off = stell(ctx->main_stream->s); |
1538 | | |
1539 | 72.7M | return (off - ctx->main_stream->unread_size); |
1540 | 72.7M | } |
1541 | | |
1542 | | gs_offset_t pdfi_tell(pdf_c_stream *s) |
1543 | 519k | { |
1544 | 519k | return stell(s->s); |
1545 | 519k | } |
1546 | | |
1547 | | int pdfi_unread_byte(pdf_context *ctx, pdf_c_stream *s, char c) |
1548 | 1.07G | { |
1549 | 1.07G | if (s->unread_size == UNREAD_BUFFER_SIZE) |
1550 | 0 | return_error(gs_error_ioerror); |
1551 | | |
1552 | 1.07G | s->unget_buffer[s->unread_size++] = c; |
1553 | | |
1554 | 1.07G | return 0; |
1555 | 1.07G | } |
1556 | | |
1557 | | int pdfi_unread(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, uint32_t size) |
1558 | 97.2k | { |
1559 | 97.2k | if (size + s->unread_size > UNREAD_BUFFER_SIZE) |
1560 | 6 | return_error(gs_error_ioerror); |
1561 | | |
1562 | 97.2k | Buffer += size; |
1563 | 370k | while (size) { |
1564 | 273k | s->unget_buffer[s->unread_size++] = *--Buffer; |
1565 | 273k | size--; |
1566 | 273k | } |
1567 | | |
1568 | 97.2k | return 0; |
1569 | 97.2k | } |
1570 | | |
1571 | | int pdfi_read_byte(pdf_context *ctx, pdf_c_stream *s) |
1572 | 10.0G | { |
1573 | 10.0G | int32_t code; |
1574 | | |
1575 | 10.0G | if (s->eof && s->unread_size == 0) |
1576 | 253k | return EOFC; |
1577 | | |
1578 | 10.0G | if (s->unread_size) |
1579 | 1.07G | return (byte)s->unget_buffer[--s->unread_size]; |
1580 | | |
1581 | | /* TODO the Ghostscript code uses sbufptr(s) to avoid a memcpy |
1582 | | * at some point we should modify this code to do so as well. |
1583 | | */ |
1584 | 9.01G | code = spgetc(s->s); |
1585 | 9.01G | if (code == EOFC) { |
1586 | 345k | s->eof = true; |
1587 | 345k | return EOFC; |
1588 | 9.01G | } else if (code == gs_error_ioerror) { |
1589 | 0 | pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL); |
1590 | 0 | s->eof = true; |
1591 | 0 | return EOFC; |
1592 | 9.01G | } else if(code == ERRC) { |
1593 | 67.4k | return ERRC; |
1594 | 67.4k | } |
1595 | 9.01G | return (int)code; |
1596 | 9.01G | } |
1597 | | |
1598 | | |
1599 | | int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t count, pdf_c_stream *s) |
1600 | 2.66M | { |
1601 | 2.66M | uint32_t i = 0, total = size * count; |
1602 | 2.66M | uint32_t bytes = 0; |
1603 | 2.66M | int32_t code; |
1604 | | |
1605 | 2.66M | if (s->eof && s->unread_size == 0) |
1606 | 3.68k | return 0; |
1607 | | |
1608 | 2.66M | if (s->unread_size) { |
1609 | 17.7k | i = s->unread_size; |
1610 | 17.7k | if (i >= total) |
1611 | 0 | i = total; |
1612 | 17.7k | bytes = i; |
1613 | 36.1k | while (bytes) { |
1614 | 18.4k | *Buffer++ = s->unget_buffer[--s->unread_size]; |
1615 | 18.4k | bytes--; |
1616 | 18.4k | } |
1617 | 17.7k | total -= i; |
1618 | 17.7k | if (total == 0 || s->eof) |
1619 | 0 | return i; |
1620 | 17.7k | } |
1621 | | |
1622 | | /* TODO the Ghostscript code uses sbufptr(s) to avoid a memcpy |
1623 | | * at some point we should modify this code to do so as well. |
1624 | | */ |
1625 | 2.66M | code = sgets(s->s, Buffer, total, &bytes); |
1626 | 2.66M | if (code == EOFC) { |
1627 | 25.5k | s->eof = true; |
1628 | 2.63M | } else if (code == gs_error_ioerror) { |
1629 | 0 | pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL); |
1630 | 0 | s->eof = true; |
1631 | 2.63M | } else if(code == ERRC) { |
1632 | 7.55k | bytes = ERRC; |
1633 | 2.63M | } else { |
1634 | 2.63M | bytes = bytes + i; |
1635 | 2.63M | } |
1636 | | |
1637 | 2.66M | return bytes; |
1638 | 2.66M | } |
1639 | | |
1640 | | /* Read bytes from stream object into buffer. |
1641 | | * Handles both plain streams and filtered streams. |
1642 | | * Buffer gets allocated here, and must be freed by caller. |
1643 | | * Preserves the location of the current stream file position. |
1644 | | */ |
1645 | | int |
1646 | | pdfi_stream_to_buffer(pdf_context *ctx, pdf_stream *stream_obj, byte **buf, int64_t *bufferlen) |
1647 | 41.1k | { |
1648 | 41.1k | byte *Buffer = NULL; |
1649 | 41.1k | int code = 0; |
1650 | 41.1k | int64_t buflen = 0, read = 0, ToRead = *bufferlen; |
1651 | 41.1k | gs_offset_t savedoffset; |
1652 | 41.1k | pdf_c_stream *stream; |
1653 | 41.1k | bool filtered; |
1654 | 41.1k | pdf_dict *stream_dict = NULL; |
1655 | | |
1656 | 41.1k | savedoffset = pdfi_tell(ctx->main_stream); |
1657 | | |
1658 | 41.1k | pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET); |
1659 | | |
1660 | 41.1k | code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict); |
1661 | 41.1k | if (code < 0) |
1662 | 0 | goto exit; |
1663 | | |
1664 | | /* See if this is a filtered stream */ |
1665 | 41.1k | code = pdfi_dict_known(ctx, stream_dict, "Filter", &filtered); |
1666 | 41.1k | if (code < 0) |
1667 | 0 | goto exit; |
1668 | | |
1669 | 41.1k | if (!filtered) { |
1670 | 4.02k | code = pdfi_dict_known(ctx, stream_dict, "F", &filtered); |
1671 | 4.02k | if (code < 0) |
1672 | 0 | goto exit; |
1673 | 4.02k | } |
1674 | | |
1675 | 41.1k | retry: |
1676 | 41.1k | if (ToRead == 0) { |
1677 | 38.3k | if (filtered || ctx->encryption.is_encrypted) { |
1678 | 36.1k | code = pdfi_filter(ctx, stream_obj, ctx->main_stream, &stream, false); |
1679 | 36.1k | if (code < 0) { |
1680 | 36 | goto exit; |
1681 | 36 | } |
1682 | 522k | while (seofp(stream->s) != true && serrorp(stream->s) != true) { |
1683 | 486k | (void)sbufskip(stream->s, sbufavailable(stream->s)); |
1684 | 486k | s_process_read_buf(stream->s); |
1685 | 486k | buflen += sbufavailable(stream->s); |
1686 | 486k | } |
1687 | 36.0k | pdfi_close_file(ctx, stream); |
1688 | 36.0k | } else { |
1689 | 2.25k | buflen = pdfi_stream_length(ctx, stream_obj); |
1690 | 2.25k | } |
1691 | 38.3k | } else |
1692 | 2.82k | buflen = *bufferlen; |
1693 | | |
1694 | | /* Alloc buffer */ |
1695 | 41.1k | Buffer = gs_alloc_bytes(ctx->memory, buflen, "pdfi_stream_to_buffer (Buffer)"); |
1696 | 41.1k | if (!Buffer) { |
1697 | 4 | code = gs_note_error(gs_error_VMerror); |
1698 | 4 | goto exit; |
1699 | 4 | } |
1700 | | |
1701 | 41.1k | code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET); |
1702 | 41.1k | if (code < 0) { |
1703 | 0 | buflen = 0; |
1704 | 0 | goto exit; |
1705 | 0 | } |
1706 | 41.1k | if (filtered || ctx->encryption.is_encrypted) { |
1707 | 37.1k | code = pdfi_filter(ctx, stream_obj, ctx->main_stream, &stream, false); |
1708 | 37.1k | if (code < 0) |
1709 | 4 | goto exit; |
1710 | 37.1k | read = sfread(Buffer, 1, buflen, stream->s); |
1711 | 37.1k | if (read == ERRC) { |
1712 | | /* Error reading the expected number of bytes. If we already calculated the number of |
1713 | | * bytes in the loop above, then ignore the error and carry on. If, however, we were |
1714 | | * told how many bytes to expect, and failed to read that many, go back and do this |
1715 | | * the slow way to determine how many bytes are *really* available. |
1716 | | */ |
1717 | 77 | if(ToRead != 0) { |
1718 | 51 | buflen = ToRead = 0; |
1719 | 51 | pdfi_close_file(ctx, stream); |
1720 | 51 | code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET); |
1721 | 51 | if (code < 0) |
1722 | 0 | goto exit; |
1723 | 51 | gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)"); |
1724 | 51 | goto retry; |
1725 | 51 | } |
1726 | 77 | } |
1727 | 37.0k | pdfi_close_file(ctx, stream); |
1728 | 37.0k | } else { |
1729 | 4.01k | read = sfread(Buffer, 1, buflen, ctx->main_stream->s); |
1730 | 4.01k | if (read == ERRC) { |
1731 | | /* Error reading the expected number of bytes. If we already calculated the number of |
1732 | | * bytes in the loop above, then ignore the error and carry on. If, however, we were |
1733 | | * told how many bytes to expect, and failed to read that many, go back and do this |
1734 | | * the slow way to determine how many bytes are *really* available. |
1735 | | */ |
1736 | 0 | if(ToRead != 0) { |
1737 | 0 | buflen = ToRead = 0; |
1738 | 0 | code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET); |
1739 | 0 | if (code < 0) |
1740 | 0 | goto exit; |
1741 | 0 | gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)"); |
1742 | 0 | goto retry; |
1743 | 0 | } |
1744 | 0 | } |
1745 | 4.01k | } |
1746 | | |
1747 | 41.1k | exit: |
1748 | 41.1k | pdfi_seek(ctx, ctx->main_stream, savedoffset, SEEK_SET); |
1749 | 41.1k | if (Buffer && code < 0) |
1750 | 4 | gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)"); |
1751 | 41.1k | else |
1752 | 41.1k | *buf = Buffer; |
1753 | 41.1k | *bufferlen = buflen; |
1754 | 41.1k | return code; |
1755 | 41.1k | } |
1756 | | |
1757 | | int pdfi_open_resource_file(pdf_context *ctx, const char *fname, const int fnamelen, stream **s) |
1758 | 323k | { |
1759 | 323k | int code = 0; |
1760 | 323k | if (fname == NULL || fnamelen == 0) |
1761 | 0 | *s = NULL; |
1762 | 323k | else if (gp_file_name_is_absolute(fname, fnamelen) || fname[0] == '%') { |
1763 | | /* If it's an absolute path or an explicit PS style device, just try to open it */ |
1764 | 0 | *s = sfopen(fname, "r", ctx->memory); |
1765 | 0 | } |
1766 | 323k | else { |
1767 | 323k | char fnametotry[gp_file_name_sizeof]; |
1768 | 323k | uint fnlen; |
1769 | 323k | gs_parsed_file_name_t pname; |
1770 | 323k | gp_file_name_combine_result r; |
1771 | 323k | int i, total; |
1772 | | |
1773 | 323k | *s = NULL; |
1774 | 323k | i = 0; |
1775 | 323k | total = ctx->search_paths.num_resource_paths - ctx->search_paths.num_init_resource_paths - 1; |
1776 | 622k | retry: |
1777 | 4.61M | for (; i < total; i++) { |
1778 | 4.00M | gs_param_string *ss = &ctx->search_paths.resource_paths[i]; |
1779 | | |
1780 | 4.00M | if (ss->data[0] == '%') { |
1781 | 631k | code = gs_parse_file_name(&pname, (char *)ss->data, ss->size, ctx->memory); |
1782 | 631k | if (code < 0 || (pname.len + fnamelen >= gp_file_name_sizeof)) { |
1783 | 0 | continue; |
1784 | 0 | } |
1785 | 631k | memcpy(fnametotry, pname.fname, pname.len); |
1786 | 631k | memcpy(fnametotry + pname.len, fname, fnamelen); |
1787 | 631k | code = pname.iodev->procs.open_file(pname.iodev, fnametotry, pname.len + fnamelen, "r", s, ctx->memory); |
1788 | 631k | if (code < 0) { |
1789 | 615k | continue; |
1790 | 615k | } |
1791 | 16.3k | break; |
1792 | 631k | } |
1793 | 3.37M | else { |
1794 | 3.37M | fnlen = gp_file_name_sizeof; |
1795 | 3.37M | r = gp_file_name_combine((char *)ss->data, ss->size, fname, fnamelen, false, fnametotry, &fnlen); |
1796 | 3.37M | if (r != gp_combine_success || fnlen > gp_file_name_sizeof - 1) |
1797 | 0 | continue; |
1798 | 3.37M | fnametotry[fnlen] = '\0'; |
1799 | 3.37M | *s = sfopen(fnametotry, "r", ctx->memory); |
1800 | 3.37M | if (*s != NULL) |
1801 | 0 | break; |
1802 | 3.37M | } |
1803 | 4.00M | } |
1804 | 622k | if (*s == NULL && i < ctx->search_paths.num_resource_paths) { |
1805 | 307k | gs_param_string *ss = &ctx->search_paths.genericresourcedir; |
1806 | 307k | fnlen = gp_file_name_sizeof; |
1807 | 307k | r = gp_file_name_combine((char *)ss->data, ss->size, fname, fnamelen, false, fnametotry, &fnlen); |
1808 | 307k | if (r == gp_combine_success || fnlen < gp_file_name_sizeof) { |
1809 | 307k | fnametotry[fnlen] = '\0'; |
1810 | 307k | *s = sfopen(fnametotry, "r", ctx->memory); |
1811 | 307k | } |
1812 | 307k | } |
1813 | 622k | if (*s == NULL && i < ctx->search_paths.num_resource_paths) { |
1814 | 298k | total = ctx->search_paths.num_resource_paths; |
1815 | 298k | goto retry; |
1816 | 298k | } |
1817 | 622k | } |
1818 | 323k | if (*s == NULL) |
1819 | 298k | return_error(gs_error_invalidfileaccess); |
1820 | | |
1821 | 25.4k | return 0; |
1822 | 323k | } |
1823 | | |
1824 | | int pdfi_open_font_file(pdf_context *ctx, const char *fname, const int fnamelen, stream **s) |
1825 | 316k | { |
1826 | 316k | int code = 0; |
1827 | 316k | const char *fontdirstr = "Font/"; |
1828 | 316k | const int fontdirstrlen = strlen(fontdirstr); |
1829 | | |
1830 | 316k | if (fname == NULL || fnamelen == 0) |
1831 | 0 | *s = NULL; |
1832 | 316k | else if (gp_file_name_is_absolute(fname, fnamelen) || fname[0] == '%') { |
1833 | | /* If it's an absolute path or an explicit PS style device, just try to open it */ |
1834 | 0 | *s = sfopen(fname, "r", ctx->memory); |
1835 | 0 | } |
1836 | 316k | else { |
1837 | 316k | char fnametotry[gp_file_name_sizeof]; |
1838 | 316k | uint fnlen; |
1839 | 316k | gs_parsed_file_name_t pname; |
1840 | 316k | gp_file_name_combine_result r; |
1841 | 316k | int i; |
1842 | | |
1843 | 316k | *s = NULL; |
1844 | 316k | for (i = 0; i < ctx->search_paths.num_font_paths; i++) { |
1845 | 0 | gs_param_string *ss = &ctx->search_paths.font_paths[i]; |
1846 | |
|
1847 | 0 | if (ss->data[0] == '%') { |
1848 | 0 | code = gs_parse_file_name(&pname, (char *)ss->data, ss->size, ctx->memory); |
1849 | 0 | if (code < 0 || (pname.len + fnamelen >= gp_file_name_sizeof)) { |
1850 | 0 | continue; |
1851 | 0 | } |
1852 | 0 | memcpy(fnametotry, pname.fname, pname.len); |
1853 | 0 | memcpy(fnametotry + pname.len, fname, fnamelen); |
1854 | 0 | code = pname.iodev->procs.open_file(pname.iodev, fnametotry, pname.len + fnamelen, "r", s, ctx->memory); |
1855 | 0 | if (code < 0) { |
1856 | 0 | continue; |
1857 | 0 | } |
1858 | 0 | break; |
1859 | 0 | } |
1860 | 0 | else { |
1861 | 0 | fnlen = gp_file_name_sizeof; |
1862 | 0 | r = gp_file_name_combine((char *)ss->data, ss->size, fname, fnamelen, false, fnametotry, &fnlen); |
1863 | 0 | if (r != gp_combine_success || fnlen > gp_file_name_sizeof - 1) |
1864 | 0 | continue; |
1865 | 0 | fnametotry[fnlen] = '\0'; |
1866 | 0 | *s = sfopen(fnametotry, "r", ctx->memory); |
1867 | 0 | if (*s != NULL) |
1868 | 0 | break; |
1869 | 0 | } |
1870 | 0 | } |
1871 | 316k | if (*s == NULL && i < ctx->search_paths.num_resource_paths) { |
1872 | 316k | gs_param_string *ss = &ctx->search_paths.genericresourcedir; |
1873 | 316k | char fstr[gp_file_name_sizeof]; |
1874 | | |
1875 | 316k | fnlen = gp_file_name_sizeof; |
1876 | | |
1877 | 316k | memcpy(fstr, fontdirstr, fontdirstrlen); |
1878 | 316k | memcpy(fstr + fontdirstrlen, fname, fnamelen); |
1879 | | |
1880 | 316k | r = gp_file_name_combine((char *)ss->data, ss->size, fstr, fontdirstrlen + fnamelen, false, fnametotry, &fnlen); |
1881 | 316k | if (r == gp_combine_success || fnlen < gp_file_name_sizeof) { |
1882 | 316k | fnametotry[fnlen] = '\0'; |
1883 | 316k | *s = sfopen(fnametotry, "r", ctx->memory); |
1884 | 316k | } |
1885 | 316k | } |
1886 | 316k | } |
1887 | 316k | if (*s == NULL) |
1888 | 295k | return pdfi_open_resource_file(ctx, fname, fnamelen, s); |
1889 | | |
1890 | 20.4k | return 0; |
1891 | 316k | } |