Coverage Report

Created: 2025-12-31 07:31

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
9.29M
{
69
9.29M
    *new_stream = NULL;
70
9.29M
    *new_stream = (pdf_c_stream *)gs_alloc_bytes(ctx->memory, sizeof(pdf_c_stream), "pdfi_alloc_stream");
71
9.29M
    if (*new_stream == NULL)
72
0
        return_error(gs_error_VMerror);
73
9.29M
    memset(*new_stream, 0x00, sizeof(pdf_c_stream));
74
9.29M
    (*new_stream)->eof = false;
75
9.29M
    ((pdf_c_stream *)(*new_stream))->s = source;
76
9.29M
    ((pdf_c_stream *)(*new_stream))->original = original;
77
9.29M
    return 0;
78
9.29M
}
79
80
/***********************************************************************************/
81
/* Decompression filters.                                                          */
82
83
static int
84
pdfi_filter_report_error(stream_state * st, const char *str)
85
6.75k
{
86
6.75k
    if_debug1m('s', st->memory, "[s]stream error: %s\n", str);
87
6.75k
    strncpy(st->error_string, str, STREAM_MAX_ERROR_STRING);
88
    /* Ensure null termination. */
89
6.75k
    st->error_string[STREAM_MAX_ERROR_STRING] = 0;
90
6.75k
    return 0;
91
6.75k
}
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
8.38M
{
99
8.38M
    stream *s;
100
8.38M
    uint ssize = gs_struct_type_size(templat->stype);
101
8.38M
    stream_state *sst = NULL;
102
8.38M
    int code;
103
104
8.38M
    if (templat->stype != &st_stream_state) {
105
8.38M
        sst = s_alloc_state(mem, templat->stype, "pdfi_filter_open(stream_state)");
106
8.38M
        if (sst == NULL)
107
0
            return_error(gs_error_VMerror);
108
8.38M
        if (templat->set_defaults != NULL) {
109
8.30M
            (*templat->set_defaults)(sst);
110
8.30M
        }
111
8.38M
    }
112
8.38M
    if (buffer_size < 128)
113
56.5k
        buffer_size = file_default_buffer_size;
114
115
8.38M
    code = file_open_stream((char *)0, 0, "r", buffer_size, &s,
116
8.38M
                                (gx_io_device *)0, (iodev_proc_fopen_t)0, mem);
117
8.38M
    if (code < 0) {
118
0
        gs_free_object(mem, sst, "pdfi_filter_open(stream_state)");
119
0
        return code;
120
0
    }
121
8.38M
    s_std_init(s, s->cbuf, s->bsize, procs, s_mode_read);
122
8.38M
    s->procs.process = templat->process;
123
8.38M
    s->save_close = s->procs.close;
124
8.38M
    s->procs.close = file_close_file;
125
8.38M
    s->close_at_eod = 0;
126
8.38M
    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
8.38M
    } else if (st != NULL)         /* might not have client parameters */
131
8.38M
        memcpy(sst, st, ssize);
132
8.38M
    s->state = sst;
133
8.38M
    s_init_state(sst, templat, mem);
134
8.38M
    sst->report_error = pdfi_filter_report_error;
135
136
8.38M
    if (templat->init != NULL) {
137
8.36M
        code = (*templat->init)(sst);
138
8.36M
        if (code < 0) {
139
8
            gs_free_object(mem, sst, "filter_open(stream_state)");
140
8
            gs_free_object(mem, s->cbuf, "filter_open(buffer)");
141
8
            gs_free_object(mem, s, "filter_open(stream)");
142
8
            return code;
143
8
        }
144
8.36M
    }
145
8.38M
    *new_stream = s;
146
8.38M
    return 0;
