Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zpdfops.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Custom operators for PDF interpreter */
18
19
#if defined(BUILD_PDF) && BUILD_PDF == 1
20
#include "ghostpdf.h"
21
#include "pdf_page.h"
22
#include "gzht.h"
23
#include "gsrefct.h"
24
#include "pdf_misc.h"
25
#include "pdf_stack.h"
26
#include "pdf_dict.h"
27
#include "pdf_array.h"
28
#include "pdf_loop_detect.h"
29
30
#include "iminst.h"
31
#include "dstack.h"
32
#include "gsicc_profilecache.h"
33
#include "pagelist.h"
34
#endif
35
36
#include "ghost.h"
37
#include "gsmchunk.h"
38
#include "oper.h"
39
#include "igstate.h"
40
#include "istack.h"
41
#include "iutil.h"
42
#include "gspath.h"
43
#include "math_.h"
44
#include "ialloc.h"
45
#include "malloc_.h"
46
#include "string_.h"
47
#include "store.h"
48
#include "gxgstate.h"
49
#include "gxdevsop.h"
50
#include "idict.h"
51
#include "iname.h"
52
#include "bfont.h"
53
54
#ifdef HAVE_LIBIDN
55
#  include <stringprep.h>
56
#endif
57
58
/* ------ Graphics state ------ */
59
60
/* <screen_index> <x> <y> .setscreenphase - */
61
static int
62
zsetscreenphase(i_ctx_t *i_ctx_p)
63
5
{
64
5
    os_ptr op = osp;
65
5
    int code;
66
5
    int x, y;
67
68
5
    check_type(op[-2], t_integer);
69
1
    check_type(op[-1], t_integer);
70
1
    check_type(*op, t_integer);
71
1
    x = op[-1].value.intval;
72
1
    y = op->value.intval;
73
1
    if (op[-2].value.intval < -1 ||
74
1
        op[-2].value.intval >= gs_color_select_count
75
1
        )
76
1
        return_error(gs_error_rangecheck);
77
0
    code = gs_setscreenphase(igs, x, y,
78
0
                             (gs_color_select_t) op[-2].value.intval);
79
0
    if (code >= 0)
80
0
        pop(3);
81
0
    return code;
82
1
}
83
84
/* Construct a smooth path passing though a number of points  on the stack */
85
/* for PDF ink annotations. The program is based on a very simple method of */
86
/* smoothing polygons by Maxim Shemanarev. */
87
/* http://www.antigrain.com/research/bezier_interpolation/ */
88
/* <mark> <x0> <y0> ... <xn> <yn> .pdfinkpath - */
89
static int
90
zpdfinkpath(i_ctx_t *i_ctx_p)
91
0
{
92
0
    os_ptr op = osp;
93
0
    uint i, count;
94
0
    int code;
95
0
    double x0, y0, x1, y1, x2, y2, x3, y3, xc1, yc1, xc2, yc2, xc3, yc3;
96
0
    double len1, len2, len3, k1, k2, xm1, ym1, xm2, ym2;
97
0
    double ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y;
98
0
    const double smooth_value = 1; /* from 0..1 range */
99
0
    ref lval;
100
101
0
    check_read_type(*op, t_array);
102
0
    count = r_size(op);
103
104
0
    if ((count & 1) != 0 || count < 2)
105
0
        return_error(gs_error_rangecheck);
106
107
0
    if ((code = array_get(imemory, op, 0, &lval)) < 0)
108
0
        return code;
109
0
    if ((code = real_param(&lval, &x1)) < 0)
110
0
        return code;
111
112
0
    if ((code = array_get(imemory, op, 1, &lval)) < 0)
113
0
        return code;
114
0
    if ((code = real_param(&lval, &y1)) < 0)
115
0
        return code;
116
117
0
    if ((code = gs_moveto(igs, x1, y1)) < 0)
118
0
        return code;
119
0
    if (count == 2)
120
0
          goto pop;
121
122
0
    if ((code = array_get(imemory, op, 2, &lval)) < 0)
123
0
        return code;
124
0
    if ((code = real_param(&lval, &x2)) < 0)
125
0
        return code;
126
127
0
    if ((code = array_get(imemory, op, 3, &lval)) < 0)
128
0
        return code;
129
0
    if ((code = real_param(&lval, &y2)) < 0)
130
0
        return code;
131
132
0
    if (count == 4) {
133
0
        if((code = gs_lineto(igs, x2, y2)) < 0)
134
0
            return code;
135
0
        goto pop;
136
0
    }
137
0
    x0 = 2*x1 - x2;
138
0
    y0 = 2*y1 - y2;
139
140
0
    for (i = 4; i <= count; i += 2) {
141
0
        if (i < count) {
142
0
            if ((code = array_get(imemory, op, i, &lval)) < 0)
143
0
                return code;
144
0
            if ((code = real_param(&lval, &x3)) < 0)
145
0
                return code;
146
0
            if ((code = array_get(imemory, op, i + 1, &lval)) < 0)
147
0
                return code;
148
0
            if ((code = real_param(&lval, &y3)) < 0)
149
0
                return code;
150
0
        } else {
151
0
            x3 = 2*x2 - x1;
152
0
            y3 = 2*y2 - y1;
153
0
        }
154
155
0
        xc1 = (x0 + x1) / 2.0;
156
0
        yc1 = (y0 + y1) / 2.0;
157
0
        xc2 = (x1 + x2) / 2.0;
158
0
        yc2 = (y1 + y2) / 2.0;
159
0
        xc3 = (x2 + x3) / 2.0;
160
0
        yc3 = (y2 + y3) / 2.0;
161
162
0
        len1 = hypot(x1 - x0, y1 - y0);
163
0
        len2 = hypot(x2 - x1, y2 - y1);
164
0
        len3 = hypot(x3 - x2, y3 - y2);
165
166
0
        k1 = len1 / (len1 + len2);
167
0
        k2 = len2 / (len2 + len3);
168
169
0
        xm1 = xc1 + (xc2 - xc1) * k1;
170
0
        ym1 = yc1 + (yc2 - yc1) * k1;
171
172
0
        xm2 = xc2 + (xc3 - xc2) * k2;
173
0
        ym2 = yc2 + (yc3 - yc2) * k2;
174
175
0
        ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
176
0
        ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
177
178
0
        ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
179
0
        ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
180
181
0
        code = gs_curveto(igs, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2, y2);
182
0
        if (code < 0)
183
0
            return code;
184
0
        x0 = x1, x1 = x2, x2 = x3;
185
0
        y0 = y1, y1 = y2, y2 = y3;
186
0
    }
187
0
  pop:
188
0
    pop(1);
189
0
    return 0;
190
0
}
191
192
static int
193
zpdfFormName(i_ctx_t *i_ctx_p)
194
0
{
195
0
    os_ptr op = osp;
196
0
    uint count = ref_stack_count(&o_stack);
197
0
    int code;
198
199
0
    if (count == 0)
200
0
        return_error(gs_error_stackunderflow);
201
0
    check_read_type(*op, t_string);
202
203
0
    code = (*dev_proc(i_ctx_p->pgs->device, dev_spec_op))((gx_device *)i_ctx_p->pgs->device,
204
0
        gxdso_pdf_form_name, (void *)op->value.const_bytes, r_size(op));
205
206
0
    if (code < 0)
207
0
        return code;
208
209
0
    pop(1);
210
0
    return 0;
211
0
}
212
213
#ifdef HAVE_LIBIDN
214
/* Given a UTF-8 password string, convert it to the canonical form
215
 * defined by SASLprep (RFC 4013).  This is a permissive implementation,
216
 * suitable for verifying existing passwords but not for creating new
217
 * ones -- if you want to create a new password, you'll need to add a
218
 * strict mode that returns stringprep errors to the user, and uses the
219
 * STRINGPREP_NO_UNASSIGNED flag to disallow unassigned characters.
220
 * <string> .saslprep <string> */
