Coverage Report

Created: 2025-06-10 07:27

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