147
8.38M
}
148
149
static int pdfi_Predictor_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream)
150
60.0k
{
151
60.0k
    int code;
152
60.0k
    int64_t Predictor, Colors, BPC, Columns;
153
60.0k
    uint min_size;
154
60.0k
    stream_PNGP_state pps;
155
60.0k
    stream_PDiff_state ppds;
156
    /* NOTE: 'max_min_left=1' is a horribly named definition from stream.h */
157
158
60.0k
    code = pdfi_dict_get_int_def(ctx, d, "Predictor", &Predictor, 1);
159
60.0k
    if (code < 0)
160
7
        return code;
161
162
    /* Predictor values 0,1 are identity (use the existing stream).
163
     * The other values need to be cascaded.
164
     */
165
60.0k
    switch(Predictor) {
166
8
        case 0:
167
8
            Predictor = 1;
168
8
            break;
169
3.37k
        case 1:
170
3.37k
            break;
171
35
        case 2:
172
35
        case 10:
173
48
        case 11:
174
14.3k
        case 12:
175
14.3k
        case 13:
176
14.3k
        case 14:
177
56.4k
        case 15:
178
            /* grab values common to both kinds of predictors */
179
56.4k
            min_size = s_zlibD_template.min_out_size + max_min_left;
180
56.4k
            code = pdfi_dict_get_int_def(ctx, d, "Colors", &Colors, 1);
181
56.4k
            if (code < 0)
182
3
                return code;
183
56.4k
            if (Colors < 1 || Colors > s_PNG_max_Colors)
184
630
                return_error(gs_error_rangecheck);
185
186
55.7k
            code = pdfi_dict_get_int_def(ctx, d, "BitsPerComponent", &BPC, 8);
187
55.7k
            if (code < 0)
188
0
                return code;
189
            /* tests for 1-16, powers of 2 */
190
55.7k
            if (BPC < 1 || BPC > 16 || (BPC & (BPC - 1)) != 0)
191
298
                return_error(gs_error_rangecheck);
192
193
55.4k
            code = pdfi_dict_get_int_def(ctx, d, "Columns", &Columns, 1);
194
55.4k
            if (code < 0)
195
77
                return code;
196
55.4k
            if (Columns < 1)
197
14
                return_error(gs_error_rangecheck);
198
55.4k
            break;
199
55.4k
        default:
200
240
            return_error(gs_error_rangecheck);
201
60.0k
    }
202
203
58.7k
    switch(Predictor) {
204
3.38k
        case 1:
205
3.38k
            *new_stream = source;
206
3.38k
            break;
207
35
        case 2:
208
            /* zpd_setup, componentwise horizontal differencing */
209
35
            ppds.Colors = (int)Colors;
210
35
            ppds.BitsPerComponent = (int)BPC;
211
35
            ppds.Columns = (int)Columns;
212
35
            code = pdfi_filter_open(min_size, &s_filter_read_procs,
213
35
                             (const stream_template *)&s_PDiffD_template,
214
35
                             (const stream_state *)&ppds, ctx->memory->non_gc_memory, new_stream);
215
35
            if (code < 0)
216
0
                return code;
217
218
35
            (*new_stream)->strm = source;
219
35
            break;
220
55.3k
        default:
221
            /* zpp_setup, PNG predictor */
222
55.3k
            pps.Colors = (int)Colors;
223
55.3k
            pps.BitsPerComponent = (int)BPC;
224
55.3k
            pps.Columns = (uint)Columns;
225
55.3k
            pps.Predictor = Predictor;
226
55.3k
            code = pdfi_filter_open(min_size, &s_filter_read_procs,
227
55.3k
                             (const stream_template *)&s_PNGPD_template,
228
55.3k
                             (const stream_state *)&pps, ctx->memory->non_gc_memory, new_stream);
229
55.3k
            if (code < 0)
230
5
                return code;
231
232
55.3k
            (*new_stream)->strm = source;
233
55.3k
            break;
234
58.7k
    }
235
58.7k
    return 0;
236
58.7k
}
237
238
int pdfi_apply_Arc4_filter(pdf_context *ctx, pdf_string *Key, pdf_c_stream *source, pdf_c_stream **new_stream)
239
24.5k
{
240
24.5k
    int code = 0;
241
24.5k
    stream_arcfour_state state;
242
24.5k
    stream *new_s;
243
24.5k
    int min_size = 2048;
244
245
24.5k
    s_arcfour_set_key(&state, (const unsigned char *)Key->data, Key->length); /* lgtm [cpp/weak-cryptographic-algorithm] */
246
247
24.5k
    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
24.5k
    if (code < 0)
249
0
        return code;
250
251
24.5k
    code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
252
24.5k
    if (code >= 0)
253
24.5k
        new_s->strm = source->s;
254
24.5k
    return code;
255
24.5k
}
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
56.7k
{
259
56.7k
    stream_aes_state state;
260
56.7k
    uint min_size = 2048;
261
56.7k
    int code = 0;
262
56.7k
    stream *new_s;
263
264
56.7k
    s_aes_set_key(&state, Key->data, Key->length);
265
56.7k
    s_aes_set_padding(&state, use_padding);
266
267
56.7k
    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
56.7k
    if (code < 0)
270
0
        return code;
271
272
56.7k
    code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
273
56.7k
    if (code >= 0)
274
56.7k
        new_s->strm = source->s;
275
56.7k
    return code;
276
56.7k
}
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
3.43M
{
329
3.43M
    stream_zlib_state zls;
330
3.43M
    uint min_size = 2048;
331
3.43M
    int code;
332
3.43M
    stream *Flate_source = NULL;
333
334
3.43M
    memset(&zls, 0, sizeof(zls));
335
336
    /* s_zlibD_template defined in base/szlibd.c */
337
3.43M
    (*s_zlibD_template.set_defaults)((stream_state *)&zls);
338
339
3.43M
    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
3.43M
    if (code < 0)
341
0
        return code;
342
343
3.43M
    (*new_stream)->strm = source;
344
3.43M
    source = *new_stream;
345
346
3.43M
    if (d && pdfi_type_of(d) == PDF_DICT) {
347
60.0k
        Flate_source = (*new_stream)->strm;
348
60.0k
        code = pdfi_Predictor_filter(ctx, d, source, new_stream);
349
60.0k
        if (code < 0)
350
1.27k
            pdfi_close_filter_chain(ctx, source, Flate_source);
351
60.0k
    }
352
3.43M
    return code;
353
3.43M
}
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
1.14k
{
384
1.14k
    stream_jbig2decode_state state;
385
1.14k
    uint min_size = s_jbig2decode_template.min_out_size;
386
1.14k
    int code;
387
1.14k
    pdf_stream *Globals = NULL;
388
1.14k
    byte *buf = NULL;
389
1.14k
    int64_t buflen = 0;
390
1.14k
    void *globalctx;
391
392
1.14k
    s_jbig2decode_set_global_data((stream_state*)&state, NULL, NULL);
393
394
1.14k
    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
1.14k
    code = pdfi_filter_open(min_size, &s_filter_read_procs,
416
1.14k
                            (const stream_template *)&s_jbig2decode_template,
417
1.14k
                            (const stream_state *)&state, ctx->memory->non_gc_memory, new_stream);
418
1.14k
    if (code < 0)
419
0
        goto cleanupExit;
420
421
1.14k
    (*new_stream)->strm = source;
422
1.14k
    code = 0;
423
424
1.14k
 cleanupExit:
425
1.14k
    gs_free_object(ctx->memory, buf, "pdfi_JBIG2Decode_filter (Globals buf)");
426
1.14k
    pdfi_countdown(Globals);
427
1.14k
    return code;
428
1.14k
}
429
430
static int pdfi_LZW_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream)
431
224
{
432
224
    stream_LZW_state lzs;
433
224
    uint min_size = 2048;
434
224
    int code;
435
224
    int64_t i;
436
437
    /* s_zlibD_template defined in base/szlibd.c */
438
224
    s_LZW_set_defaults_inline(&lzs);
439
440
224
    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
224
    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
224
    if (code < 0)
454
0
        return code;
455
224
    (*new_stream)->strm = source;
456
224
    source = *new_stream;
457
458
224
    if (d && pdfi_type_of(d) == PDF_DICT)
459
0
        pdfi_Predictor_filter(ctx, d, source, new_stream);
460
224
    return 0;
461
224
}
462
463
static int PS_JPXD_PassThrough(void *d, byte *Buffer, int Size)
464
173k
{
465
173k
    gx_device *dev = (gx_device *)d;
466
173k
    int code = 0;
467
468
173k
    if (Buffer == NULL) {
469
6.80k
        if (Size == 0)
470
3.40k
            code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_end, NULL, 0);
471
3.40k
        else
472
3.40k
            code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_begin, NULL, 0);
473
166k
    } else {
474
166k
        code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_data, Buffer, Size);
475
166k
    }
476
173k
    return code;
477
173k
}
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
18.7k
{
487
18.7k
    stream_jpxd_state state;
488
18.7k
    uint min_size = s_jpxd_template.min_out_size;
489
18.7k
    int code;
490
18.7k
    pdf_obj *csobj = NULL;
491
18.7k
    pdf_name *csname = NULL;
492
18.7k
    bool alpha;
493
18.7k
    gx_device *dev = gs_currentdevice(ctx->pgs);
494
495
18.7k
    state.memory = ctx->memory->non_gc_memory;
496
18.7k
    if (s_jpxd_template.set_defaults)
497
18.7k
      (*s_jpxd_template.set_defaults)((stream_state *)&state);
498
499
    /* Pull some extra params out of the image dict */
500
18.7k
    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
18.7k
        code = pdfi_dict_get_bool(ctx, dict, "Alpha", &alpha);
506
18.7k
        if (code == 0)
507
0
            state.alpha = alpha;
508
18.7k
    }
509
18.7k
    if (dict && pdfi_dict_get(ctx, dict, "ColorSpace", &csobj) == 0) {
510
        /* parse the value */
511
11.3k
        switch (pdfi_type_of(csobj)) {
512
94
        case PDF_ARRAY:
513
            /* assume it's the first array element */
514
94
            code = pdfi_array_get(ctx, (pdf_array *)csobj, (uint64_t)0, (pdf_obj **)&csname);
515
94
            if (code < 0) {
516
0
                pdfi_countdown(csobj);
517
0
                return code;
518
0
            }
519
94
            break;
520
11.2k
        case PDF_NAME:
521
            /* use the name directly */
522
11.2k
            csname = (pdf_name *)csobj;
523
11.2k
            csobj = NULL; /* To keep ref counting straight */
524
11.2k
            break;
525
2
        default:
526
2
            code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefined), NULL, E_PDF_BAD_JPX_CS, "pdfi_JPX_filter", "");
527
2
            break;
528
11.3k
        }
529
11.3k
        if (csname != NULL && pdfi_type_of(csname) == PDF_NAME) {
530
            /* request raw index values if the colorspace is /Indexed */
531
11.3k
            if (pdfi_name_is(csname, "Indexed"))
532
94
                state.colorspace = gs_jpx_cs_indexed;
533
            /* tell the filter what output we want for other spaces */
534
11.2k
            else if (pdfi_name_is(csname, "DeviceGray"))
535
3.78k
                state.colorspace = gs_jpx_cs_gray;
536
7.47k
            else if (pdfi_name_is(csname, "DeviceRGB"))
537
7.47k
                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
11.3k
        }
579
11.3k
    }
580
581
18.7k
    if (csobj)
582
96
        pdfi_countdown(csobj);
583
18.7k
    if (csname)
584
11.3k
        pdfi_countdown(csname);
585
586
587
18.7k
    if (dev_proc(dev, dev_spec_op)(dev, gxdso_JPX_passthrough_query, NULL, 0) > 0) {
588
3.62k
        state.StartedPassThrough = 0;
589
3.62k
        state.PassThrough = 1;
590
3.62k
        state.PassThroughfn = (PS_JPXD_PassThrough);
591
3.62k
        state.device = (void *)dev;
592
3.62k
    }
593
15.1k
    else {
594
15.1k
        state.PassThrough = 0;
595
15.1k
        state.device = (void *)NULL;
596
15.1k
    }