221
static int
222
zsaslprep(i_ctx_t *i_ctx_p)
223
{
224
    os_ptr op = osp;
225
    uint input_size = r_size(op);
226
    byte *buffer;
227
    uint buffer_size;
228
    uint output_size;
229
    Stringprep_rc err;
230
231
    check_read_type(*op, t_string);
232
233
    /* According to http://unicode.org/faq/normalization.html, converting
234
     * a UTF-8 string to normalization form KC has a worst-case expansion
235
     * factor of 11, so we allocate 11 times the length of the string plus
236
     * 1 for the NUL terminator.  If somehow that's still not big enough,
237
     * stringprep will return STRINGPREP_TOO_SMALL_BUFFER; there's no
238
     * danger of corrupting memory. */
239
    buffer_size = input_size * 11 + 1;
240
    buffer = ialloc_string(buffer_size, "saslprep result");
241
    if (buffer == 0)
242
        return_error(gs_error_VMerror);
243
244
    memcpy(buffer, op->value.bytes, input_size);
245
    buffer[input_size] = '\0';
246
247
    err = stringprep((char *)buffer, buffer_size, 0, stringprep_saslprep);
248
    if (err != STRINGPREP_OK) {
249
        ifree_string(buffer, buffer_size, "saslprep result");
250
251
        /* Since we're just verifying the password to an existing
252
         * document here, we don't care about "invalid input" errors
253
         * like STRINGPREP_CONTAINS_PROHIBITED.  In these cases, we
254
         * ignore the error and return the original string unchanged --
255
         * chances are it's not the right password anyway, and if it
256
         * is we shouldn't gratuitously fail to decrypt the document.
257
         *
258
         * On the other hand, errors like STRINGPREP_NFKC_FAILED are
259
         * real errors, and should be returned to the user.
260
         *
261
         * Fortunately, the stringprep error codes are sorted to make
262
         * this easy: the errors we want to ignore are the ones with
263
         * codes less than 100. */
264
        if ((int)err < 100)
265
            return 0;
266
267
        return_error(gs_error_ioerror);
268
    }
269
270
    output_size = strlen((char *)buffer);
271
    buffer = iresize_string(buffer, buffer_size, output_size,
272
        "saslprep result"); /* can't fail */
273
    make_string(op, a_all | icurrent_space, output_size, buffer);
274
275
    return 0;
276
}
277
#endif
278
279
#if defined(BUILD_PDF) && BUILD_PDF == 1
280
281
static int zpdfi_populate_search_paths(i_ctx_t *i_ctx_p, pdf_context *ctx)
282
40.8k
{
283
40.8k
    int code = 0;
284
    /* This should only be called once per pdfi context
285
       if the paths are already populated, just skip it.
286
     */
287
40.8k
    if (ctx->search_paths.resource_paths == NULL) {
288
40.8k
        ref *l2dictref, *grdref, *fpathref;
289
40.8k
        int i;
290
40.8k
        const gs_file_path *pfpath = i_ctx_p->lib_path;
291
40.8k
        gs_main_instance *minst = get_minst_from_memory(imemory);
292
40.8k
        code = dict_find_string(systemdict, "pssystemparams", &l2dictref);
293
40.8k
        if (code >= 0 && r_has_type(l2dictref, t_dictionary)) {
294
40.8k
            code = dict_find_string(l2dictref, "GenericResourceDir", &grdref);
295
40.8k
            if (code >= 0 && r_has_type(grdref, t_string)) {
296
40.8k
                ctx->search_paths.genericresourcedir.data = gs_alloc_bytes(ctx->memory, r_size(grdref), "zpdfi_populate_search_paths");
297
40.8k
                if (ctx->search_paths.genericresourcedir.data == NULL) {
298
0
                    code = gs_note_error(gs_error_VMerror);
299
0
                    goto done;
300
0
                }
301
40.8k
                memcpy((char *)ctx->search_paths.genericresourcedir.data, grdref->value.const_bytes, r_size(grdref));
302
40.8k
                ctx->search_paths.genericresourcedir.size = r_size(grdref);
303
40.8k
                ctx->search_paths.genericresourcedir.persistent = false;
304
40.8k
            }
305
40.8k
        }
306
307
40.8k
        ctx->search_paths.resource_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(&pfpath->list), "array of paths");
308
40.8k
        if (ctx->search_paths.resource_paths == NULL) {
309
0
            code = gs_note_error(gs_error_VMerror);
310
0
            goto done;
311
0
        }
312
40.8k
        memset(ctx->search_paths.resource_paths, 0x00, sizeof(gs_param_string) * r_size(&pfpath->list));
313
314
40.8k
        ctx->search_paths.num_resource_paths = r_size(&pfpath->list);
315
572k
        for (i = 0; i < r_size(&pfpath->list); i++) {
316
531k
            const ref *prdir = pfpath->list.value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
317
531k
            ctx->search_paths.resource_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths");
318
531k
            if (ctx->search_paths.resource_paths[i].data == NULL) {
319
0
                code = gs_note_error(gs_error_VMerror);
320
0
                goto done;
321
0
            }
322
531k
            memcpy((char *)ctx->search_paths.resource_paths[i].data, prdir->value.const_bytes, r_size(prdir));
323
531k
            ctx->search_paths.resource_paths[i].size = r_size(prdir);
324
531k
            ctx->search_paths.resource_paths[i].persistent = false;
325
531k
        }
326
40.8k
        code = dict_find_string(systemdict, "FONTPATH", &fpathref);
327
40.8k
        if (code >= 0 && r_has_type(fpathref, t_array)) {
328
0
            ctx->search_paths.font_paths = (gs_param_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_param_string) * r_size(fpathref), "array of font paths");
329
0
            memset(ctx->search_paths.font_paths, 0x00, sizeof(gs_param_string) * r_size(fpathref));
330
331
0
            ctx->search_paths.num_font_paths = r_size(fpathref);
332
0
            for (i = 0; i < r_size(fpathref); i++) {
333
0
                const ref *prdir = fpathref->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
334
0
                ctx->search_paths.font_paths[i].data = gs_alloc_bytes(ctx->memory, r_size(prdir), "zpdfi_populate_search_paths");
335
0
                if (ctx->search_paths.font_paths[i].data == NULL) {
336
0
                    code = gs_note_error(gs_error_VMerror);
337
0
                    goto done;
338
0
                }
339
0
                memcpy((char *)ctx->search_paths.font_paths[i].data, prdir->value.const_bytes, r_size(prdir));
340
0
                ctx->search_paths.font_paths[i].size = r_size(prdir);
341
0
                ctx->search_paths.font_paths[i].persistent = false;
342
0
            }
343
0
        }
344
40.8k
        ctx->search_paths.search_here_first = minst->search_here_first;
345
40.8k
    }
346
40.8k
done:
347
40.8k
    return code >= 0 ? 0 : code;
348
40.8k
}
349
350
static int zpdfi_populate_fontmap_files(i_ctx_t *i_ctx_p, pdf_context *ctx)
351
40.8k
{
352
40.8k
    int code, i;
353
40.8k
    ref *fontmaps;
354
355
40.8k
    code = dict_find_string(systemdict, "FONTMAP", &fontmaps);
356
40.8k
    if (code >= 0 && r_has_type(fontmaps, t_array)) {
357
0
        ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string) * r_size(fontmaps), "array of fontmap files");
358
0
        if (ctx->fontmapfiles != 0) {
359
0
            memset(ctx->fontmapfiles, 0x00, sizeof(gs_string) * r_size(fontmaps));
360
0
            ctx->num_fontmapfiles = r_size(fontmaps);
361
0
            for (i = 0; i < r_size(fontmaps); i++) {
362
0
                const ref *fmapfile = fontmaps->value.refs + i; /* By nature, this cannot be a short/mixed array, only a "normal" array */
363
0
                ctx->fontmapfiles[i].data = gs_alloc_bytes(ctx->memory, r_size(fmapfile), "zpdfi_populate_fontmap_files");
364
0
                if (ctx->fontmapfiles[i].data == NULL) {
365
0
                    code = gs_note_error(gs_error_VMerror);
366
0
                    goto done;
367
0
                }
368
0
                memcpy((char *)ctx->fontmapfiles[i].data, fmapfile->value.const_bytes, r_size(fmapfile));
369
0
                ctx->fontmapfiles[i].size = r_size(fmapfile);
370
0
            }
371
0
        }
372
0
        else {
373
0
            code = gs_note_error(gs_error_VMerror);
374
0
            goto done;
375
0
        }
376
0
    }
377
40.8k
    else if (code >= 0 && r_has_type(fontmaps, t_string)) {
378
0
        ctx->fontmapfiles = (gs_string *)gs_alloc_bytes(ctx->memory, sizeof(gs_string), "array of fontmap files");
379
0
        if (ctx->fontmapfiles != 0) {
380
0
            ctx->num_fontmapfiles = 1;
381
0
            ctx->fontmapfiles[0].data = gs_alloc_bytes(ctx->memory, r_size(fontmaps), "zpdfi_populate_fontmap_files");
382
0
            if (ctx->fontmapfiles[0].data == NULL) {
383
0
                code = gs_note_error(gs_error_VMerror);
384
0
                goto done;
385
0
            }
386
0
            memcpy((char *)ctx->fontmapfiles[0].data, fontmaps->value.const_bytes, r_size(fontmaps));
387
0
            ctx->fontmapfiles[0].size = r_size(fontmaps);
388
0
        }
389
0
        else {
390
0
            code = gs_note_error(gs_error_VMerror);
391
0
            goto done;
392
0
        }
393
0
    }
394
40.8k
    else
395
40.8k
        code = 0;
396
40.8k
done:
397
40.8k
    return code;
398
40.8k
}
399
400
/*
401
 * Declare the structure we use to represent an instance of the PDF parser
402
 * as a t_struct.
403
 */
404
typedef struct pdfctx_s {
405
    pdf_context *ctx;               /* Not exposed to garbager */
406
    stream *ps_stream;
407
    gs_memory_t *pdf_memory;        /* The 'wrapped' memory allocator used by the PDF interpreter. Not exposed to garbager */
408
    gs_memory_t *pdf_stream_memory; /* The memory allocator used to copy the PostScript stream to pdf_stream. Not exposed to garbager */
409
    stream *pdf_stream;
410
    bool UsingPDFFile;
411
    gsicc_profile_cache_t *profile_cache;
412
    gs_memory_t *cache_memory;      /* The memory allocator used to allocate the working (GC'ed) profile cache */
413
} pdfctx_t;
414
415
/* There is some unfortunately necessary complication in the structure above regarding the ICC profile cache.
416
 * Initially the problem was due to adding the colour space name to the 'interpreter data' part of the colour
417
 * space, in order to be able to identify the case where we switch to the current colour space.
418
 *
419
 * This caused problems with ICC spaces, because these maintain a reference to the colour space. If the profile
420
 * was stored in the PostScript profile cache (which it would be, because the profile cache is stored in the
421
 * grapchis state, which we inherit from the PostScript interpreter) then it would outlive the PDF interpreter,
422
 *  and when we came to free the cache it would try to free the colour space, which would try to free the PDF
423
 * name object, which had already been freed.
424
 *
425
 * To work around this we replaced the profile cache in the graphics state with the profile cache from the PDF
426
 * interpreter. Now when we free the PDF profile cache, it frees the colour spaces, and the PDF names, while they
427
 * are still valid.
428
 *
429
 * However, we then discovered that the garbage collector could reclaim the colour spaces. This happens because
430
 * no GC-visible object declares it has a reference to the colour space. It doesn't matter that the colour
431
 * space has been counted up, the GC frees it. Now the profile cache in pdfi is pointing to a colour space which
432
 * has gone away....
433
 *
434
 * To get round this, we create a brand-new profile cache, using GC'ed memory (well actually the interpreter
435
 * allocator, which is GC'ed for Ghostscript). When we switch to pdfi we replace the graphics state pdfi is
436
 * using with the one from the PostScript environment, and at the same time we swap out the profile cache
437
 * being used by that graphics state, so it uses our new one. On return to PostScript we swap them back.
438
 * This allows the lifetime of the profiles in the profile cache to be correct, because they are visible to the
439
 * garbage collector (the PDF context is a GC-visible object and enumerates it's member profile cache)
440
 * When we finalize the PDF context we count down the profile cache which dereferences all its entries. This
441
 * effectively frees the colour space (the memory may not be reclaimed yet) which calls the interpreter
442
 * specific cleanup, which frees the (still valid at this point) PDF name object and sets the pointer to NULL.
443
 *
444
 * The net result is that we have the profiles visible to the garbage collector during their lifetime, but
445
 * still have control over the cache, so we can empty it of the profiles created for pdfi when we close the
446
 * PDF interpreter.
447
 */
