Coverage Report

Created: 2026-02-14 07:09

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