597
598
18.7k
    code = pdfi_filter_open(min_size, &s_filter_read_procs, (const stream_template *)&s_jpxd_template,
599
18.7k
                            (const stream_state *)&state, ctx->memory->non_gc_memory, new_stream);
600
18.7k
    if (code < 0)
601
0
        return code;
602
18.7k
    (*new_stream)->strm = source;
603
18.7k
    source = *new_stream;
604
605
18.7k
    return 0;
606
18.7k
}
607
608
private_st_jpeg_decompress_data();
609
610
static int PDF_DCTD_PassThrough(void *d, byte *Buffer, int Size)
611
549k
{
612
549k
    gx_device *dev = (gx_device *)d;
613
549k
    int code = 0;
614
615
549k
    if (Buffer == NULL) {
616
13.7k
        if (Size == 0)
617
6.75k
            code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_end, NULL, 0);
618
6.97k
        else
619
6.97k
            code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_begin, NULL, 0);
620
535k
    } else {
621
535k
        code = dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_data, Buffer, Size);
622
535k
    }
623
549k
    return code;
624
549k
}
625
626
static int pdfi_DCT_filter(pdf_context *ctx, pdf_dict *stream_dict, pdf_dict *decode,
627
                           stream *source, stream **new_stream)
628
22.1k
{
629
22.1k
    stream_DCT_state dcts;
630
22.1k
    uint min_size = s_DCTD_template.min_out_size;
631
22.1k
    int code;
632
22.1k
    int64_t i;
633
22.1k
    jpeg_decompress_data *jddp;
634
22.1k
    gx_device *dev = gs_currentdevice_inline(ctx->pgs);
635
22.1k
    double Height = 0;
636
637
22.1k
    dcts.memory = ctx->memory;
638
    /* First allocate space for IJG parameters. */
639
22.1k
    jddp = gs_alloc_struct_immovable(ctx->memory, jpeg_decompress_data,
640
22.1k
      &st_jpeg_decompress_data, "pdfi_DCT");
641
22.1k
    if (jddp == 0)
642
0
        return_error(gs_error_VMerror);
643
22.1k
    if (s_DCTD_template.set_defaults)
644
22.1k
        (*s_DCTD_template.set_defaults) ((stream_state *) & dcts);
645
646
22.1k
    dcts.data.decompress = jddp;
647
22.1k
    jddp->memory = dcts.jpeg_memory = ctx->memory;  /* set now for allocation */
648
22.1k
    jddp->scanline_buffer = NULL;                 /* set this early for safe error exit */
649
22.1k
    dcts.report_error = pdfi_filter_report_error;     /* in case create fails */
650
22.1k
    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
22.1k
    if (decode && pdfi_type_of(decode) == PDF_DICT) {
657
        /* TODO: Why is this here?  'i' never gets used? */
658
1.08k
        code = pdfi_dict_get_int(ctx, decode, "ColorTransform", &i);
659
1.08k
        if (code < 0 && code != gs_error_undefined)
660
0
            return code;
661
1.08k
    }
662
663
22.1k
    if (dev_proc(dev, dev_spec_op)(dev, gxdso_JPEG_passthrough_query, NULL, 0) > 0) {
664
6.99k
        jddp->StartedPassThrough = 0;
665
6.99k
        jddp->PassThrough = 1;
666
6.99k
        jddp->PassThroughfn = (PDF_DCTD_PassThrough);
667
6.99k
        jddp->device = (void *)dev;
668
6.99k
    }
669
15.1k
    else {
670
15.1k
        jddp->PassThrough = 0;
671
15.1k
        jddp->device = (void *)NULL;
672
15.1k
    }
673
674
    /* Hack for Bug695112.pdf to grab a height in case it is missing from the JPEG data */
675
22.1k
    code = pdfi_dict_knownget_number(ctx, stream_dict, "Height", &Height);
676
22.1k
    if (code < 0)
677
1
        return code;
678
22.1k
    jddp->Height = (int)floor(Height);
679
680
22.1k
    jddp->templat = s_DCTD_template;
681
682
22.1k
    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
22.1k
    if (code < 0)
684
0
        return code;
685
22.1k
    (*new_stream)->strm = source;
686
22.1k
    source = *new_stream;
687
688
22.1k
    return 0;
689
22.1k
}
690
691
static int pdfi_ASCII85_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream)
692
1.25k
{
693
1.25k
    stream_A85D_state ss;
694
1.25k
    uint min_size = 2048;
695
1.25k
    int code;
696
697
1.25k
    ss.pdf_rules = true;
698
699
1.25k
    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
1.25k
    if (code < 0)
701
0
        return code;
702
703
1.25k
    (*new_stream)->strm = source;
704
1.25k
    return 0;
705
1.25k
}
706
707
static int pdfi_CCITTFax_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream)
708
8.87k
{
709
8.87k
    stream_CFD_state ss;
710
8.87k
    uint min_size = 2048;
711
8.87k
    bool bval;
712
8.87k
    int code;
713
8.87k
    int64_t i;
714
715
8.87k
    s_CF_set_defaults_inline(&ss);
716
717
8.87k
    if (d && pdfi_type_of(d) == PDF_DICT) {
718
8.80k
        code = pdfi_dict_get_int(ctx, d, "K", &i);
719
8.80k
        if (code < 0 && code != gs_error_undefined)
720
4
            return code;
721
8.80k
        if (code == 0)
722
8.70k
            ss.K = i;
723
724
8.80k
        code = pdfi_dict_get_bool(ctx, d, "EndOfLine", &bval);
725
8.80k
        if (code < 0 && code != gs_error_undefined)
726
0
            return code;
727
8.80k
        if (code == 0)
728
0
            ss.EndOfLine = bval ? 1 : 0;
729
730
8.80k
        code = pdfi_dict_get_bool(ctx, d, "EncodedByteAlign", &bval);
731
8.80k
        if (code < 0 && code != gs_error_undefined)
732
0
            return code;
733
8.80k
        if (code == 0)
734
0
            ss.EncodedByteAlign = bval ? 1 : 0;
735
736
8.80k
        code = pdfi_dict_get_bool(ctx, d, "EndOfBlock", &bval);
737
8.80k
        if (code < 0 && code != gs_error_undefined)
738
0
            return code;
739
8.80k
        if (code == 0)
740
792
            ss.EndOfBlock = bval ? 1 : 0;
741
742
8.80k
        code = pdfi_dict_get_bool(ctx, d, "BlackIs1", &bval);
743
8.80k
        if (code < 0 && code != gs_error_undefined)
744
0
            return code;
745
8.80k
        if (code == 0)
746
143
            ss.BlackIs1 = bval ? 1 : 0;
747
748
8.80k
        code = pdfi_dict_get_int(ctx, d, "Columns", &i);
749
8.80k
        if (code < 0 && code != gs_error_undefined)
750
8
            return code;
751
8.79k
        if (code == 0)
752
8.75k
            ss.Columns = i;
753
754
8.79k
        code = pdfi_dict_get_int(ctx, d, "Rows", &i);
755
8.79k
        if (code < 0 && code != gs_error_undefined)
756
0
            return code;
757
8.79k
        if (code == 0)
758
1.93k
            ss.Rows = i;
759
760
8.79k
        code = pdfi_dict_get_int(ctx, d, "DamagedRowsBeforeError", &i);
761
8.79k
        if (code < 0 && code != gs_error_undefined)
762
0
            return code;
763
8.79k
        if (code == 0)
764
0
            ss.DamagedRowsBeforeError = i;
765
766
8.79k
    }
767
768
8.85k
    code = pdfi_filter_open(min_size, &s_filter_read_procs,
769
8.85k
                            (const stream_template *)&s_CFD_template,
770
8.85k
                            (const stream_state *)&ss,
771
8.85k
                            ctx->memory->non_gc_memory, new_stream);
772
8.85k
    if (code < 0)
773
3
        return code;
774
775
8.85k
    (*new_stream)->strm = source;
776
8.85k
    return 0;
777
8.85k
}
778
779
static int pdfi_RunLength_filter(pdf_context *ctx, pdf_dict *d, stream *source, stream **new_stream)
780
631
{
781
631
    stream_RLD_state ss;
782
631
    uint min_size = 2048;
783
631
    int code;
784
785
631
    if (s_RLD_template.set_defaults)
786
631
        (*s_RLD_template.set_defaults) ((stream_state *) & ss);
787
788
631
    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
631
    if (code < 0)
790
0
        return code;
791
792
631
    (*new_stream)->strm = source;
793
631
    return 0;
794
631
}
795
796
static int pdfi_simple_filter(pdf_context *ctx, const stream_template *tmplate, stream *source, stream **new_stream)
797
1.88k
{
798
1.88k
    uint min_size = 2048;
799
1.88k
    int code;
800
801
1.88k
    code = pdfi_filter_open(min_size, &s_filter_read_procs, tmplate, NULL, ctx->memory->non_gc_memory, new_stream);
802
1.88k
    if (code < 0)
803
0
        return code;
804
805
1.88k
    (*new_stream)->strm = source;
806
1.88k
    return 0;
807
1.88k
}
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
3.49M
{
812
3.49M
    int code;
813
814
3.49M
    code = pdfi_loop_detector_mark(ctx);
815
3.49M
    if (code < 0)
816
0
        return code;
817
818
3.49M
    if (dict->object_num != 0) {
819
3.41M
        code = pdfi_loop_detector_add_object(ctx, dict->object_num);
820
3.41M
        if (code < 0)
821
0
            goto cleanupExit;
822
3.41M
    } else {
823
85.7k
        if (dict->indirect_num != 0) {
824
15.1k
            code = pdfi_loop_detector_add_object(ctx, dict->indirect_num);
825
15.1k
            if (code < 0)
826
0
                goto cleanupExit;
827
15.1k
        }
828
85.7k
    }
829
830
3.49M
    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
3.49M
    if (pdfi_name_is(n, "RunLengthDecode")) {
843
630
        code = pdfi_RunLength_filter(ctx, decode, source, new_stream);
844
630
        goto cleanupExit;
845
630
    }
846
3.49M
    if (pdfi_name_is(n, "CCITTFaxDecode")) {
847
3.16k
        code = pdfi_CCITTFax_filter(ctx, decode, source, new_stream);
848
3.16k
        goto cleanupExit;
849
3.16k
    }
850
3.49M
    if (pdfi_name_is(n, "ASCIIHexDecode")) {
851
798
        code = pdfi_simple_filter(ctx, &s_AXD_template, source, new_stream);
852
798
        goto cleanupExit;
853
798
    }
854
3.49M
    if (pdfi_name_is(n, "ASCII85Decode")) {
855
1.06k
        code = pdfi_ASCII85_filter(ctx, decode, source, new_stream);
856
1.06k
        goto cleanupExit;
857
1.06k
    }
858
3.49M
    if (pdfi_name_is(n, "FlateDecode")) {
859
3.43M
        code = pdfi_Flate_filter(ctx, decode, source, new_stream);
860
3.43M
        goto cleanupExit;
861
3.43M
    }
862
56.8k
    if (pdfi_name_is(n, "JBIG2Decode")) {
863
1.14k
        code = pdfi_JBIG2Decode_filter(ctx, dict, decode, source, new_stream);
864
1.14k
        goto cleanupExit;
865
1.14k
    }
866
55.7k
    if (pdfi_name_is(n, "LZWDecode")) {
867
220
        code = pdfi_LZW_filter(ctx, decode, source, new_stream);
868
220
        goto cleanupExit;
869
220
    }
870
55.4k
    if (pdfi_name_is(n, "DCTDecode")) {
871
22.0k
        code = pdfi_DCT_filter(ctx, dict, decode, source, new_stream);
872
22.0k
        goto cleanupExit;
873
22.0k
    }
874
33.4k
    if (pdfi_name_is(n, "JPXDecode")) {
875
18.7k
        code = pdfi_JPX_filter(ctx, dict, decode, source, new_stream);
876
18.7k
        goto cleanupExit;
877
18.7k
    }
878
14.6k
    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
14.6k
    if (pdfi_name_is(n, "AHx")) {
884
1.08k
        if (!inline_image) {
885
111
            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
111
        }
888
1.08k
        code = pdfi_simple_filter(ctx, &s_AXD_template, source, new_stream);
889
1.08k
        goto cleanupExit;
890
1.08k
    }
891
13.5k
    if (pdfi_name_is(n, "A85")) {
892
193
        if (!inline_image) {
893
193
            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
193
        }
896
193
        code = pdfi_ASCII85_filter(ctx, decode, source, new_stream);
897
193
        goto cleanupExit;
898
193
    }
899
13.3k
    if (pdfi_name_is(n, "LZW")) {
900
4
        if (!inline_image) {
901
4
            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
4
        }
904
4
        code = pdfi_LZW_filter(ctx, decode, source, new_stream);
905
4
        goto cleanupExit;
906
4
    }
907
13.3k
    if (pdfi_name_is(n, "CCF")) {
908
5.70k
        if (!inline_image) {
909
0
            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
0
        }
912
5.70k
        code = pdfi_CCITTFax_filter(ctx, decode, source, new_stream);
913
5.70k
        goto cleanupExit;
914
5.70k
    }
915
7.66k
    if (pdfi_name_is(n, "DCT")) {
916
112
        if (!inline_image) {
917
1
            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
1
        }
920
112
        code = pdfi_DCT_filter(ctx, dict, decode, source, new_stream);
921
112
        goto cleanupExit;
922
112
    }
923
7.55k
    if (pdfi_name_is(n, "Fl")) {
924
293
        if (!inline_image) {
925
49
            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
49
        }
928
293
        code = pdfi_Flate_filter(ctx, decode, source, new_stream);
929
293
        goto cleanupExit;
930
293
    }
931
7.26k
    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
7.26k
    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
7.26k
    pdfi_set_error(ctx, 0, NULL, E_PDF_UNKNOWNFILTER, "pdfi_apply_filter", NULL);
949
7.26k
    code = gs_error_undefined;
950
951
3.49M
cleanupExit:
952
3.49M
    pdfi_loop_detector_cleartomark(ctx);
953
3.49M
    return code;
954
7.26k
}
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
4.09M
{
959
4.09M
    pdf_obj *o = NULL, *o1 = NULL;
960
4.09M
    pdf_obj *decode = NULL;
961
4.09M
    pdf_obj *Filter = NULL;
962
4.09M
    pdf_dict *stream_dict = NULL;
963
4.09M
    pdf_array *DecodeParams = NULL;
964
4.09M
    int code;
965
4.09M
    int64_t i, j, duplicates;
966
4.09M
    stream *s = source->s, *new_s = NULL;
967
968
4.09M
    *new_stream = NULL;
969
970
4.09M
    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
4.09M
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
976
4.09M
    if (code < 0)
977
0
        goto exit;
978
979
    /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. */
980
4.09M
    if (inline_image) {
981
353k
        code = pdfi_dict_knownget(ctx, stream_dict, "F", &Filter);
982
353k
        if (code == 0)
983
346k
            code = pdfi_dict_knownget(ctx, stream_dict, "Filter", &Filter);
984
353k
    } else
985
3.74M
        code = pdfi_dict_knownget(ctx, stream_dict, "Filter", &Filter);
986
987
4.09M
    if (code < 0)
988
0
        goto exit;
989
4.09M
    if (code == 0) {
990
        /* No filter, just open the stream */
991
599k
        code = pdfi_alloc_stream(ctx, s, source->s, new_stream);
992
599k
        goto exit;
993
599k
    }
994
995
3.49M
    switch (pdfi_type_of(Filter)) {
996
18
    default:
997
18
        code = gs_note_error(gs_error_typecheck);
998
18
        goto exit;
999
3.44M
    case PDF_NAME:
1000
        /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. */
1001
3.44M
        if (inline_image) {
1002
5.85k
            code = pdfi_dict_knownget(ctx, stream_dict, "DP", &decode);
1003
5.85k
            if (code == 0)
1004
149
                code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", &decode);
1005
3.43M
        } else {
1006
3.43M
            code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", &decode);
1007
3.43M
            if (code == 0)
1008
3.37M
                code = pdfi_dict_knownget(ctx, stream_dict, "DP", &decode);
1009
3.43M
        }
1010
3.44M
        if (code < 0)
1011
12
            goto exit;
1012
1013
3.44M
        code = pdfi_apply_filter(ctx, stream_dict, (pdf_name *)Filter,
1014
3.44M
                                 (pdf_dict *)decode, s, &new_s, inline_image);
1015
3.44M
        if (code < 0)
1016
8.45k
            goto exit;
1017
1018
3.43M
        code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
1019
3.43M
        break;
1020
54.1k
    case PDF_ARRAY:
1021
54.1k
    {
1022
54.1k
        pdf_array *filter_array = (pdf_array *)Filter;
1023
1024
        /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. */
1025
54.1k
        if (inline_image) {
1026
1.23k
            code = pdfi_dict_knownget(ctx, stream_dict, "DP", (pdf_obj **)&DecodeParams);
1027
1.23k
            if (code == 0)
1028
1.11k
                code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", (pdf_obj **)&DecodeParams);
1029
52.8k
        } else {
1030
52.8k
            code = pdfi_dict_knownget(ctx, stream_dict, "DecodeParms", (pdf_obj **)&DecodeParams);
1031
52.8k
            if (code == 0)
1032
45.4k
                code = pdfi_dict_knownget(ctx, stream_dict, "DP", &decode);
1033
52.8k
        }
1034
54.1k
        if (code < 0)
1035
0
            goto exit;
1036
1037
54.1k
        if (DecodeParams != NULL) {
1038
7.50k
            if (pdfi_array_size(DecodeParams) == 0 || pdfi_array_size(DecodeParams) != pdfi_array_size(filter_array)) {
1039
65
                pdfi_countdown(DecodeParams);
1040
65
                DecodeParams = NULL;
1041
65
                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
7.43k
            } else {
1044
7.43k
                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
7.43k
            }
1049
7.50k
        }
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
55.3k
        for (i = 0; i < (int)pdfi_array_size(filter_array) - 1;i++) {
1056
1.21k
            code = pdfi_array_get_type(ctx, filter_array, i, PDF_NAME, &o);
1057
1.21k
            if (code < 0)
1058
2
                goto exit;
1059
1.21k
            duplicates = 0;
1060
1061
2.46k
            for (j = i + 1; j < pdfi_array_size(filter_array);j++) {
1062
1.24k
                code = pdfi_array_get_type(ctx, filter_array, j, PDF_NAME, &o1);
1063
1.24k
                if (code < 0) {
1064
1
                    goto exit;
1065
1
                }
1066
1.24k
                if (((pdf_name *)o)->length == ((pdf_name *)o1)->length) {
1067
24
                    if (memcmp(((pdf_name *)o)->data, ((pdf_name *)o1)->data, ((pdf_name *)o)->length) == 0)
1068
9
                        duplicates++;
1069
24
                }
1070
1.24k
                pdfi_countdown(o1);
1071
1.24k
                o1 = NULL;
1072
1.24k
            }
1073
1.21k
            pdfi_countdown(o);
1074
1.21k
            o = NULL;
1075
1.21k
            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.21k
        }
1081
1082
109k
        for (i = 0; i < pdfi_array_size(filter_array);i++) {
1083
55.2k
            code = pdfi_array_get_type(ctx, filter_array, i, PDF_NAME, &o);
1084
55.2k
            if (code < 0)
1085
0
                goto error;
1086
55.2k
            if (DecodeParams != NULL) {
1087
7.91k
                code = pdfi_array_get(ctx, DecodeParams, i, &decode);
1088
7.91k
                if (code < 0) {
1089
12
                    goto error;
1090
12
                }
1091
7.91k
            }
1092
55.2k
            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
55.2k
            if (decode && decode == PDF_NULL_OBJ) {
1099
588
                pdfi_countdown(decode);
1100
588
                decode = NULL;
1101
588
            }
1102
1103
55.2k
            code = pdfi_apply_filter(ctx, stream_dict, (pdf_name *)o,
1104
55.2k
                                     (pdf_dict *)decode, s, &new_s, inline_image);
1105
55.2k
            pdfi_countdown(decode);
1106
55.2k
            decode = NULL;
1107
55.2k
            pdfi_countdown(o);
1108
55.2k
            o = NULL;
1109
55.2k
            if (code < 0)
1110
101
                goto error;
1111
1112
55.1k
            s = new_s;
1113
55.1k
        }
1114
53.9k
        code = pdfi_alloc_stream(ctx, s, source->s, new_stream);
1115
53.9k
    }
1116
3.49M
    }
1117
1118
4.09M
 exit:
1119
4.09M
    pdfi_countdown(o);
1120
4.09M
    pdfi_countdown(o1);
1121
4.09M
    pdfi_countdown(DecodeParams);
1122
4.09M
    pdfi_countdown(decode);
1123
4.09M
    pdfi_countdown(Filter);
1124
4.09M
    return code;
1125
1126
113
 error:
1127
113
    if (s)
1128
113
        pdfi_close_filter_chain(ctx, s, source->s);
1129
113
    *new_stream = NULL;
1130
113
    pdfi_countdown(o);
1131
113
    pdfi_countdown(o1);
1132
113
    pdfi_countdown(DecodeParams);
1133
113
    pdfi_countdown(decode);
1134
113
    pdfi_countdown(Filter);
1135
113
    return code;
1136
3.49M
}
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
4.07M
{
1141
4.07M
    int code;
1142
4.07M
    pdf_c_stream *crypt_stream = NULL, *SubFile_stream = NULL;
1143
4.07M
    pdf_string *StreamKey = NULL;
1144
4.07M
    pdf_dict *stream_dict = NULL;
1145
4.07M
    pdf_obj *FileSpec = NULL;
1146
4.07M
    pdf_stream *NewStream = NULL;
1147
4.07M
    bool known = false;
1148
1149
4.07M
    *new_stream = NULL;
1150
1151
4.07M
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
1152
4.07M
    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
4.07M
    if (!inline_image) {
1163
3.72M
        code = pdfi_dict_known(ctx, stream_dict, "F", &known);
1164
3.72M
        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
3.72M
    }
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
4.07M
    if (ctx->encryption.is_encrypted && !inline_image) {
1261
41.5k
        int64_t Length;
1262
1263
41.5k
        if (ctx->encryption.StmF == CRYPT_IDENTITY)
1264
0
            return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
1265
1266
41.5k
        code = pdfi_dict_get_type(ctx, stream_dict, "StreamKey", PDF_STRING, (pdf_obj **)&StreamKey);
1267
41.5k
        if (code == gs_error_undefined) {
1268
12.5k
            code = pdfi_compute_objkey(ctx, (pdf_obj *)stream_dict, &StreamKey);
1269
12.5k
            if (code < 0)
1270
0
                return code;
1271
12.5k
            code = pdfi_dict_put(ctx, stream_dict, "StreamKey", (pdf_obj *)StreamKey);
1272
12.5k
            if (code < 0)
1273
0
                goto error;
1274
12.5k
        }
1275
41.5k
        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
41.5k
        Length = pdfi_stream_length(ctx, stream_obj);
1291
1292
41.5k
        if (Length <= 0) {
1293
            /* Don't treat as an encrypted stream if Length is 0 */
1294
358
            pdfi_countdown(StreamKey);
1295
358
            return pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
1296
358
        }
1297
1298
41.2k
        code = pdfi_apply_SubFileDecode_filter(ctx, Length, NULL, source, &SubFile_stream, false);
1299
41.2k
        if (code < 0)
1300
0
            goto error;
1301
1302
41.2k
        SubFile_stream->original = source->s;
1303
1304
41.2k
        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
3.23k
            case CRYPT_V1:
1312
3.38k
            case CRYPT_V2:
1313
3.38k
                code = pdfi_apply_Arc4_filter(ctx, StreamKey, SubFile_stream, &crypt_stream);
1314
3.38k
                break;
1315
36.7k
            case CRYPT_AESV2:
1316
37.8k
            case CRYPT_AESV3:
1317
37.8k
                code = pdfi_apply_AES_filter(ctx, StreamKey, 1, SubFile_stream, &crypt_stream);
1318
37.8k
                break;
1319
0
            default:
1320
0
                code = gs_error_rangecheck;
1321
41.2k
        }
1322
41.2k
        if (code < 0) {
1323
0
            pdfi_close_file(ctx, SubFile_stream);
1324
0
            goto error;
1325
0
        }
1326
1327
41.2k
        crypt_stream->original = SubFile_stream->original;
1328
41.2k
        gs_free_object(ctx->memory, SubFile_stream, "pdfi_filter");
1329
1330
41.2k
        code = pdfi_filter_no_decryption(ctx, stream_obj, crypt_stream, new_stream, false);
1331
41.2k
        if (code < 0) {
1332
821
            pdfi_close_file(ctx, crypt_stream);
1333
821
            goto error;
1334
821
        }
1335
1336
40.4k
        (*new_stream)->original = source->s;
1337
40.4k
        gs_free_object(ctx->memory, crypt_stream, "pdfi_filter");
1338
4.03M
    } else {
1339
4.03M
        code = pdfi_filter_no_decryption(ctx, stream_obj, source, new_stream, inline_image);
1340
4.03M
    }