448
449
/* Structure descriptors */
450
static void pdfctx_finalize(const gs_memory_t *cmem, void *vptr);
451
452
gs_private_st_composite_final(st_pdfctx_t, pdfctx_t, "pdfctx_struct",\
453
    pdfctx_enum_ptrs, pdfctx_reloc_ptrs, pdfctx_finalize);
454
455
static
456
1.03k
ENUM_PTRS_BEGIN(pdfctx_enum_ptrs) return 0;
457
1.03k
ENUM_PTR3(0, pdfctx_t, ps_stream, pdf_stream, profile_cache);
458
1.03k
ENUM_PTRS_END
459
460
259
static RELOC_PTRS_BEGIN(pdfctx_reloc_ptrs);
461
259
RELOC_PTR3(pdfctx_t, ps_stream, pdf_stream, profile_cache);
462
259
RELOC_PTRS_END
463
464
static void
465
pdfctx_finalize(const gs_memory_t *cmem, void *vptr)
466
40.8k
{
467
40.8k
    pdfctx_t *pdfctx = vptr;
468
    /* Finalize methods have to cope with the possibility of being called multiple times
469
     *  on the same object - hence we null the entries.
470
     */
471
472
40.8k
    if (pdfctx->profile_cache != NULL) {
473
127
        rc_decrement(pdfctx->profile_cache, "free the working profile cache");
474
127
        pdfctx->profile_cache = NULL;
475
127
    }
476
40.8k
    if (cmem != NULL) {
477
40.8k
        if (pdfctx->ctx != NULL) {
478
127
            if (pdfctx->pdf_stream) {
479
109
                 memset(pdfctx->pdf_stream, 0x00, sizeof(stream));
480
109
                 gs_free_object(pdfctx->pdf_stream_memory, pdfctx->pdf_stream, "free PDF copy of stream");
481
109
                 pdfctx->pdf_stream = NULL;
482
109
            }
483
484
127
            if (pdfctx->ps_stream) {
485
                /* Detach the PostScript stream from the PDF context, otherwise the
486
                 * free_context code will close the main stream.
487
                 */
488
109
                pdfctx->ctx->main_stream = NULL;
489
109
            }
490
127
            (void)pdfi_free_context(pdfctx->ctx);
491
127
            pdfctx->ctx = NULL;
492
127
        }
493
40.8k
        if (pdfctx->pdf_memory != NULL) {
494
            /* gs_memory_chunk_unwrap() returns the "wrapped" allocator, which we don't need */
495
40.8k
            (void)gs_memory_chunk_unwrap(pdfctx->pdf_memory);
496
40.8k
            pdfctx->pdf_memory = NULL;
497
40.8k
        }
498
40.8k
    }
499
40.8k
}
500
501
static int zPDFstream(i_ctx_t *i_ctx_p)
502
40.8k
{
503
40.8k
    os_ptr op = osp;
504
40.8k
    int code = 0;
505
40.8k
    stream *s;
506
40.8k
    pdfctx_t *pdfctx;
507
40.8k
    pdfi_switch_t i_switch;
508
509
40.8k
    check_op(2);
510
511
40.8k
    check_read_file(i_ctx_p, s, op - 1);
512
513
40.8k
    check_type(*op, t_pdfctx);
514
40.8k
    pdfctx = r_ptr(op, pdfctx_t);
515
516
    /* If the supplied context already has a file open, signal an error */
517
40.8k
    if (pdfctx->ps_stream != NULL || pdfctx->UsingPDFFile)
518
0
        return_error(gs_error_ioerror);
519
520
40.8k
    s->close_at_eod = false;
521
40.8k
    pdfctx->ps_stream = s;
522
40.8k
    pdfctx->pdf_stream = s_alloc_immovable(imemory->stable_memory, "PDFstream copy of PS stream");
523
40.8k
    pdfctx->pdf_stream_memory = imemory->stable_memory;
524
40.8k
    if (pdfctx->pdf_stream == NULL)
525
0
        return_error(gs_error_VMerror);
526
527
40.8k
    *(pdfctx->pdf_stream) = *(pdfctx->ps_stream);
528
529
40.8k
    code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
530
531
40.8k
    if (code >= 0) {
532
40.8k
        code = pdfi_set_input_stream(pdfctx->ctx, pdfctx->pdf_stream);
533
534
40.8k
        pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
535
40.8k
    }
536
537
40.8k
    if (code < 0) {
538
15.5k
        memset(pdfctx->pdf_stream, 0x00, sizeof(stream));
539
15.5k
        gs_free_object(imemory, pdfctx->pdf_stream, "PDFstream copy of PS stream");
540
15.5k
        pdfctx->pdf_stream = NULL;
541
15.5k
        pdfctx->ps_stream = NULL;
542
15.5k
        return code;
543
15.5k
    }
544
545
25.3k
    pdfctx->ctx->finish_page = NULL;
546
25.3k
    make_tav(op, t_pdfctx, icurrent_space | a_all, pstruct, (obj_header_t *)(pdfctx));
547
548
25.3k
    pop(2);
549
25.3k
    return 0;
550
40.8k
}
551
552
static int zPDFfile(i_ctx_t *i_ctx_p)
553
5
{
554
5
    os_ptr op = osp;
555
5
    pdfctx_t *pdfctx;
556
5
    char pdffilename[gp_file_name_sizeof];
557
5
    int code = 0;
558
5
    pdfi_switch_t i_switch;
559
560
5
    check_op(2);
561
562
1
    check_type(*op, t_pdfctx);
563
0
    pdfctx = r_ptr(op, pdfctx_t);
564
565
0
    check_read_type(*(op - 1), t_string);
566
0
    if (r_size(op - 1) > gp_file_name_sizeof - 2)
567
0
        return_error(gs_error_limitcheck);
568
569
    /* If the supplied context already has a file open, signal an error */
570
0
    if (pdfctx->ps_stream != NULL)
571
0
        return_error(gs_error_ioerror);
572
573
0
    pdfctx->ps_stream = NULL;
574
575
0
    memcpy(pdffilename, (op - 1)->value.bytes, r_size(op - 1));
576
0
    pdffilename[r_size(op - 1)] = 0;
577
578
0
    code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
579
580
0
    if (code >= 0) {
581
0
        code = pdfi_open_pdf_file(pdfctx->ctx, pdffilename);
582
583
0
        pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
584
0
    }
585
586
0
    if (code < 0)
587
0
        return code;
588
589
0
    pdfctx->UsingPDFFile = true;
590
0
    pdfctx->ctx->finish_page = NULL;
591
592
0
    pop(2);
593
0
    return 0;
594
0
}
595
596
static int zPDFclose(i_ctx_t *i_ctx_p)
597
40.7k
{
598
40.7k
    os_ptr op = osp;
599
40.7k
    int code = 0;
600
40.7k
    pdfctx_t *pdfctx;
601
602
40.7k
    check_type(*op, t_pdfctx);
603
40.7k
    pdfctx = r_ptr(op, pdfctx_t);
604
605
40.7k
    if (pdfctx->profile_cache != NULL) {
606
40.7k
        rc_decrement(pdfctx->profile_cache, "free the working profile cache");
607
40.7k
        pdfctx->profile_cache = NULL;
608
40.7k
    }
609
610
40.7k
    if (pdfctx->ctx != NULL) {
611
40.7k
        pdfi_report_errors(pdfctx->ctx);
612
40.7k
        if (pdfctx->ps_stream) {
613
            /* Detach the PostScript stream from the PDF context, otherwise the
614
             * close code will close the main stream
615
             */
616
25.2k
            pdfctx->ctx->main_stream->s = NULL;
617
25.2k
        }
618
40.7k
        code = pdfi_free_context(pdfctx->ctx);
619
40.7k
        pdfctx->ctx = NULL;
620
40.7k
    }
621
40.7k
    if (pdfctx->pdf_stream) {
622
25.2k
        memset(pdfctx->pdf_stream, 0x00, sizeof(stream));
623
25.2k
        gs_free_object(imemory, pdfctx->pdf_stream, "free copy of PostScript stream");
624
25.2k
        pdfctx->pdf_stream = NULL;
625
25.2k
    }
626
40.7k
    if (pdfctx->ps_stream)
627
25.2k
        pdfctx->ps_stream = NULL;
628
40.7k
    pop(1);
629
40.7k
    return code;
630
40.7k
}
631
632
static int PDFobj_to_PSobj(i_ctx_t *i_ctx_p, pdfctx_t *pdfctx, pdf_obj *PDFobj, ref *PSobj);
633
634
#define DEBUG_INFO_DICT 0
635
636
static void debug_printmark(int type)
637
264k
{
638
#if DEBUG_INFO_DICT
639
    switch(type) {
640
        case 0:
641
            dbgprintf("<<\n");
642
            break;
643
        case 1:
644
            dbgprintf(">>\n");
645
            break;
646
        case 2:
647
            dbgprintf("[");
648
            break;
649
        case 3:
650
            dbgprintf("]\n");
651
            break;
652
    }
653
#endif
654
264k
}
655
656
static void debug_pdfobj(i_ctx_t *i_ctx_p, pdfctx_t *pdfctx, pdf_obj *PDFobj)
657
934k
{
658
#if DEBUG_INFO_DICT
659
    char *str = NULL;
660
    int code = 0, len = 0;
661
662
    switch(pdfi_type_of(PDFobj)) {
663
        case PDF_NAME:
664
            code = pdfi_string_from_name(pdfctx->ctx, (pdf_name *)PDFobj, &str, &len);
665
            if (code < 0)
666
                return;
667
            dbgprintf1("/%s ", str);
668
            (void)pdfi_free_string_from_name(pdfctx->ctx, str);
669
            break;
670
        case PDF_STRING:
671
            str = (char *)gs_alloc_bytes(pdfctx->ctx->memory, ((pdf_string *)PDFobj)->length + 1, "");
672
            if (str == NULL)
673
                return;
674
            memset(str, 0x00, ((pdf_string *)PDFobj)->length + 1);
675
            memcpy(str, ((pdf_string *)PDFobj)->data, ((pdf_string *)PDFobj)->length);
676
            dbgprintf1("/%s ", str);
677
            gs_free_object(pdfctx->ctx->memory, str, "");
678
            break;
679
        case PDF_INT:
680
            dbgprintf1("/%d ", ((pdf_num *)PDFobj)->value.i);
681
            break;
682
        case PDF_REAL:
683
            dbgprintf1("/%f ", ((pdf_num *)PDFobj)->value.d);
684
            break;
685
            break;
686
        case PDF_BOOL:
687
            if (PDFobj == PDF_TRUE_OBJ)
688
                dbgprintf("true ");
689
            else
690
                dbgprintf("false ");
691
            break;
692
        default:
693
            break;
694
    }
695
#endif
696
934k
}
697
698
static int PDFdict_to_PSdict(i_ctx_t *i_ctx_p, pdfctx_t *pdfctx, pdf_dict *PDFdict, ref *PSdict)
699
53.4k
{
700
53.4k
    int code = 0;
701
53.4k
    uint64_t index = 0;
702
53.4k
    pdf_name *Key = NULL;
703
53.4k
    pdf_obj *Value = NULL;
704
53.4k
    ref nameref, valueref;
705
53.4k
    char *str = NULL;
706
53.4k
    int len = 0;
707
708
53.4k
    code = dict_create(pdfi_dict_entries(PDFdict), PSdict);
709
53.4k
    if (code < 0)
710
0
        return code;
711
712
53.4k
    code = pdfi_loop_detector_mark(pdfctx->ctx);
713
53.4k
    if (code < 0)
714
0
        goto error;
715
716
53.4k
    code = pdfi_dict_first(pdfctx->ctx, PDFdict, (pdf_obj **)&Key, &Value, &index);
717
53.4k
    if (code == gs_error_undefined) {
718
57
        code = 0;
719
57
        goto error;
720
57
    }
721
722
283k
    while (code >= 0) {
723
283k
        code = pdfi_string_from_name(pdfctx->ctx, Key, &str, &len);
724
283k
        if (code < 0)
725
0
            goto error;
726
727
283k
        debug_pdfobj(i_ctx_p, pdfctx, (pdf_obj *)Key);
728
729
283k
        code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)str, len, &nameref, 1);
