Coverage Report

Created: 2025-08-28 07:06

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