1341
4.07M
error:
1342
4.07M
    pdfi_countdown(NewStream);
1343
4.07M
    pdfi_countdown(StreamKey);
1344
4.07M
    pdfi_countdown(FileSpec);
1345
4.07M
    return code;
1346
4.07M
}
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
4.76M
{
1358
4.76M
    int code;
1359
4.76M
    stream_SFD_state state;
1360
4.76M
    stream *new_s = NULL;
1361
4.76M
    int min_size = 2048;
1362
1363
4.76M
    *new_stream = NULL;
1364
1365
4.76M
    memset(&state, 0, sizeof(state));
1366
1367
4.76M
    if (s_SFD_template.set_defaults)
1368
4.76M
        s_SFD_template.set_defaults((stream_state *)&state);
1369
1370
4.76M
    if (EODString != NULL) {
1371
736k
        state.eod.data = (const byte *)EODString;
1372
736k
        state.eod.size = strlen(EODString);
1373
736k
    }
1374
1375
4.76M
    if (EODCount > 0)
1376
4.02M
        state.count = EODCount - source->unread_size;
1377
736k
    else
1378
736k
        state.count = EODCount;
1379
1380
4.76M
    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
4.76M
    if (code < 0)
1382
0
        return code;
1383
1384
4.76M
    code = pdfi_alloc_stream(ctx, new_s, source->s, new_stream);
1385
4.76M
    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
4.76M
    new_s->strm = source->s;
1392
4.76M
    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
4.76M
    return code;
1398
4.76M
}
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
145k
{
1454
145k
    int code;
1455
145k
    int64_t bufferlen = 0;
1456
1457
145k
    code = pdfi_stream_to_buffer(ctx, stream_obj, Buffer, &bufferlen);
1458
145k
    if (code < 0) {
1459
707
        *Buffer = NULL;
1460
707
        *new_pdf_stream = NULL;
1461
707
        return code;
1462
707
    }
1463
145k
    code = pdfi_open_memory_stream_from_memory(ctx, (unsigned int)bufferlen, *Buffer, new_pdf_stream, retain_ownership);
1464
145k
    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
145k
    return (int)bufferlen;
1470
145k
}
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
365k
{
1474
365k
    int code;
1475
365k
    stream *new_stream;
1476
1477
365k
    new_stream = file_alloc_stream(ctx->memory, "open memory stream from memory(stream)");
1478
365k
    if (new_stream == NULL)
1479
0
        return_error(gs_error_VMerror);
1480
365k
    new_stream->close_at_eod = false;
1481
365k
    if (retain_ownership)
1482
257k
        sread_string(new_stream, Buffer, size);
1483
107k
    else
1484
107k
        sread_transient_string(new_stream, ctx->memory, Buffer, size);
1485
1486
365k
    code = pdfi_alloc_stream(ctx, new_stream, NULL, new_pdf_stream);
1487
365k
    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
365k
    return code;
1493
365k
}
1494
1495
int pdfi_close_memory_stream(pdf_context *ctx, byte *Buffer, pdf_c_stream *source)
1496
167k
{
1497
167k
    gs_free_object(ctx->memory, Buffer, "open memory stream(buffer)");
1498
167k
    if (source != NULL) {
1499
167k
        if (source->s != NULL) {
1500
167k
            sclose(source->s);
1501
167k
            gs_free_object(ctx->memory, source->s, "open memory stream(stream)");
1502
167k
        }
1503
167k
        gs_free_object(ctx->memory, source, "open memory stream(pdf_stream)");
1504
167k
    }
1505
167k
    return 0;
1506
167k
}
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
8.98M
{
1513
8.98M
    stream *next_s = s;
1514
1515
17.5M
    while(next_s && next_s != target){
1516
8.52M
        stream *curr_s = next_s;
1517
8.52M
        next_s = next_s->strm;
1518
8.52M
        if (curr_s != ctx->main_stream->s)
1519
8.52M
            sfclose(curr_s);
1520
8.52M
    }
1521
8.98M
}
1522
1523
void pdfi_close_file(pdf_context *ctx, pdf_c_stream *s)
1524
8.98M
{
1525
8.98M
    pdfi_close_filter_chain(ctx, s->s, s->original);
1526
1527
8.98M
    gs_free_object(ctx->memory, s, "closing pdf_file");
1528
8.98M
}
1529
1530
int pdfi_seek(pdf_context *ctx, pdf_c_stream *s, gs_offset_t offset, uint32_t origin)
1531
21.9M
{
1532
21.9M
    int code = 0;
1533
1534
21.9M
    if (origin == SEEK_CUR && s->unread_size != 0)
1535
1.46k
        offset -= s->unread_size;
1536
1537
21.9M
    s->unread_size = 0;;
1538
1539
21.9M
    code = sfseek(s->s, offset, origin);
1540
21.9M
    if (s->eof && code >= 0)
1541
158k
        s->eof = 0;
1542
1543
21.9M
    return code;
1544
21.9M
}
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
250M
{
1556
250M
    gs_offset_t off = stell(ctx->main_stream->s);
1557
1558
250M
    return (off - ctx->main_stream->unread_size);
1559
250M
}
1560
1561
gs_offset_t pdfi_tell(pdf_c_stream *s)
1562
1.96M
{
1563
1.96M
    return stell(s->s);
1564
1.96M
}
1565
1566
int pdfi_unread_byte(pdf_context *ctx, pdf_c_stream *s, char c)
1567
2.84G
{
1568
2.84G
    if (s->unread_size == UNREAD_BUFFER_SIZE)
1569
0
        return_error(gs_error_ioerror);
1570
1571
2.84G
    s->unget_buffer[s->unread_size++] = c;
1572
1573
2.84G
    return 0;
1574
2.84G
}
1575
1576
int pdfi_unread(pdf_context *ctx, pdf_c_stream *s, byte *Buffer, uint32_t size)
1577
244k
{
1578
244k
    if (size + s->unread_size > UNREAD_BUFFER_SIZE)
1579
15
        return_error(gs_error_ioerror);
1580
1581
244k
    Buffer += size;
1582
953k
    while (size) {
1583
709k
        s->unget_buffer[s->unread_size++] = *--Buffer;
1584
709k
        size--;
1585
709k
    }
1586
1587
244k
    return 0;
1588
244k
}
1589
1590
int pdfi_read_byte(pdf_context *ctx, pdf_c_stream *s)
1591
22.7G
{
1592
22.7G
    int32_t code;
1593
1594
22.7G
    if (s->eof && s->unread_size == 0)
1595
540k
        return EOFC;
1596
1597
22.7G
    if (s->unread_size)
1598
2.83G
        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
19.8G
    code = spgetc(s->s);
1604
19.8G
    if (code == EOFC) {
1605
884k
        s->eof = true;
1606
884k
        return EOFC;
1607
19.8G
    } else if (code == gs_error_ioerror) {
1608
246
        pdfi_set_error(ctx, code, "sgets", E_PDF_BADSTREAM, "pdfi_read_bytes", NULL);
1609
246
        s->eof = true;
1610
246
        return EOFC;
1611
19.8G
    } else if(code == ERRC) {
1612
190k
        return ERRC;
1613
190k
    }
1614
19.8G
    return (int)code;
1615
19.8G
}
1616
1617
1618
int pdfi_read_bytes(pdf_context *ctx, byte *Buffer, uint32_t size, uint32_t count, pdf_c_stream *s)
1619
5.52M
{
1620
5.52M
    uint32_t i = 0, total = size * count;
1621
5.52M
    uint32_t bytes = 0;
1622
5.52M
    int32_t code;
1623
1624
5.52M
    if (s->eof && s->unread_size == 0)
1625
13
        return 0;
1626
1627
5.52M
    if (s->unread_size) {
1628
47.1k
        i = s->unread_size;
1629
47.1k
        if (i >= total)
1630
0
            i = total;
1631
47.1k
        bytes = i;
1632
99.4k
        while (bytes) {
1633
52.3k
            *Buffer++ = s->unget_buffer[--s->unread_size];
1634
52.3k
            bytes--;
1635
52.3k
        }
1636
47.1k
        total -= i;
1637
47.1k
        if (total == 0 || s->eof)
1638
0
            return i;
1639
47.1k
    }
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
5.52M
    code = sgets(s->s, Buffer, total, &bytes);
1645
5.52M
    if (code == EOFC) {
1646
633
        s->eof = true;
1647
5.52M
    } 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
5.52M
    } else if(code == ERRC) {
1651
244
        bytes = ERRC;
1652
5.52M
    } else {
1653
5.52M
        bytes = bytes + i;
1654
5.52M
    }