730
283k
        if (code < 0)
731
0
            goto error;
732
733
283k
        code = PDFobj_to_PSobj(i_ctx_p, pdfctx, Value, &valueref);
734
283k
        if (code < 0)
735
0
            goto error;
736
737
283k
        code = dict_put(PSdict, &nameref, &valueref, &i_ctx_p->dict_stack);
738
283k
        if (code < 0)
739
0
            goto error;
740
741
283k
        pdfi_countdown(Key);
742
283k
        pdfi_countdown(Value);
743
283k
        Key = NULL;
744
283k
        Value = NULL;
745
746
283k
        code = pdfi_loop_detector_cleartomark(pdfctx->ctx);
747
283k
        if (code < 0)
748
0
            goto error;
749
750
283k
        code = pdfi_loop_detector_mark(pdfctx->ctx);
751
283k
        if (code < 0)
752
0
            goto error;
753
754
283k
        (void)pdfi_free_string_from_name(pdfctx->ctx, str);
755
283k
        str = NULL;
756
283k
        code = pdfi_dict_next(pdfctx->ctx, PDFdict, (pdf_obj **)&Key, &Value, &index);
757
283k
        if (code == gs_error_undefined) {
758
53.3k
            code = 0;
759
53.3k
            break;
760
53.3k
        }
761
283k
    }
762
53.4k
error:
763
53.4k
    (void)pdfi_free_string_from_name(pdfctx->ctx, str);
764
53.4k
    pdfi_countdown(Key);
765
53.4k
    pdfi_countdown(Value);
766
767
53.4k
    if (code < 0)
768
0
        (void)pdfi_loop_detector_cleartomark(pdfctx->ctx);
769
53.4k
    else
770
53.4k
        code = pdfi_loop_detector_cleartomark(pdfctx->ctx);
771
53.4k
    return code;
772
53.3k
}
773
774
static int PDFarray_to_PSarray(i_ctx_t *i_ctx_p, pdfctx_t *pdfctx, pdf_array *PDFarray, ref *PSarray)
775
78.7k
{
776
78.7k
    int code = 0, i = 0;
777
78.7k
    ref PS_ref;
778
78.7k
    pdf_obj *array_obj = NULL;
779
78.7k
    ref *eltp = NULL;
780
781
78.7k
    code = pdfi_loop_detector_mark(pdfctx->ctx);
782
78.7k
    if (code < 0)
783
0
        goto error;
784
785
78.7k
    code = ialloc_ref_array(PSarray, a_all, pdfi_array_size(PDFarray), "zPDFInfo");
786
78.7k
    if (code < 0)
787
0
        goto error;
788
789
393k
    for (i = 0;i < pdfi_array_size(PDFarray); i++) {
790
314k
        code = pdfi_array_fetch_recursing(pdfctx->ctx, PDFarray, i, &array_obj, true, true);
791
314k
        if (code < 0)
792
0
            goto error;
793
314k
        code = PDFobj_to_PSobj(i_ctx_p, pdfctx, array_obj, &PS_ref);
794
314k
        if (code < 0) {
795
0
            pdfi_countdown(array_obj);
796
0
            goto error;
797
0
        }
798
799
314k
        eltp = PSarray->value.refs + i;
800
314k
        ref_assign_old((const ref *)PSarray, eltp, &PS_ref, "zPDFInfo");
801
802
314k
        pdfi_countdown(array_obj);
803
314k
        array_obj = NULL;
804
314k
    }
805
78.7k
error:
806
78.7k
    if (code < 0)
807
0
        (void)pdfi_loop_detector_cleartomark(pdfctx->ctx);
808
78.7k
    else
809
78.7k
        code = pdfi_loop_detector_cleartomark(pdfctx->ctx);
810
78.7k
    return code;
811
78.7k
}
812
813
static int PDFobj_to_PSobj(i_ctx_t *i_ctx_p, pdfctx_t *pdfctx, pdf_obj *PDFobj, ref *PSobj)
814
651k
{
815
651k
    int code = 0;
816
817
651k
    code = pdfi_loop_detector_mark(pdfctx->ctx);
818
651k
    if (code < 0)
819
0
        goto error;
820
821
651k
    debug_pdfobj(i_ctx_p, pdfctx, PDFobj);
822
823
651k
    switch(pdfi_type_of(PDFobj)) {
824
2.53k
        case PDF_NAME:
825
2.53k
            {
826
2.53k
                char *str = NULL;
827
2.53k
                int len;
828
829
2.53k
                code = pdfi_string_from_name(pdfctx->ctx, (pdf_name *)PDFobj, &str, &len);
830
2.53k
                if (code < 0)
831
0
                    goto error;
832
2.53k
                code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)str, len, PSobj, 1);
833
2.53k
                (void)pdfi_free_string_from_name(pdfctx->ctx, str);
834
2.53k
            }
835
0
            break;
836
48.9k
        case PDF_STRING:
837
48.9k
            {
838
48.9k
                byte *sbody;
839
48.9k
                uint size = ((pdf_name *)PDFobj)->length;
840
841
48.9k
                sbody = ialloc_string(size, "string");
842
48.9k
                if (sbody == 0) {
843
0
                    code = gs_note_error(gs_error_VMerror);
844
48.9k
                } else {
845
48.9k
                    make_string(PSobj, a_all | icurrent_space, size, sbody);
846
48.9k
                    memcpy(sbody, ((pdf_name *)PDFobj)->data, size);
847
48.9k
                }
848
48.9k
            }
849
48.9k
            break;
850
277k
        case PDF_INT:
851
277k
            {
852
277k
                int64_t i;
853
854
277k
                code = pdfi_obj_to_int(pdfctx->ctx, PDFobj, &i);
855
277k
                if (code < 0)
856
0
                    goto error;
857
277k
                make_int(PSobj, i);
858
277k
            }
859
0
            break;
860
86.9k
        case PDF_BOOL:
861
86.9k
            if (PDFobj == PDF_TRUE_OBJ)
862
86.9k
                make_bool(PSobj, 1);
863
65.6k
            else
864
86.9k
                make_bool(PSobj, 0);
865
86.9k
            break;
866
102k
        case PDF_REAL:
867
102k
            {
868
102k
                double d;
869
870
102k
                code = pdfi_obj_to_real(pdfctx->ctx, PDFobj, &d);
871
102k
                if (code < 0)
872
0
                    goto error;
873
102k
                make_real(PSobj, d);
874
102k
            }