1655
1656
5.52M
    return bytes;
1657
5.52M
}
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
301k
{
1667
301k
    byte *Buffer = NULL;
1668
301k
    int code = 0;
1669
301k
    uint read = 0;
1670
301k
    size_t buflen = 0;
1671
301k
    int64_t ToRead = *bufferlen;
1672
301k
    gs_offset_t savedoffset;
1673
301k
    pdf_c_stream *stream = NULL, *SubFileStream = NULL;
1674
301k
    bool filtered;
1675
301k
    pdf_dict *stream_dict = NULL;
1676
1677
301k
    savedoffset = pdfi_tell(ctx->main_stream);
1678
1679
301k
    pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET);
1680
1681
301k
    code = pdfi_dict_from_obj(ctx, (pdf_obj *)stream_obj, &stream_dict);
1682
301k
    if (code < 0)
1683
0
        goto exit;
1684
1685
    /* See if this is a filtered stream */
1686
301k
    code = pdfi_dict_known(ctx, stream_dict, "Filter", &filtered);
1687
301k
    if (code < 0)
1688
0
        goto exit;
1689
1690
301k
    if (!filtered) {
1691
39.1k
        code = pdfi_dict_known(ctx, stream_dict, "F", &filtered);
1692
39.1k
        if (code < 0)
1693
0
            goto exit;
1694
39.1k
    }
1695
1696
308k
retry:
1697
308k
    if (ToRead == 0) {
1698
292k
        if (filtered || ctx->encryption.is_encrypted) {
1699
260k
            code = pdfi_apply_SubFileDecode_filter(ctx, 0, "endstream", ctx->main_stream, &SubFileStream, false);
1700
260k
            if (code < 0)
1701
0
                goto exit;
1702
260k
            code = pdfi_filter(ctx, stream_obj, SubFileStream, &stream, false);
1703
260k
            if (code < 0) {
1704
1.02k
                pdfi_close_file(ctx, SubFileStream);
1705
1.02k
                goto exit;
1706
1.02k
            }
1707
1.61M
            while (seofp(stream->s) != true && serrorp(stream->s) != true) {
1708
1.35M
                s_process_read_buf(stream->s);
1709
1.35M
                buflen += sbufavailable(stream->s);
1710
1.35M
                (void)sbufskip(stream->s, sbufavailable(stream->s));
1711
1.35M
            }
1712
259k
            pdfi_close_file(ctx, stream);
1713
259k
            pdfi_close_file(ctx, SubFileStream);
1714
259k
        } else {
1715
32.0k
            buflen = pdfi_stream_length(ctx, stream_obj);
1716
32.0k
        }
1717
292k
    } else