875
0
            break;
876
53.4k
        case PDF_DICT:
877
53.4k
            if (PDFobj->object_num != 0) {
878
9.89k
                code = pdfi_loop_detector_add_object(pdfctx->ctx, PDFobj->object_num);
879
9.89k
                if (code < 0)
880
0
                    goto error;
881
9.89k
            }
882
53.4k
            debug_printmark(0);
883
53.4k
            code = PDFdict_to_PSdict(i_ctx_p, pdfctx, (pdf_dict *)PDFobj, PSobj);
884
53.4k
            debug_printmark(1);
885
53.4k
            break;
886
78.7k
        case PDF_ARRAY:
887
78.7k
            if (PDFobj->object_num != 0) {
888
626
                code = pdfi_loop_detector_add_object(pdfctx->ctx, PDFobj->object_num);
889
626
                if (code < 0)
890
0
                    goto error;
891
626
            }
892
78.7k
            debug_printmark(2);
893
78.7k
            code = PDFarray_to_PSarray(i_ctx_p, pdfctx, (pdf_array *)PDFobj, PSobj);
894
78.7k
            debug_printmark(3);
895
78.7k
            break;
896
76
        default:
897
76
            make_null(PSobj);
898
76
            break;
899
651k
    }
900
901
651k
error:
902
651k
    if (code < 0)
903
0
        (void)pdfi_loop_detector_cleartomark(pdfctx->ctx);
904
651k
    else
905
651k
        code = pdfi_loop_detector_cleartomark(pdfctx->ctx);
906
651k
    return code;
907
651k
}
908
909
static int zPDFinfo(i_ctx_t *i_ctx_p)
910
25.3k
{
911
25.3k
    os_ptr op = osp;
912
25.3k
    pdfctx_t *pdfctx;
913
25.3k
    int code = 0;
914
25.3k
    ref intref, nameref;
915
25.3k
    uint64_t TotalFiles = 0, ix = 0;
916
25.3k
    char **names_array = NULL;
917
918
25.3k
    check_type(*(op), t_pdfctx);
919
25.3k
    pdfctx = r_ptr(op, pdfctx_t);
920
921
25.3k
    if (pdfctx->pdf_stream != NULL || pdfctx->UsingPDFFile) {
922
25.3k
        code = dict_create(4, op);
923
25.3k
        if (code < 0)
924
0
            return code;
925
926
25.3k
        code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1);
927
25.3k
        if (code < 0)
928
0
            return code;
929
930
25.3k
        make_int(&intref, pdfctx->ctx->num_pages);
931
932
25.3k
        code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack);
933
25.3k
        if (code < 0)
934
0
            return code;
935
936
        /* Code to process Collections. The pdfi_prep_collection() function returns an
937
         * array of descriptions and filenames. Because the descriptions can contain
938
         * UTF16-BE encoded data we can't sue a NULL terminated string, so the description
939
         * strings are terminated with a triple-NULL sequence of bytes.
940
         * We copy the contents into a PostScript array, which we store in the info
941
         * dictionary using the /Collection key.
942
         */
943
25.3k
        if (pdfctx->ctx->Collection != NULL) {
944
0
            code = pdfi_prep_collection(pdfctx->ctx, &TotalFiles, &names_array);
945
0
            if (code >= 0 && TotalFiles > 0) {
946
0
                uint size;
947
0
                ref collection, stringref;
948
949
0
                code = ialloc_ref_array(&collection, a_all, TotalFiles * 2, "names array");
950
0
                if (code < 0)
951
0
                    goto error;
952
953
0
                code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"Collection", 10, &nameref, 1);
954
0
                if (code < 0)
955
0
                    goto error;
956
957
0
                code = dict_put(op, &nameref, &collection, &i_ctx_p->dict_stack);
958
0
                if (code < 0)
959
0
                    goto error;
960
961
0
                for (ix=0; ix < TotalFiles * 2; ix++) {
962
0
                    char *ptr = names_array[ix];
963
0
                    byte *sbody;
964
0
                    ref *pelement;
965
966
0
                    size = 0;
967
0
                    do {
968
0
                        if (ptr[0] == 0x00 && ptr[1] == 0x00 && ptr[2] == 0x00)
969
0
                            break;
970
0
                        ptr++;
971
0
                        size++;
972
0
                    } while (1);
973
0
                    sbody = ialloc_string(size, "string");
974
0
                    if (sbody == 0) {
975
0
                        code = gs_error_VMerror;
976
0
                        goto error;
977
0
                    }
978
0
                    make_string(&stringref, a_all | icurrent_space, size, sbody);
979
0
                    memset(sbody, 0x00, size);
980
0
                    memcpy(sbody, names_array[ix], size);
981
0
                    gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames");
982
0
                    names_array[ix] = NULL;
983
0
                    pelement = collection.value.refs + ix;
984
0
                    ref_assign_old(&collection, pelement, &stringref, "put names string");
985
0
                }
986
0
            }
987
0
            gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames");
988
0
            code = 0;
989
25.3k
        } else {
990
25.3k
            if (pdfctx->ctx->Info != NULL) {
991
9.84k
                code = PDFobj_to_PSobj(i_ctx_p, pdfctx, (pdf_obj *)pdfctx->ctx->Info, (ref *)op);
992
9.84k
                if (code < 0)
993
0
                    return code;
994
995
9.84k
                code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1);
996
9.84k
                if (code < 0)
997
0
                    return code;
998
999
9.84k
                make_int(&intref, pdfctx->ctx->num_pages);
1000
1001
9.84k
                code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack);
1002
9.84k
                if (code < 0)
1003
0
                    return code;
1004
15.4k
            } else {
1005
15.4k
                code = dict_create(1, op);
1006
15.4k
                if (code < 0)
1007
0
                    return code;
1008
1009
15.4k
                code = names_ref(imemory->gs_lib_ctx->gs_name_table, (const byte *)"NumPages", 8, &nameref, 1);
1010
15.4k
                if (code < 0)
1011
0
                    return code;
1012
1013
15.4k
                make_int(&intref, pdfctx->ctx->num_pages);
1014
1015
15.4k
                code = dict_put(op, &nameref, &intref, &i_ctx_p->dict_stack);
1016
15.4k
                if (code < 0)
1017
0
                    return code;
1018
15.4k
            }
1019
25.3k
        }
1020
25.3k
    }
1021
0
    else {
1022
0
        return_error(gs_error_ioerror);
1023
0
    }
1024
25.3k
    return code;
1025
1026
0
error:
1027
0
    for (ix=0; ix < TotalFiles * 2; ix++)
1028
0
        gs_free_object(pdfctx->ctx->memory, names_array[ix], "free collection temporary filenames");
1029
0
    gs_free_object(pdfctx->ctx->memory, names_array, "free collection temporary filenames");
1030
0
    return code;
1031
25.3k
}
1032
1033
static int zPDFpageinfo(i_ctx_t *i_ctx_p)
1034
54.0k
{
1035
54.0k
    os_ptr op = osp;
1036
54.0k
    int page = 0, code = 0;
1037
54.0k
    pdfctx_t *pdfctx;
1038
54.0k
    pdf_dict *InfoDict = NULL;
1039
54.0k
    pdfi_switch_t i_switch;
1040
1041
54.0k
    check_op(2);
1042
1043
54.0k
    check_type(*op, t_integer);
1044
54.0k
    page = op->value.intval;
1045
1046
54.0k
    check_type(*(op - 1), t_pdfctx);
1047
54.0k
    pdfctx = r_ptr(op - 1, pdfctx_t);
1048
1049
54.0k
    if (pdfctx->pdf_stream != NULL || pdfctx->UsingPDFFile) {
1050
54.0k
        code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
1051
1052
54.0k
        if (code >= 0) {
1053
54.0k
            code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &InfoDict, false);
1054
1055
54.0k
            pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
1056
54.0k
        }
1057
1058
54.0k
        if (code < 0)
1059
10.5k
            return code;
1060
1061
43.4k
        pop(1);
1062
43.4k
        op = osp;
1063
1064
43.4k
        code = PDFobj_to_PSobj(i_ctx_p, pdfctx, (pdf_obj *)InfoDict, op);
1065
43.4k
        pdfi_countdown(InfoDict);
1066
43.4k
        if (code < 0)
1067
0
            return code;
1068
43.4k
    }
1069
0
    else {
1070
0
        return_error(gs_error_ioerror);
1071
0
    }
1072
43.4k
    return 0;
1073
54.0k
}
1074
1075
static int zPDFpageinfoExt(i_ctx_t *i_ctx_p)
1076
0
{
1077
0
    os_ptr op = osp;
1078
0
    int page = 0, code = 0;
1079
0
    pdfctx_t *pdfctx;
1080
0
    pdf_dict *InfoDict = NULL;
1081
0
    pdfi_switch_t i_switch;
1082
1083
0
    check_op(2);
1084
1085
0
    check_type(*op, t_integer);
1086
0
    page = op->value.intval;
1087
1088
0
    check_type(*(op - 1), t_pdfctx);
1089
0
    pdfctx = r_ptr(op - 1, pdfctx_t);
1090
1091
0
    if (pdfctx->pdf_stream != NULL || pdfctx->UsingPDFFile) {
1092
0
        code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
1093
1094
0
        if (code >= 0) {
1095
0
            code = pdfi_page_info(pdfctx->ctx, (uint64_t)page, &InfoDict, true);
1096
1097
0
            pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
1098
0
        }
1099
1100
0
        if (code < 0)
1101
0
            return code;
1102
1103
0
        pop(1);
1104
0
        op = osp;
1105
1106
0
        code = PDFobj_to_PSobj(i_ctx_p, pdfctx, (pdf_obj *)InfoDict, op);
1107
0
        pdfi_countdown(InfoDict);
1108
0
        if (code < 0)
1109
0
            return code;
1110
0
    }
1111
0
    else {
1112
0
        return_error(gs_error_ioerror);
1113
0
    }
1114
0
    return 0;
1115
0
}
1116
1117
static int zPDFmetadata(i_ctx_t *i_ctx_p)
1118
0
{
1119
#if 0
1120
    os_ptr op = osp;
1121
    pdfctx_t *pdfctx;
1122
1123
    check_type(*op, t_pdfctx);
1124
    pdfctx = r_ptr(op, pdfctx_t);
1125
#endif
1126
1127
0
    return_error(gs_error_undefined);
1128
0
}
1129
1130
static int zPDFdrawpage(i_ctx_t *i_ctx_p)
1131
43.3k
{
1132
43.3k
    os_ptr op = osp;
1133
43.3k
    int code = 0;
1134
43.3k
    uint64_t page = 0;
1135
43.3k
    pdfctx_t *pdfctx;
1136
43.3k
    pdfi_switch_t i_switch;
1137
1138
43.3k
    check_op(2);
1139
1140
43.3k
    check_type(*op, t_integer);
1141
43.3k
    page = op->value.intval;
1142
1143
43.3k
    check_type(*(op - 1), t_pdfctx);
1144
43.3k
    pdfctx = r_ptr(op - 1, pdfctx_t);
1145
1146
43.3k
    if (pdfctx->pdf_stream != NULL || pdfctx->UsingPDFFile) {
1147
43.3k
        code = gs_gsave(igs);
1148
43.3k
        if (code < 0)
1149
0
            return code;
1150
1151
43.3k
        code = pdfi_gstate_from_PS(pdfctx->ctx, igs, &i_switch, pdfctx->profile_cache);
1152
1153
43.3k
        if (code >= 0) {
1154
43.3k
            if (pdfctx->ctx->args.pdfinfo)
1155
0
                code = pdfi_output_page_info(pdfctx->ctx, page);
1156
43.3k
            else
1157
43.3k
                code = pdfi_page_render(pdfctx->ctx, page, false);
1158
43.3k
            if (code >= 0)
1159
39.0k
                pop(2);
1160
1161
43.3k
            pdfi_gstate_to_PS(pdfctx->ctx, igs, &i_switch);
1162
43.3k
        }
1163
43.3k
        if (code == 0)
1164
39.0k
            code = gs_grestore(igs);
1165
4.36k
        else
1166
4.36k
            (void)gs_grestore(igs);
1167
43.3k
    }
1168
0
    else {
1169
0
        return_error(gs_error_ioerror);
1170
0
    }
1171
43.3k
    return code;
1172
43.3k
}
1173
1174
static int zPDFdrawannots(i_ctx_t *i_ctx_p)
1175
0
{
1176
#if 0
1177
    os_ptr op = osp;
1178
    pdfctx_t *pdfctx;
1179
1180
    check_type(*op, t_pdfctx);
1181
    pdfctx = r_ptr(op, pdfctx_t);
1182
#endif
1183
1184
0
    return_error(gs_error_undefined);
1185
0
}
1186
1187
static int zpdfi_glyph_index(gs_font *pfont, byte *str, uint size, uint *glyph)
1188
78.5M
{
1189
78.5M
    int code = 0;
1190
78.5M
    ref nref;
1191
78.5M
    code = name_ref(pfont->memory, str, size, &nref, true);
1192
78.5M
    if (code < 0)
1193
8
        return code;
1194
78.5M
    *glyph = name_index(pfont->memory, &nref);
1195
78.5M
    return 0;
1196
78.5M
}
1197
1198
static int param_value_get_namelist(gs_memory_t *ps_mem, pdf_context *ctx, ref *pvalueref, char ***pstrlist)
1199
0
{
1200
0
    char *data;
1201
0
    uint size, count;
1202
0
    char **strlist = NULL;
1203
0
    ref lval, sref;
1204
0
    int code;
1205
1206
0
    check_read_type(*pvalueref, t_array);
1207
1208
0
    strlist = (char **)gs_alloc_bytes(ctx->memory, (r_size(pvalueref)+1)*sizeof(char *), "param_value_get_namelist");
1209
0
    if (strlist == NULL)
1210
0
        return_error(gs_error_VMerror);
1211
0
    memset(strlist, 0x00, (r_size(pvalueref)+1)*sizeof(char *));
1212
1213
0
    for (count = 0;count < r_size(pvalueref); count++) {
1214
0
        code = array_get(ps_mem, pvalueref, count, &lval);
1215
0
        if (code < 0)
1216
0
            return code;
1217
1218
0
        if (!r_has_type(&lval, t_string) && !r_has_type(&lval, t_name))
1219
0
            return_error(gs_error_typecheck);
1220
1221
0
        if (r_has_type(&lval, t_name))
1222
0
            name_string_ref(ps_mem, (const ref *)&lval, &sref);
1223
0
        else
1224
0
            sref = lval;
1225
1226
0
        strlist[count] = (char *)gs_alloc_bytes(ctx->memory, sref.tas.rsize + 1, "param_value_get_namelist");
1227
0
        if (strlist[count] == NULL)
1228
0
            return_error(gs_error_VMerror);
1229
0
        memset(strlist[count], 0x00, sref.tas.rsize + 1);
1230
0
        memcpy(strlist[count], sref.value.bytes, sref.tas.rsize);
1231
0
    }
1232
0
    *pstrlist = strlist;
1233
0
    return 0;
1234
0
}
1235
1236
static int zPDFInit(i_ctx_t *i_ctx_p)
1237
40.8k
{
1238
40.8k
    os_ptr op = osp;
1239
40.8k
    ref *pdictref = NULL, *pvalueref;
1240
40.8k
    pdfctx_t *pdfctx = NULL;
1241
40.8k
    pdf_context *ctx = NULL;
1242
40.8k
    int code = 0;
1243
40.8k
    gs_memory_t *cmem;
1244
1245
40.8k
    code = gs_memory_chunk_wrap(&cmem, imemory->non_gc_memory);
1246
40.8k
    if (code < 0)
1247
0
        return_error(gs_error_VMerror);
1248
1249
40.8k
    pdfctx = gs_alloc_struct(imemory, pdfctx_t, &st_pdfctx_t, "PDFcontext");
1250
40.8k
    if (!pdfctx) {
1251
0
        code = gs_note_error(gs_error_VMerror);
1252
0
        goto error;
1253
0
    }
1254
40.8k
    pdfctx->pdf_memory = cmem;
1255
40.8k
    pdfctx->ctx = NULL;
1256
40.8k
    pdfctx->ps_stream = NULL;
1257
40.8k
    pdfctx->pdf_stream = NULL;
1258
40.8k
    pdfctx->UsingPDFFile = false;
1259
40.8k
    pdfctx->pdf_stream_memory = NULL;
1260
40.8k
    pdfctx->profile_cache = gsicc_profilecache_new(imemory);
1261
40.8k
    if (pdfctx->profile_cache == NULL) {
1262
0
        code = gs_note_error(gs_error_VMerror);
1263
0
        goto error;
1264
0
    }
1265
40.8k
    pdfctx->cache_memory = imemory;
1266
1267
40.8k
    ctx = pdfi_create_context(cmem);
1268
40.8k
    if (ctx == NULL) {
1269
0
        code = gs_note_error(gs_error_VMerror);
1270
0
        goto error;
1271
0
    }
1272
1273
40.8k
    pdfctx->ctx = ctx;
1274
40.8k
    get_zfont_glyph_name(&pdfctx->ctx->get_glyph_name);
1275
40.8k
    pdfctx->ctx->get_glyph_index = zpdfi_glyph_index;
1276
1277
40.8k
    if (ref_stack_count(&o_stack) > 0 && r_has_type(op, t_dictionary)) {
1278
40.8k
        pdictref = op;
1279
1280
40.8k
        code = gs_error_typecheck;
1281
40.8k
        if (dict_find_string(pdictref, "PDFDEBUG", &pvalueref) > 0) {
1282
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1283
0
                goto error;
1284
40.8k
            pdfctx->ctx->args.pdfdebug = pvalueref->value.boolval;
1285
40.8k
        }
1286
1287
40.8k
        if (dict_find_string(pdictref, "PDFSTOPONERROR", &pvalueref) > 0) {
1288
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1289
0
                goto error;
1290
40.8k
            pdfctx->ctx->args.pdfstoponerror = pvalueref->value.boolval;
1291
40.8k
        }
1292
1293
40.8k
        if (dict_find_string(pdictref, "PDFSTOPONWARNING", &pvalueref) > 0) {
1294
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1295
0
                goto error;
1296
40.8k
            pdfctx->ctx->args.pdfstoponwarning = pvalueref->value.boolval;
1297
40.8k
            if (pvalueref->value.boolval)
1298
0
                pdfctx->ctx->args.pdfstoponerror = pvalueref->value.boolval;
1299
40.8k
        }
1300
1301
40.8k
        if (dict_find_string(pdictref, "NOTRANSPARENCY", &pvalueref) > 0) {
1302
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1303
0
                goto error;
1304
40.8k
            pdfctx->ctx->args.notransparency = pvalueref->value.boolval;
1305
40.8k
        }
1306
1307
40.8k
        if (dict_find_string(pdictref, "QUIET", &pvalueref) > 0) {
1308
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1309
0
                goto error;
1310
40.8k
            pdfctx->ctx->args.QUIET = pvalueref->value.boolval;
1311
40.8k
        }
1312
1313
40.8k
        if (dict_find_string(pdictref, "VerboseErrors", &pvalueref) > 0) {
1314
0
            if (!r_has_type(pvalueref, t_boolean))
1315
0
                goto error;
1316
0
            pdfctx->ctx->args.verbose_errors = pvalueref->value.boolval;
1317
0
        }
1318
1319
40.8k
        if (dict_find_string(pdictref, "VerboseWarnings", &pvalueref) > 0) {
1320
0
            if (!r_has_type(pvalueref, t_boolean))
1321
0
                goto error;
1322
0
            pdfctx->ctx->args.verbose_warnings = pvalueref->value.boolval;
1323
0
        }
1324
1325
40.8k
        if (dict_find_string(pdictref, "PDFPassword", &pvalueref) > 0) {
1326
0
            if (!r_has_type(pvalueref, t_string))
1327
0
                goto error;
1328
0
            pdfctx->ctx->encryption.Password = (char *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF Password from zpdfops");
1329
0
            memset(pdfctx->ctx->encryption.Password, 0x00, r_size(pvalueref) + 1);
1330
0
            memcpy(pdfctx->ctx->encryption.Password, pvalueref->value.const_bytes, r_size(pvalueref));
1331
0
            pdfctx->ctx->encryption.PasswordLen = r_size(pvalueref);
1332
0
        }
1333
1334
40.8k
        if (dict_find_string(pdictref, "FirstPage", &pvalueref) > 0) {
1335
0
            if (!r_has_type(pvalueref, t_integer))
1336
0
                goto error;
1337
0
            pdfctx->ctx->args.first_page = pvalueref->value.intval;
1338
0
        }
1339
1340
40.8k
        if (dict_find_string(pdictref, "LastPage", &pvalueref) > 0) {
1341
0
            if (!r_has_type(pvalueref, t_integer))
1342
0
                goto error;
1343
0
            pdfctx->ctx->args.last_page = pvalueref->value.intval;
1344
0
        }
1345
1346
40.8k
        if (dict_find_string(pdictref, "PDFNOCIDFALLBACK", &pvalueref) > 0) {
1347
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1348
0
                goto error;
1349
40.8k
            pdfctx->ctx->args.nocidfallback = pvalueref->value.boolval;
1350
40.8k
        }
1351
1352
40.8k
        if (dict_find_string(pdictref, "NO_PDFMARK_OUTLINES", &pvalueref) > 0) {
1353
0
            if (!r_has_type(pvalueref, t_boolean))
1354
0
                goto error;
1355
0
            pdfctx->ctx->args.no_pdfmark_outlines = pvalueref->value.boolval;
1356
0
        }
1357
1358
        /* This one can be a boolean OR an integer */
1359
40.8k
        if (dict_find_string(pdictref, "UsePDFX3Profile", &pvalueref) > 0) {
1360
0
            if (!r_has_type(pvalueref, t_boolean)) {
1361
0
                if (!r_has_type(pvalueref, t_integer))
1362
0
                    goto error;
1363
0
                else {
1364
0
                    pdfctx->ctx->args.UsePDFX3Profile = true;
1365
0
                    pdfctx->ctx->args.PDFX3Profile_num = pvalueref->value.intval;
1366
0
                }
1367
0
            } else {
1368
0
                pdfctx->ctx->args.UsePDFX3Profile = pvalueref->value.boolval;
1369
0
                pdfctx->ctx->args.PDFX3Profile_num = 0;
1370
0
            }
1371
0
        }
1372
1373
40.8k
        if (dict_find_string(pdictref, "NO_PDFMARK_DESTS", &pvalueref) > 0) {
1374
0
            if (!r_has_type(pvalueref, t_boolean))
1375
0
                goto error;
1376
0
            pdfctx->ctx->args.no_pdfmark_dests = pvalueref->value.boolval;
1377
0
        }
1378
1379
40.8k
        if (dict_find_string(pdictref, "PDFFitPage", &pvalueref) > 0) {
1380
0
            if (!r_has_type(pvalueref, t_boolean))
1381
0
                goto error;
1382
0
            pdfctx->ctx->args.pdffitpage = pvalueref->value.boolval;
1383
0
        }
1384
1385
40.8k
        if (dict_find_string(pdictref, "Printed", &pvalueref) > 0) {
1386
0
            if (!r_has_type(pvalueref, t_boolean))
1387
0
                goto error;
1388
0
            pdfctx->ctx->args.printed = pvalueref->value.boolval;
1389
0
        }
1390
1391
40.8k
        if (dict_find_string(pdictref, "UseBleedBox", &pvalueref) > 0) {
1392
0
            if (!r_has_type(pvalueref, t_boolean))
1393
0
                goto error;
1394
0
            pdfctx->ctx->args.usebleedbox = pvalueref->value.boolval;
1395
0
        }
1396
1397
40.8k
        if (dict_find_string(pdictref, "UseCropBox", &pvalueref) > 0) {
1398
0
            if (!r_has_type(pvalueref, t_boolean))
1399
0
                goto error;
1400
0
            pdfctx->ctx->args.usecropbox = pvalueref->value.boolval;
1401
0
        }
1402
1403
40.8k
        if (dict_find_string(pdictref, "UseArtBox", &pvalueref) > 0) {
1404
0
            if (!r_has_type(pvalueref, t_boolean))
1405
0
                goto error;
1406
0
            pdfctx->ctx->args.useartbox = pvalueref->value.boolval;
1407
0
        }
1408
1409
40.8k
        if (dict_find_string(pdictref, "UseTrimBox", &pvalueref) > 0) {
1410
0
            if (!r_has_type(pvalueref, t_boolean))
1411
0
                goto error;
1412
0
            pdfctx->ctx->args.usetrimbox = pvalueref->value.boolval;
1413
0
        }
1414
1415
40.8k
        if (dict_find_string(pdictref, "ShowAcroForm", &pvalueref) > 0) {
1416
0
            if (!r_has_type(pvalueref, t_boolean))
1417
0
                goto error;
1418
0
            pdfctx->ctx->args.showacroform = pvalueref->value.boolval;
1419
0
        }
1420
1421
40.8k
        if (dict_find_string(pdictref, "ShowAnnots", &pvalueref) > 0) {
1422
0
            if (!r_has_type(pvalueref, t_boolean))
1423
0
                goto error;
1424
0
            pdfctx->ctx->args.showannots = pvalueref->value.boolval;
1425
0
        }
1426
1427
40.8k
        if (dict_find_string(pdictref, "PreserveAnnots", &pvalueref) > 0) {
1428
0
            if (!r_has_type(pvalueref, t_boolean))
1429
0
                goto error;
1430
0
            pdfctx->ctx->args.preserveannots = pvalueref->value.boolval;
1431
0
        }
1432
1433
40.8k
        if (dict_find_string(pdictref, "PreserveMarkedContent", &pvalueref) > 0) {
1434
0
            if (!r_has_type(pvalueref, t_boolean))
1435
0
                goto error;
1436
0
            pdfctx->ctx->args.preservemarkedcontent = pvalueref->value.boolval;
1437
0
        }
1438
1439
40.8k
        if (dict_find_string(pdictref, "NoUserUnit", &pvalueref) > 0) {
1440
0
            if (!r_has_type(pvalueref, t_boolean))
1441
0
                goto error;
1442
0
            pdfctx->ctx->args.nouserunit = pvalueref->value.boolval;
1443
0
        }
1444
1445
40.8k
        if (dict_find_string(pdictref, "RENDERTTNOTDEF", &pvalueref) > 0) {
1446
40.8k
            if (!r_has_type(pvalueref, t_boolean))
1447
0
                goto error;
1448
40.8k
            pdfctx->ctx->args.renderttnotdef = pvalueref->value.boolval;
1449
40.8k
        }
1450
1451
40.8k
        if (dict_find_string(pdictref, "DOPDFMARKS", &pvalueref) > 0) {
1452
0
            if (!r_has_type(pvalueref, t_boolean))
1453
0
                goto error;
1454
0
            pdfctx->ctx->args.dopdfmarks = pvalueref->value.boolval;
1455
0
        }
1456
1457
40.8k
        if (dict_find_string(pdictref, "PDFINFO", &pvalueref) > 0) {
1458
0
            if (!r_has_type(pvalueref, t_boolean))
1459
0
                goto error;
1460
0
            pdfctx->ctx->args.pdfinfo = pvalueref->value.boolval;
1461
0
        }
1462
40.8k
        if (dict_find_string(pdictref, "ShowAnnotTypes", &pvalueref) > 0) {
1463
0
            code = param_value_get_namelist(imemory, pdfctx->ctx, pvalueref,
1464
0
                                            &pdfctx->ctx->args.showannottypes);
1465
0
            if (code < 0)
1466
0
                goto error;
1467
0
        }
1468
40.8k
        if (dict_find_string(pdictref, "PreserveAnnotTypes", &pvalueref) > 0) {
1469
0
            code = param_value_get_namelist(imemory, pdfctx->ctx, pvalueref,
1470
0
                                            &pdfctx->ctx->args.preserveannottypes);
1471
0
            if (code < 0)
1472
0
                goto error;
1473
0
        }
1474
40.8k
        if (dict_find_string(pdictref, "CIDFSubstPath", &pvalueref) > 0) {
1475
0
            if (!r_has_type(pvalueref, t_string))
1476
0
                goto error;
1477
0
            pdfctx->ctx->args.cidfsubstpath.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF cidfsubstpath from zpdfops");
1478
0
            if (pdfctx->ctx->args.cidfsubstpath.data == NULL) {
1479
0
                code = gs_note_error(gs_error_VMerror);
1480
0
                goto error;
1481
0
            }
1482
0
            memcpy(pdfctx->ctx->args.cidfsubstpath.data, pvalueref->value.const_bytes, r_size(pvalueref));
1483
0
            pdfctx->ctx->args.cidfsubstpath.size = r_size(pvalueref);
1484
0
        }
1485
40.8k
        if (dict_find_string(pdictref, "CIDFSubstFont", &pvalueref) > 0) {
1486
0
            if (!r_has_type(pvalueref, t_string))
1487
0
                goto error;
1488
0
            pdfctx->ctx->args.cidfsubstfont.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(pvalueref) + 1, "PDF cidfsubstfont from zpdfops");
1489
0
            if (pdfctx->ctx->args.cidfsubstfont.data == NULL) {
1490
0
                code = gs_note_error(gs_error_VMerror);
1491
0
                goto error;
1492
0
            }
1493
0
            memcpy(pdfctx->ctx->args.cidfsubstfont.data, pvalueref->value.const_bytes, r_size(pvalueref));
1494
0
            pdfctx->ctx->args.cidfsubstfont.size = r_size(pvalueref);
1495
0
        }
1496
40.8k
        if (dict_find_string(pdictref, "SUBSTFONT", &pvalueref) > 0) {
1497
0
            ref nmstr, *namstrp;
1498
0
            if (r_has_type(pvalueref, t_string)) {
1499
0
                namstrp = pvalueref;
1500
0
                pdfctx->ctx->args.defaultfont_is_name = false;
1501
0
            } else if (r_has_type(pvalueref, t_name)) {
1502
0
                name_string_ref(imemory, pvalueref, &nmstr);
1503
0
                namstrp = &nmstr;
1504
0
                pdfctx->ctx->args.defaultfont_is_name = true;
1505
0
            }
1506
0
            else {
1507
0
                code = gs_note_error(gs_error_typecheck);
1508
0
                goto error;
1509
0
            }
1510
0
            pdfctx->ctx->args.defaultfont.data = (byte *)gs_alloc_bytes(pdfctx->ctx->memory, r_size(namstrp) + 1, "PDF defaultfontname from zpdfops");
1511
0
            if (pdfctx->ctx->args.defaultfont.data == NULL) {
1512
0
                code = gs_note_error(gs_error_VMerror);
1513
0
                goto error;
1514
0
            }
1515
0
            memcpy(pdfctx->ctx->args.defaultfont.data, pvalueref->value.const_bytes, r_size(namstrp));
1516
0
            pdfctx->ctx->args.defaultfont.size = r_size(namstrp);
1517
0
        }
1518
40.8k
        if (dict_find_string(pdictref, "IgnoreToUnicode", &pvalueref) > 0) {
1519
0
            if (!r_has_type(pvalueref, t_boolean))
1520
0
                goto error;
1521
0
            pdfctx->ctx->args.ignoretounicode = pvalueref->value.boolval;
1522
0
        }
1523
40.8k
        if (dict_find_string(pdictref, "NONATIVEFONTMAP", &pvalueref) > 0) {
1524
0
            if (!r_has_type(pvalueref, t_boolean))
1525
0
                goto error;
1526
0
            pdfctx->ctx->args.nonativefontmap = pvalueref->value.boolval;
1527
0
        }
1528
40.8k
        if (dict_find_string(pdictref, "PageCount", &pvalueref) > 0) {
1529
40.8k
            if (!r_has_type(pvalueref, t_integer))
1530
0
                goto error;
1531
40.8k
            pdfctx->ctx->Pdfmark_InitialPage = pvalueref->value.intval;
1532
40.8k
        }
1533
40.8k
        code = 0;
1534
40.8k
        pop(1);
1535
40.8k
    }
1536
40.8k
    code = zpdfi_populate_search_paths(i_ctx_p, ctx);
1537
40.8k
    if (code < 0)
1538
0
        goto error;
1539
1540
40.8k
    code = zpdfi_populate_fontmap_files(i_ctx_p, ctx);
1541
40.8k
    if (code < 0)
1542
0
        goto error;
1543
1544
40.8k
    op = osp;
1545
40.8k
    push(1);
1546
40.8k
    make_tav(op, t_pdfctx, icurrent_space | a_all, pstruct, (obj_header_t *)(pdfctx));
1547
40.8k
    return 0;
1548
1549
0
error:
1550
0
    if (ctx != NULL)
1551
0
        pdfi_free_context(ctx);
1552
    /* gs_memory_chunk_unwrap() returns the "wrapped" allocator, which we don't need */
1553
0
    (void)gs_memory_chunk_unwrap(cmem);
1554
0
    if (pdfctx != NULL) {
1555
0
        pdfctx->ctx = NULL; /* Freed already above! */
1556
0
        if (pdfctx->profile_cache != NULL) {
1557
0
            gs_free_object(imemory, pdfctx->profile_cache, "discard temporary profile cache");
1558
0
            pdfctx->profile_cache = NULL;
1559
0
        }
1560
0
        pdfctx->pdf_memory = NULL;
1561
0
        gs_free_object(imemory, pdfctx, "PDFcontext");
1562
0
    }
1563
0
    return code;
1564
40.8k
}
1565
1566
/*   <Pagelist_string> num_pages .PDFparsePageList even/odd, start, end ... range_count */
1567
/*   PostScript will create an array of 3 integers per range      */
1568
static int zPDFparsePageList(i_ctx_t *i_ctx_p)
1569
1
{
1570
1
    int code = 0, size = 0, i;
1571
1
    os_ptr op = osp;
1572
1
    int *page_range_array;
1573
1
    int num_pages;
1574
1575
1
    check_op(2);
1576
1577
0
    code = int_param(op, max_int, &num_pages);
1578
0
    if (code < 0)
1579
0
        return code;
1580
1581
0
    check_type_only(*(op - 1), t_string);
1582
1583
0
    code = pagelist_parse_to_array((char *)((op - 1)->value.const_bytes), imemory, num_pages, &page_range_array);
1584
0
    make_int(op, 0);        /* default return 0 */
1585
0
    if (code < 0) {
1586
0
        return code;
1587
0
    }
1588
    /* code returned is the number of ranges */
1589
0
    size = 3 * (code - 1);    /* runpdfpagerange doesn't use 0, 0, 0 marker at end */
1590
0
    code = ref_stack_push(&o_stack, size - 1);
1591
0
    if (code < 0) {
1592
0
        return code;
1593
0
    }
1594
    /* push the even/odd, start, end triples on the stack */
1595
0
    for (i=0; i < size;  i++) {
1596
        /* skip the initial "ordered" flag */
1597
0
        make_int(ref_stack_index(&o_stack, size - i), page_range_array[i+1]);
1598
0
    }
1599
0
    make_int(ref_stack_index(&o_stack, 0), size);
1600
0
    pagelist_free_range_array(imemory, page_range_array);    /* all done with C array */
1601
0
    return 0;
1602
0
}
1603
#else
1604
1605
static int zPDFfile(i_ctx_t *i_ctx_p)
1606
{
1607
    return_error(gs_error_undefined);
1608
}
1609
1610
static int zPDFstream(i_ctx_t *i_ctx_p)
1611
{
1612
    return_error(gs_error_undefined);
1613
}
1614
1615
static int zPDFclose(i_ctx_t *i_ctx_p)
1616
{
1617
    return_error(gs_error_undefined);
1618
}
1619
1620
static int zPDFinfo(i_ctx_t *i_ctx_p)
1621
{
1622
    return_error(gs_error_undefined);
1623
}
1624
1625
static int zPDFpageinfo(i_ctx_t *i_ctx_p)
1626
{
1627
    return_error(gs_error_undefined);
1628
}
1629
1630
static int zPDFpageinfoExt(i_ctx_t *i_ctx_p)
1631
{
1632
    return_error(gs_error_undefined);
1633
}
1634
1635
static int zPDFmetadata(i_ctx_t *i_ctx_p)
1636
{
1637
    return_error(gs_error_undefined);
1638
}
1639
1640
static int zPDFdrawpage(i_ctx_t *i_ctx_p)
1641
{
1642
    return_error(gs_error_undefined);
1643
}
1644
1645
static int zPDFdrawannots(i_ctx_t *i_ctx_p)
1646
{
1647
    return_error(gs_error_undefined);
1648
}
1649
1650
static int zPDFInit(i_ctx_t *i_ctx_p)
1651
{
1652
    return_error(gs_error_undefined);
1653
}
1654
1655
static int zPDFparsePageList(i_ctx_t *i_ctx_p)
1656
{
1657
    return_error(gs_error_undefined);
1658
}
1659
#endif
1660
1661
static int zPDFAvailable(i_ctx_t *i_ctx_p)
1662
40.8k
{
1663
40.8k
    os_ptr op = osp;
1664
1665
40.8k
    push(1);
1666
40.8k
#if defined(BUILD_PDF) && BUILD_PDF == 1
1667
40.8k
    make_bool(op, true);
1668
#else
1669
    make_bool(op, false);
1670
#endif
1671
40.8k
    return 0;
1672
40.8k
}
1673
1674
/* ------ Initialization procedure ------ */
1675
1676
const op_def zpdfops_op_defs[] =
1677
{
1678
    {"0.pdfinkpath", zpdfinkpath},
1679
    {"1.pdfFormName", zpdfFormName},
1680
    {"3.setscreenphase", zsetscreenphase},
1681
    {"0.PDFFile", zPDFfile},
1682
    {"1.PDFStream", zPDFstream},
1683
    {"1.PDFClose", zPDFclose},
1684
    {"1.PDFInfo", zPDFinfo},
1685
    {"1.PDFPageInfo", zPDFpageinfo},
1686
    {"1.PDFPageInfoExt", zPDFpageinfoExt},
1687
    {"1.PDFMetadata", zPDFmetadata},
1688
    {"1.PDFDrawPage", zPDFdrawpage},
1689
    {"1.PDFDrawAnnots", zPDFdrawannots},
1690
    {"1.PDFInit", zPDFInit},
1691
    {"1.PDFparsePageList", zPDFparsePageList},
1692
    {"0.PDFAvailable", zPDFAvailable},
1693
#ifdef HAVE_LIBIDN
1694
    {"1.saslprep", zsaslprep},
1695
#endif
1696
    op_def_end(0)
1697
};