1718
15.9k
        buflen = *bufferlen;
1719
1720
    /* Alloc buffer */
1721
307k
    Buffer = gs_alloc_bytes(ctx->memory, buflen, "pdfi_stream_to_buffer (Buffer)");
1722
307k
    if (!Buffer) {
1723
6
        code = gs_note_error(gs_error_VMerror);
1724
6
        goto exit;
1725
6
    }
1726
1727
307k
    code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET);
1728
307k
    if (code < 0) {
1729
0
        buflen = 0;
1730
0
        goto exit;
1731
0
    }
1732
307k
    if (filtered || ctx->encryption.is_encrypted) {
1733
267k
        if (ToRead && stream_obj->length_valid)
1734
8.15k
            code = pdfi_apply_SubFileDecode_filter(ctx, stream_obj->Length, NULL, ctx->main_stream, &SubFileStream, false);
1735
259k
        else
1736
259k
            code = pdfi_apply_SubFileDecode_filter(ctx, 0, "endstream", ctx->main_stream, &SubFileStream, false);
1737
267k
        if (code < 0)
1738
0
            goto exit;
1739
1740
267k
        code = pdfi_filter(ctx, stream_obj, SubFileStream, &stream, false);
1741
267k
        if (code < 0) {
1742
            /* Because we opened the SubFileDecode separately to the filter chain, we need to close it separately too */
1743
156
            pdfi_close_file(ctx, SubFileStream);
1744
156
            goto exit;
1745
156
        }
1746
1747
267k
        code = sgets(stream->s, Buffer, buflen, (unsigned int *)&read);
1748
267k
        if (read < buflen) {
1749
3.51k
            memset(Buffer + read, 0x00, buflen - read);
1750
3.51k
        }
1751
1752
267k
        pdfi_close_file(ctx, stream);
1753
        /* Because we opened the SubFileDecode separately to the filter chain, we need to close it separately too */
1754
267k
        pdfi_close_file(ctx, SubFileStream);
1755
267k
        if (code == ERRC || code == EOFC) {
1756
3.93k
            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.93k
            if(ToRead != 0) {
1763
922
                buflen = ToRead = 0;
1764
922
                code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET);
1765
922
                if (code < 0)
1766
0
                    goto exit;
1767
922
                gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)");
1768
922
                goto retry;
1769
922
            }
1770
3.93k
        }
1771
267k
    } else {
1772
39.1k
        if (ToRead && stream_obj->length_valid)
1773
7.12k
            code = pdfi_apply_SubFileDecode_filter(ctx, stream_obj->Length, NULL, ctx->main_stream, &SubFileStream, false);
1774
32.0k
        else
1775
32.0k
            code = pdfi_apply_SubFileDecode_filter(ctx, ToRead, "endstream", ctx->main_stream, &SubFileStream, false);
1776
39.1k
        if (code < 0)
1777
0
            goto exit;
1778
1779
39.1k
        code = sgets(SubFileStream->s, Buffer, buflen, (unsigned int *)&read);
1780
39.1k
        if (read < buflen) {
1781
170
            memset(Buffer + read, 0x00, buflen - read);
1782
170
        }
1783
1784
39.1k
        pdfi_close_file(ctx, SubFileStream);
1785
39.1k
        if (code == ERRC || code == EOFC) {
1786
5.53k
            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
5.53k
            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
5.53k
            filtered = 1;
1797
5.53k
            code = pdfi_seek(ctx, ctx->main_stream, pdfi_stream_offset(ctx, stream_obj), SEEK_SET);
1798
5.53k
            if (code < 0)
1799
0
                goto exit;
1800
5.53k
            gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)");
1801
5.53k
            goto retry;
1802
5.53k
        }
1803
39.1k
    }
1804
1805
301k
 exit:
1806
301k
    pdfi_seek(ctx, ctx->main_stream, savedoffset, SEEK_SET);
1807
301k
    if (Buffer && code < 0)
1808
156
        gs_free_object(ctx->memory, Buffer, "pdfi_stream_to_buffer (Buffer)");
1809
301k
    else
1810
301k
        *buf = Buffer;
1811
301k
    *bufferlen = buflen;
1812
301k
    return code;
1813
307k
}
1814
1815
static int pdfi_open_resource_file_inner(pdf_context *ctx, const char *fname, const int fnamelen, stream **s)
1816
4.05M
{
1817
4.05M
    int code = 0;
1818
4.05M
    if (fname == NULL || fnamelen == 0 || fnamelen >= gp_file_name_sizeof)
1819
2
        *s = NULL;
1820
4.05M
    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
4.05M
    else {
1831
4.05M
        char fnametotry[gp_file_name_sizeof];
1832
4.05M
        uint fnlen;
1833
4.05M
        gs_parsed_file_name_t pname;
1834
4.05M
        gp_file_name_combine_result r;
1835
4.05M
        int i, total;
1836
1837
4.05M
        *s = NULL;
1838
4.05M
        i = 0;
1839
4.05M
        total = ctx->search_paths.num_resource_paths - ctx->search_paths.num_init_resource_paths - 1;
1840
7.98M
retry:
1841
59.9M
        for (; i < total; i++) {
1842
51.9M
            gs_param_string *ss = &ctx->search_paths.resource_paths[i];
1843
1844
51.9M
            if (ss->data[0] == '%') {
1845
8.05M
                code = gs_parse_file_name(&pname, (char *)ss->data, ss->size, ctx->memory);
1846
8.05M
                if (code < 0 || (pname.len + fnamelen >= gp_file_name_sizeof)) {
1847
0
                    continue;
1848
0
                }
1849
8.05M
                memcpy(fnametotry, pname.fname, pname.len);
1850
8.05M
                memcpy(fnametotry + pname.len, fname, fnamelen);
1851
8.05M
                code = pname.iodev->procs.open_file(pname.iodev, fnametotry, pname.len + fnamelen, "r", s, ctx->memory);
1852
8.05M
                if (code < 0) {
1853
7.99M
                    continue;
1854
7.99M
                }
1855
54.7k
                break;
1856
8.05M
            }
1857
43.9M
            else {
1858
43.9M
                fnlen = gp_file_name_sizeof;
1859
43.9M
                r = gp_file_name_combine((char *)ss->data, ss->size, fname, fnamelen, false, fnametotry, &fnlen);
1860
43.9M
                if (r != gp_combine_success || fnlen > gp_file_name_sizeof - 1)
1861
0
                    continue;
1862
43.9M
                fnametotry[fnlen] = '\0';
1863
43.9M
                *s = sfopen(fnametotry, "r", ctx->memory);
1864
43.9M
                if (*s != NULL)
1865
0
                    break;
1866
43.9M
            }
1867
51.9M
        }
1868
7.98M
        if (*s == NULL && i < ctx->search_paths.num_resource_paths) {
1869
3.99M
            gs_param_string *ss = &ctx->search_paths.genericresourcedir;
1870
3.99M
            fnlen = gp_file_name_sizeof;
1871
3.99M
            r = gp_file_name_combine((char *)ss->data, ss->size, fname, fnamelen, false, fnametotry, &fnlen);
1872
3.99M
            if (r == gp_combine_success || fnlen < gp_file_name_sizeof) {
1873
3.99M
                fnametotry[fnlen] = '\0';
1874
3.99M
                *s = sfopen(fnametotry, "r", ctx->memory);
1875
3.99M
            }
1876
3.99M
        }
1877
7.98M
        if (*s == NULL && i < ctx->search_paths.num_resource_paths) {
1878
3.93M
            total = ctx->search_paths.num_resource_paths;
1879
3.93M
            goto retry;
1880
3.93M
        }
1881
7.98M
    }
1882
4.05M
    if (*s == NULL)
1883
3.93M
        return_error(gs_error_invalidfileaccess);
1884
1885
123k
    return 0;
1886
4.05M
}
1887
1888
int pdfi_open_resource_file(pdf_context *ctx, const char *fname, const int fnamelen, stream **s)
1889
141k
{
1890
141k
    return pdfi_open_resource_file_inner(ctx, fname, fnamelen, s);
1891
141k
}
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
3.91M
{
1905
3.91M
    int code = 0;
1906
3.91M
    const char *fontdirstr = "Font/";
1907
3.91M
    const int fontdirstrlen = strlen(fontdirstr);
1908
3.91M
    uint fnlen;
1909
3.91M
    gp_file_name_combine_result r;
1910
3.91M
    char fnametotry[gp_file_name_sizeof];
1911
1912
3.91M
    if (fname == NULL || fnamelen == 0 || fnamelen >= (gp_file_name_sizeof - fontdirstrlen))
1913
2
        *s = NULL;
1914
3.91M
    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
3.91M
    else {
1925
3.91M
        char fnametotry[gp_file_name_sizeof];
1926
3.91M
        gs_parsed_file_name_t pname;
1927
3.91M
        int i;
1928
1929
3.91M
        *s = NULL;
1930
3.91M
        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
3.91M
    }
1958
1959
    /* If not in the font specific search path, try it as a resource */
1960
3.91M
    if (*s == NULL)
1961
3.91M
        code =  pdfi_open_resource_file_inner(ctx, fname, fnamelen, s);
1962
1963
3.91M
    if (*s == NULL) {
1964
3.91M
        gs_param_string *ss = &ctx->search_paths.genericresourcedir;
1965
3.91M
        char fstr[gp_file_name_sizeof];
1966
1967
3.91M
        fnlen = gp_file_name_sizeof;
1968
1969
3.91M
        if (fontdirstrlen + 1 > gp_file_name_sizeof)
1970
0
            return_error(gs_error_undefinedfilename);
1971
1972
3.91M
        memcpy(fstr, fontdirstr, fontdirstrlen);
1973
3.91M
        if (fname != NULL) {
1974
3.91M
            if (fontdirstrlen + fnamelen < gp_file_name_sizeof)
1975
3.91M
                memcpy(fstr + fontdirstrlen, fname, fnamelen);
1976
2
            else
1977
2
                return_error(gs_error_undefinedfilename);
1978
3.91M
        }
1979
1980
3.91M
        r = gp_file_name_combine((char *)ss->data, ss->size, fstr, fontdirstrlen + fnamelen, false, fnametotry, &fnlen);
1981
3.91M
        if (r == gp_combine_success || fnlen < gp_file_name_sizeof) {
1982
3.91M
            fnametotry[fnlen] = '\0';
1983
3.91M
            *s = sfopen(fnametotry, "r", ctx->memory);
1984
3.91M
        }
1985
3.91M
    }
1986
1987
3.91M
    return *s == NULL ? gs_error_undefinedfilename : 0;
1988
3.91M
}
1989
1990
int pdfi_open_font_file(pdf_context *ctx, const char *fname, const int fnamelen, stream **s)
1991
1.95M
{
1992
1.95M
    return pdfi_open_font_file_inner(ctx, fname, fnamelen, s);
1993
1.95M
}
1994
1995
bool pdfi_font_file_exists(pdf_context *ctx, const char *fname, const int fnamelen)
1996
1.95M
{
1997
1.95M
    stream *s = NULL;
1998
1.95M
    int code = pdfi_open_font_file_inner(ctx, fname, fnamelen, &s);
1999
1.95M
    if (s)
2000
0
        sfclose(s);
2001
2002
1.95M
    return (code >= 0);
2003
1.95M
}