Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdftop.c
Line
Count
Source
1
/* Copyright (C) 2018-2026 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
/* Top-level API implementation of PDF */
17
18
/* Language wrapper implementation (see pltop.h) */
19
20
#include "ghostpdf.h"
21
#include "gscdefs.h"
22
#include "pltop.h"
23
#include "plmain.h"
24
25
#include "plparse.h"        /* for e_ExitLanguage */
26
#include "gxdevice.h"       /* so we can include gxht.h below */
27
#include "gxht.h"           /* gsht1.h is incomplete, we need storage size of gs_halftone */
28
#include "gsht1.h"
29
#include "pdf_device.h"
30
#include "pdf_misc.h"
31
32
#include "gsstate.h"        /* For gs_sethalftonephase() */
33
#include "gspaint.h"        /* For gs_erasepage() */
34
#include "gscolor3.h"       /* For gs_setsmoothness() */
35
36
extern const char gp_file_name_list_separator;
37
38
static int pdfi_install_halftone(pdf_context *ctx, gx_device *pdevice);
39
static int pdf_impl_add_path(pl_interp_implementation_t *impl, const char *path);
40
41
/*
42
 * The PDF interpreter instance is derived from pl_interp_implementation_t.
43
 */
44
45
typedef struct pdf_interp_instance_s
46
{
47
    gs_memory_t *memory;                /* memory allocator to use */
48
49
    pdf_context *ctx;
50
    gp_file *scratch_file;
51
    char scratch_name[gp_file_name_sizeof];
52
}pdf_interp_instance_t;
53
54
extern const char gp_file_name_list_separator;
55
56
33.0k
#define GS_LIB_DEFAULT_STRING GS_STRINGIZE(gs_lib_default_path)
57
58
static int
59
pdf_detect_language(const char *s, int len)
60
22.7k
{
61
22.7k
    if (len >= 5 && memcmp(s, "%PDF-", 5) == 0)
62
315
        return 100;
63
22.4k
    return 0;
64
22.7k
}
65
66
static const pl_interp_characteristics_t *
67
pdf_impl_characteristics(const pl_interp_implementation_t *pimpl)
68
48.4k
{
69
48.4k
    static pl_interp_characteristics_t pdf_characteristics =
70
48.4k
    {
71
48.4k
        "PDF",
72
48.4k
        pdf_detect_language,
73
48.4k
    };
74
48.4k
    return &pdf_characteristics;
75
48.4k
}
76
77
#if 0 /* the following are not currently used */
78
static void
79
pdf_set_nocache(pl_interp_implementation_t *impl, gs_font_dir *font_dir)
80
{
81
    bool nocache;
82
    pdf_interp_instance_t *pdfi  = impl->interp_client_data;
83
    nocache = pl_main_get_nocache(pdfi->memory);
84
    if (nocache)
85
        gs_setcachelimit(font_dir, 0);
86
    return;
87
}
88
89
90
static int
91
pdf_set_icc_user_params(pl_interp_implementation_t *impl, gs_gstate *pgs)
92
{
93
    pdf_interp_instance_t *pdfi  = impl->interp_client_data;
94
    return pl_set_icc_params(pdfi->memory, pgs);
95
}
96
97
#endif
98
99
static int
100
pdf_impl_finish_page(pdf_context *ctx)
101
112
{
102
112
    return pl_finish_page(ctx->memory->gs_lib_ctx->top_of_system, ctx->pgs, 1, true);
103
112
}
104
105
/* Do per-instance interpreter allocation/init. No device is set yet */
106
static int
107
pdf_impl_allocate_interp_instance(pl_interp_implementation_t *impl,
108
                                 gs_memory_t *pmem)
109
11.0k
{
110
11.0k
    pdf_interp_instance_t *instance;
111
11.0k
    pdf_context *ctx;
112
11.0k
    int code;
113
11.0k
    const char *rompathstr = "%rom%Resource/Init";
114
11.0k
    const char *deflibstr = GS_LIB_DEFAULT_STRING;
115
11.0k
    char *newpathsstr = (char *)deflibstr;
116
117
11.0k
    instance = (pdf_interp_instance_t *) gs_alloc_bytes(pmem,
118
11.0k
            sizeof(pdf_interp_instance_t), "pdf_impl_allocate_interp_instance");
119
120
11.0k
    if (!instance)
121
0
        return gs_error_VMerror;
122
123
11.0k
    ctx = pdfi_create_context(pmem);
124
125
11.0k
    if (ctx == NULL) {
126
0
        gs_free_object(pmem, instance, "pdf_impl_allocate_interp_instance");
127
0
        return gs_error_VMerror;
128
0
    }
129
130
11.0k
    ctx->finish_page = pdf_impl_finish_page;
131
132
11.0k
    ctx->instance = instance;
133
11.0k
    instance->ctx = ctx;
134
11.0k
    instance->scratch_file = NULL;
135
11.0k
    instance->scratch_name[0] = 0;
136
11.0k
    instance->memory = pmem;
137
138
11.0k
    impl->interp_client_data = instance;
139
11.0k
    if (COMPILE_INITS == 1) {
140
11.0k
        newpathsstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(rompathstr) + strlen(GS_LIB_DEFAULT_STRING) + 2, "temp paths string");
141
11.0k
        if (newpathsstr == NULL) {
142
0
            newpathsstr = (char *)rompathstr;
143
0
        }
144
11.0k
        else {
145
11.0k
            char sepstr[2];
146
147
11.0k
            sepstr[0] = gp_file_name_list_separator;
148
11.0k
            sepstr[1] = '\0';
149
150
11.0k
            memcpy(newpathsstr, rompathstr, strlen(rompathstr) + 1);
151
11.0k
            strncat(newpathsstr, sepstr, strlen(sepstr));
152
11.0k
            strncat(newpathsstr, GS_LIB_DEFAULT_STRING, strlen(GS_LIB_DEFAULT_STRING));
153
11.0k
        }
154
11.0k
    }
155
156
11.0k
    code = pdfi_add_initial_paths_to_search_paths(ctx, newpathsstr, strlen(newpathsstr));
157
11.0k
    if (newpathsstr != deflibstr && newpathsstr != rompathstr) {
158
11.0k
        gs_free_object(ctx->memory, newpathsstr, "temp paths string");
159
11.0k
    }
160
11.0k
    return code;
161
11.0k
}
162
163
static int
164
pdf_impl_set_device(pl_interp_implementation_t *impl, gx_device *pdevice)
165
315
{
166
315
    pdf_interp_instance_t *instance = impl->interp_client_data;
167
315
    pdf_context *ctx = instance->ctx;
168
315
    int code;
169
170
#if 0
171
    gx_device_fill_in_procs(pmi->device);
172
    code = gs_opendevice(pdevice);
173
    if (code < 0)
174
        goto cleanup_setdevice;
175
#endif
176
177
    /* gsave and grestore (among other places) assume that */
178
    /* there are at least 2 gstates on the graphics stack. */
179
    /* Ensure that now. */
180
315
    code = gs_gsave(ctx->pgs);
181
315
    if (code < 0)
182
0
        goto cleanup_gsave;
183
184
315
    code = gs_setdevice_no_erase(ctx->pgs, pdevice);
185
315
    if (code < 0)
186
0
        goto cleanup_setdevice;
187
188
    /* TODO: See stuff with init_graphics in pdfi_page_render -- I think this
189
     * should be collected in one place?
190
     * This is essentially doing it one time, and the other is doing it per page.
191
     * The main thing seems to be doing it here is before the pdfwrite device
192
     * gets setup, and doing it in pdf_page.c is after the pdfwrite device gets
193
     * setup.  It can cause spurious 'gs' state entries if there are discrepencies.
194
     */
195
    /* Doing this here to avoid having a ".02 /SM" entry showing up in ExtGState
196
     * of pdfwrite output.
197
     */
198
315
    code = gs_setsmoothness(ctx->pgs, 0.02); /* Match gs code */
199
200
    /* NOTE: Not sure what this is or when it matters, but it should match gs, which sets it to true */
201
    /* TODO: Compiled out because it caused a seemingly random incorrect pdfwrite output.
202
     * Will try putting it back in when pdfwrite is more stable.
203
     */
204
#if 0
205
    gs_setlimitclamp(ctx->pgs, true); /* Match gs code */
206
#endif
207
    /* We need to setup strokeadjust the same way gs does, which is currently based on
208
     * the device resolution and the DITHERPPI arg.
209
     *
210
     * TODO: Ken thinks 150 dpi is too low for the cutoff, but if so it should
211
     * change in both gs and here, so they match.  See gs_init.ps/.useloresscreen
212
     *
213
     * TODO: Currently pdfi-in-gs is not inheriting the graphics state from gs, so it
214
     * will have the wrong setting at 300dpi.  That needs to be fixed.
215
     * (but pdfi-in-gs never actually calls this function, it is supposed to inherit
216
     * the device and graphics state from gs.  Remove this comment when that is fixed :)
217
     */
218
315
    if (pdevice->HWResolution[0] >= 150 || pdevice->HWResolution[1] >= 150 || ctx->args.ditherppi) {
219
        /* false for "high resolution" devices */
220
0
        gs_setstrokeadjust(ctx->pgs, false);
221
315
    } else {
222
        /* true for "low resolution" devices */
223
315
        gs_setstrokeadjust(ctx->pgs, true);
224
315
    }
225
226
315
    gs_setscanconverter(ctx->pgs, pl_main_get_scanconverter(ctx->memory));
227
228
315
    code = gs_erasepage(ctx->pgs);
229
315
    if (code < 0)
230
0
        goto cleanup_erase;
231
232
315
    code = pdfi_install_halftone(ctx, pdevice);
233
315
    if (code < 0)
234
0
        goto cleanup_halftone;
235
236
    /* TODO: Hack to do what is in the bottom of gs_pdfwr.ps
237
     * This basically causes the pdfwrite device to be initialized.
238
     * Not sure if this is the correct place to do this.
239
     * Note that if running gs/pdfi, it will happen in the gs interpreter.
240
     * Putting it here means it only runs in gpdf, which seems correct.
241
     */
242
315
    if (pdfi_device_check_param_exists(pdevice, "ForOPDFRead")) {
243
0
        gs_newpath(ctx->pgs);
244
0
        gs_fill(ctx->pgs);
245
0
    }
246
247
315
    ctx->job_gstate_level = ctx->pgs->level;
248
315
    return 0;
249
250
0
cleanup_halftone:
251
0
cleanup_erase:
252
    /* undo gsave */
253
0
    gs_grestore_only(ctx->pgs);     /* destroys gs_save stack */
254
255
0
cleanup_gsave:
256
    /* undo setdevice */
257
0
    gs_nulldevice(ctx->pgs);
258
259
0
cleanup_setdevice:
260
    /* nothing to undo */
261
0
    return code;
262
0
}
263
264
/* Parse an entire random access file */
265
static int
266
pdf_impl_process_file(pl_interp_implementation_t *impl, const char *filename)
267
315
{
268
315
    pdf_interp_instance_t *instance = impl->interp_client_data;
269
315
    pdf_context *ctx = instance->ctx;
270
315
    int code;
271
272
315
    code = pdfi_process_pdf_file(ctx, (char *)filename);
273
315
    if (code)
274
194
        return code;
275
276
121
    return 0;
277
315
}
278
279
static int
280
pdf_impl_process_begin(pl_interp_implementation_t * impl)
281
0
{
282
0
    return 0;
283
0
}
284
285
/* Parse a cursor-full of data */
286
static int
287
pdf_impl_process(pl_interp_implementation_t *impl, stream_cursor_read *cursor)
288
0
{
289
0
    pdf_interp_instance_t *instance = impl->interp_client_data;
290
0
    pdf_context *ctx = instance->ctx;
291
0
    int avail, n;
292
293
0
    if (!instance->scratch_file)
294
0
    {
295
0
        instance->scratch_file = gp_open_scratch_file(ctx->memory,
296
0
            "ghostpdf-scratch-", instance->scratch_name, "wb");
297
0
        if (!instance->scratch_file)
298
0
        {
299
0
            gs_catch(gs_error_invalidfileaccess, "cannot open scratch file");
300
0
            return e_ExitLanguage;
301
0
        }
302
0
        if_debug1m('|', ctx->memory, "pdf: open scratch file '%s'\n", instance->scratch_name);
303
0
    }
304
305
0
    avail = cursor->limit - cursor->ptr;
306
0
    n = gp_fwrite(cursor->ptr + 1, 1, avail, instance->scratch_file);
307
0
    if (n != avail)
308
0
    {
309
0
        gs_catch(gs_error_invalidfileaccess, "cannot write to scratch file");
310
0
        return e_ExitLanguage;
311
0
    }
312
0
    cursor->ptr = cursor->limit;
313
314
0
    return 0;
315
0
}
316
317
static int                      /* ret 0 or +ve if ok, else -ve error code */
318
pdf_impl_process_end(pl_interp_implementation_t * impl)
319
0
{
320
0
    return 0;
321
0
}
322
323
/* Skip to end of job.
324
 * Return 1 if done, 0 ok but EOJ not found, else negative error code.
325
 */
326
static int
327
pdf_impl_flush_to_eoj(pl_interp_implementation_t *impl, stream_cursor_read *pcursor)
328
0
{
329
    /* assume PDF cannot be pjl embedded */
330
0
    pcursor->ptr = pcursor->limit;
331
0
    return 0;
332
0
}
333
334
/* Parser action for end-of-file */
335
static int
336
pdf_impl_process_eof(pl_interp_implementation_t *impl)
337
0
{
338
0
    pdf_interp_instance_t *instance = impl->interp_client_data;
339
0
    pdf_context *ctx = instance->ctx;
340
0
    int code;
341
342
0
    if (instance->scratch_file)
343
0
    {
344
0
        if_debug0m('|', ctx->memory, "pdf: executing scratch file\n");
345
0
        gp_fclose(instance->scratch_file);
346
0
        instance->scratch_file = NULL;
347
0
        code = pdfi_process_pdf_file(ctx, instance->scratch_name);
348
0
        gp_unlink(ctx->memory, instance->scratch_name);
349
0
        if (code < 0)
350
0
        {
351
0
            gs_catch(code, "cannot process PDF file");
352
0
            return e_ExitLanguage;
353
0
        }
354
0
    }
355
356
0
    return 0;
357
0
}
358
359
/* Report any errors after running a job */
360
static int
361
pdf_impl_report_errors(pl_interp_implementation_t *impl,
362
        int code,           /* prev termination status */
363
        long file_position, /* file position of error, -1 if unknown */
364
        bool force_to_cout  /* force errors to cout */
365
        )
366
0
{
367
0
    return 0;
368
0
}
369
370
#if 0
371
/*
372
 * Get the allocator with which to allocate a device
373
 */
374
static gs_memory_t *
375
pdf_impl_get_device_memory(pl_interp_implementation_t *impl)
376
{
377
    pdf_interp_instance_t *instance = impl->interp_client_data;
378
    pdf_context *ctx = instance->ctx;
379
380
    return ctx->memory;
381
}
382
#endif
383
384
static int plist_value_get_int64(gs_param_typed_value *pvalue, int64_t *pint)
385
0
{
386
0
    if (pvalue->type == gs_param_type_i64) {
387
0
        *pint = pvalue->value.i64;
388
0
        return 0;
389
0
    }
390
0
    return_error(gs_error_typecheck);
391
0
}
392
393
/* Get the value for a string or a name (null terminated) */
394
static int plist_value_get_string_or_name(pdf_context *ctx, gs_param_typed_value *pvalue,
395
                                          char **pstr, int *plen, bool *is_name)
396
0
{
397
0
    const byte *data;
398
0
    uint size;
399
400
0
    if (pvalue->type == gs_param_type_string) {
401
0
        data = pvalue->value.s.data;
402
0
        size = pvalue->value.s.size;
403
0
        *is_name = false;
404
0
    } else if (pvalue->type == gs_param_type_name) {
405
0
        data = pvalue->value.n.data;
406
0
        size = pvalue->value.n.size;
407
0
        *is_name = true;
408
0
    } else {
409
0
        return_error(gs_error_typecheck);
410
0
    }
411
412
    /* Free any previous value, for example if param appears more than once */
413
0
    if (*pstr)
414
0
        gs_free_object(ctx->memory, *pstr, "plist_value_get_string_or_name()");
415
416
0
    *pstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)size + 1, "plist_value_get_string_or_name()");
417
0
    if (*pstr == NULL)
418
0
        return_error(gs_error_VMerror);
419
420
0
    memcpy(*pstr, data, size);
421
0
    *((*pstr)+size) = 0; /* Null terminate */
422
0
    *plen = size;
423
0
    return 0;
424
0
}
425
426
/* Get the value for a list of names as c-strings, (null terminated) */
427
/* Format: -s/Item1,/Item2,/Item3 (no white space) */
428
static int plist_value_get_namelist(pdf_context *ctx, gs_param_typed_value *pvalue,
429
                                    char ***pstrlist)
430
0
{
431
0
    char *data;
432
0
    uint size;
433
434
0
    if (pvalue->type != gs_param_type_string)
435
0
        return_error(gs_error_typecheck);
436
437
0
    data = (char *)pvalue->value.s.data;
438
0
    size = pvalue->value.s.size;
439
440
0
    return pdfi_parse_name_cstring_array(ctx, data, size, pstrlist);
441
0
}
442
443
static int plist_value_get_int(gs_param_typed_value *pvalue, int *pint)
444
0
{
445
0
    if (pvalue->type == gs_param_type_int) {
446
0
        *pint = (int64_t)pvalue->value.i;
447
0
        return 0;
448
0
    }
449
0
    if (pvalue->type == gs_param_type_i64) {
450
0
        int64_t i64;
451
0
        int code;
452
453
0
        code = plist_value_get_int64(pvalue, &i64);
454
0
        if (code < 0)
455
0
            return code;
456
457
0
        if (i64 > ((int64_t)1 << 32))
458
0
            return_error(gs_error_rangecheck);
459
460
0
        *pint = (int)i64;
461
0
        return 0;
462
0
    }
463
0
    return_error(gs_error_typecheck);
464
0
}
465
466
static int plist_value_get_bool(gs_param_typed_value *pvalue, bool *pbool)
467
11.0k
{
468
11.0k
    if (pvalue->type == gs_param_type_bool) {
469
11.0k
        *pbool = pvalue->value.b;
470
11.0k
        return 0;
471
11.0k
    }
472
11.0k
    return_error(gs_error_typecheck);
473
11.0k
}
474
475
1.89M
#define argis(P, S) \
476
1.89M
(!strncmp((P), (S), sizeof(S)-1) && ((P)[sizeof(S)-1] == 0 || (P)[sizeof(S)-1] == '=' || (P)[sizeof(S)-1] == '#'))
477
478
static int
479
pdf_impl_set_param(pl_interp_implementation_t *impl,
480
                   gs_param_list    *plist)
481
44.0k
{
482
44.0k
    pdf_interp_instance_t *instance = impl->interp_client_data;
483
44.0k
    pdf_context *ctx = instance->ctx;
484
44.0k
    gs_param_enumerator_t enumerator;
485
44.0k
    gs_param_key_t key;
486
44.0k
    int code;
487
44.0k
    int len;
488
44.0k
    bool discard_isname;
489
44.0k
    bool Printed_set = false;
490
491
44.0k
    param_init_enumerator(&enumerator);
492
44.0k
    if ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
493
44.0k
        char param[256];  /* big enough for any reasonable key */
494
44.0k
        gs_param_typed_value pvalue;
495
496
44.0k
        if (key.size > sizeof(param) - 1) {
497
0
            code = gs_note_error(gs_error_rangecheck);
498
0
            goto exit;
499
0
        }
500
44.0k
        memcpy(param, key.data, key.size);
501
44.0k
        param[key.size] = 0;
502
44.0k
        if ((code = param_read_typed(plist, param, &pvalue)) != 0) {
503
0
            code = (code > 0 ? gs_note_error(gs_error_unknownerror) : code);
504
0
            goto exit;
505
0
        }
506
507
44.0k
        if (argis(param, "QUIET")) {
508
11.0k
            code = plist_value_get_bool(&pvalue, &ctx->args.QUIET);
509
11.0k
            if (code < 0)
510
0
                return code;
511
11.0k
        }
512
44.0k
        if (argis(param, "FirstPage")) {
513
0
            code = plist_value_get_int(&pvalue, &ctx->args.first_page);
514
0
            if (code < 0)
515
0
                return code;
516
0
        }
517
44.0k
        if (argis(param, "LastPage")) {
518
0
            code = plist_value_get_int(&pvalue, &ctx->args.last_page);
519
0
            if (code < 0)
520
0
                return code;
521
0
        }
522
        /* PDF interpreter flags */
523
44.0k
        if (argis(param, "VerboseErrors")) {
524
0
            code = plist_value_get_bool(&pvalue, &ctx->args.verbose_errors);
525
0
            if (code < 0)
526
0
                return code;
527
0
        }
528
44.0k
        if (argis(param, "VerboseWarnings")) {
529
0
            code = plist_value_get_bool(&pvalue, &ctx->args.verbose_warnings);
530
0
            if (code < 0)
531
0
                return code;
532
0
        }
533
44.0k
        if (argis(param, "PDFCACHE")) {
534
0
            code = plist_value_get_int(&pvalue, &ctx->args.PDFCacheSize);
535
0
            if (code < 0)
536
0
                return code;
537
0
        }
538
44.0k
        if (argis(param, "PDFDEBUG")) {
539
0
            code = plist_value_get_bool(&pvalue, &ctx->args.pdfdebug);
540
0
            if (code < 0)
541
0
                return code;
542
0
        }
543
44.0k
        if (argis(param, "PDFSTOPONERROR")) {
544
0
            code = plist_value_get_bool(&pvalue, &ctx->args.pdfstoponerror);
545
0
            if (code < 0)
546
0
                return code;
547
0
        }
548
44.0k
        if (argis(param, "PDFSTOPONWARNING")) {
549
0
            code = plist_value_get_bool(&pvalue, &ctx->args.pdfstoponwarning);
550
0
            if (code < 0)
551
0
                return code;
552
0
            if (ctx->args.pdfstoponwarning != 0)
553
0
                ctx->args.pdfstoponerror = 1;
554
0
        }
555
44.0k
        if (argis(param, "NOTRANSPARENCY")) {
556
0
            code = plist_value_get_bool(&pvalue, &ctx->args.notransparency);
557
0
            if (code < 0)
558
0
                return code;
559
0
        }
560
44.0k
        if (argis(param, "PDFNOCIDFALLBACK")) {
561
0
            code = plist_value_get_bool(&pvalue, &ctx->args.nocidfallback);
562
0
            if (code < 0)
563
0
                return code;
564
0
        }
565
44.0k
        if (argis(param, "NO_PDFMARK_OUTLINES")) {
566
0
            code = plist_value_get_bool(&pvalue, &ctx->args.no_pdfmark_outlines);
567
0
            if (code < 0)
568
0
                return code;
569
0
        }
570
44.0k
        if (argis(param, "NO_PDFMARK_DESTS")) {
571
0
            code = plist_value_get_bool(&pvalue, &ctx->args.no_pdfmark_dests);
572
0
            if (code < 0)
573
0
                return code;
574
0
        }
575
44.0k
        if (argis(param, "PDFFitPage")) {
576
0
            code = plist_value_get_bool(&pvalue, &ctx->args.pdffitpage);
577
0
            if (code < 0)
578
0
                return code;
579
0
        }
580
44.0k
        if (argis(param, "UseCropBox")) {
581
0
            code = plist_value_get_bool(&pvalue, &ctx->args.usecropbox);
582
0
            if (code < 0)
583
0
                return code;
584
0
        }
585
44.0k
        if (argis(param, "UseArtBox")) {
586
0
            code = plist_value_get_bool(&pvalue, &ctx->args.useartbox);
587
0
            if (code < 0)
588
0
                return code;
589
0
        }
590
44.0k
        if (argis(param, "UseBleedBox")) {
591
0
            code = plist_value_get_bool(&pvalue, &ctx->args.usebleedbox);
592
0
            if (code < 0)
593
0
                return code;
594
0
        }
595
44.0k
        if (argis(param, "UseTrimBox")) {
596
0
            code = plist_value_get_bool(&pvalue, &ctx->args.usetrimbox);
597
0
            if (code < 0)
598
0
                return code;
599
0
        }
600
44.0k
        if (argis(param, "Printed")) {
601
0
            code = plist_value_get_bool(&pvalue, &ctx->args.printed);
602
0
            if (code < 0)
603
0
                return code;
604
0
            Printed_set = true;
605
0
        }
606
44.0k
        if (argis(param, "DITHERPPI")) {
607
0
            code = plist_value_get_bool(&pvalue, &ctx->args.ditherppi);
608
0
            if (code < 0)
609
0
                return code;
610
0
        }
611
44.0k
        if (argis(param, "ShowAcroForm")) {
612
0
            code = plist_value_get_bool(&pvalue, &ctx->args.showacroform);
613
0
            if (code < 0)
614
0
                return code;
615
0
        }
616
44.0k
        if (argis(param, "ShowAnnots")) {
617
0
            code = plist_value_get_bool(&pvalue, &ctx->args.showannots);
618
0
            if (code < 0)
619
0
                return code;
620
0
        }
621
44.0k
        if (argis(param, "SHOWANNOTTYPES")) {
622
0
            code = plist_value_get_namelist(ctx, &pvalue, &ctx->args.showannottypes);
623
0
            if (code < 0)
624
0
                return code;
625
0
        }
626
44.0k
        if (argis(param, "PreserveAnnots")) {
627
0
            code = plist_value_get_bool(&pvalue, &ctx->args.preserveannots);
628
0
            if (code < 0)
629
0
                return code;
630
0
        }
631
44.0k
        if (argis(param, "PRESERVEANNOTTYPES")) {
632
0
            code = plist_value_get_namelist(ctx, &pvalue, &ctx->args.preserveannottypes);
633
0
            if (code < 0)
634
0
                return code;
635
0
        }
636
44.0k
        if (argis(param, "PreserveMarkedContent")) {
637
0
            code = plist_value_get_bool(&pvalue, &ctx->args.preservemarkedcontent);
638
0
            if (code < 0)
639
0
                return code;
640
0
        }
641
44.0k
        if (argis(param, "PreserveEmbeddedFiles")) {
642
0
            code = plist_value_get_bool(&pvalue, &ctx->args.preserveembeddedfiles);
643
0
            if (code < 0)
644
0
                return code;
645
0
        }
646
44.0k
        if (argis(param, "PreserveDocView")) {
647
0
            code = plist_value_get_bool(&pvalue, &ctx->args.preservedocview);
648
0
            if (code < 0)
649
0
                return code;
650
0
        }
651
44.0k
        if (argis(param, "NoUserUnit")) {
652
0
            code = plist_value_get_bool(&pvalue, &ctx->args.nouserunit);
653
0
            if (code < 0)
654
0
                return code;
655
0
        }
656
44.0k
        if (argis(param, "RENDERTTNOTDEF")) {
657
0
            code = plist_value_get_bool(&pvalue, &ctx->args.renderttnotdef);
658
0
            if (code < 0)
659
0
                return code;
660
0
        }
661
44.0k
        if (argis(param, "PDFINFO")) {
662
0
            code = plist_value_get_bool(&pvalue, &ctx->args.pdfinfo);
663
0
            if (code < 0)
664
0
                return code;
665
0
        }
666
44.0k
        if (argis(param, "DOPDFMARKS")) {
667
0
            code = plist_value_get_bool(&pvalue, &ctx->args.dopdfmarks);
668
0
            if (code < 0)
669
0
                return code;
670
0
        }
671
44.0k
        if (argis(param, "PDFPassword")) {
672
0
            code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->encryption.Password , &ctx->encryption.PasswordLen, &discard_isname);
673
0
            if (code < 0)
674
0
                return code;
675
0
        }
676
44.0k
        if (argis(param, "UsePDFX3Profile")) {
677
            /* This is a weird one because it can be either a bool or an int.
678
             * If it's a bool=true, then it defaults to PDFX3Profile_num = 0
679
             * If it's an int, then we set the flag to true and use the
680
             * specified number.
681
             * PS: Yuck!
682
             */
683
0
            code = plist_value_get_bool(&pvalue, &ctx->args.UsePDFX3Profile);
684
0
            if (code == gs_error_typecheck) {
685
0
                code = plist_value_get_int(&pvalue, &ctx->args.PDFX3Profile_num);
686
0
                if (code == 0)
687
0
                    ctx->args.UsePDFX3Profile = true;
688
0
            }
689
0
            if (code < 0)
690
0
                return code;
691
0
        }
692
44.0k
        if (argis(param, "NOSUBSTDEVICECOLORS")) {
693
0
            code = plist_value_get_bool(&pvalue, &ctx->args.NOSUBSTDEVICECOLORS);
694
0
            if (code < 0)
695
0
                return code;
696
0
        }
697
44.0k
        if (argis(param, "UseOutputIntent")) {
698
0
            code = plist_value_get_string_or_name(ctx, &pvalue, &ctx->args.UseOutputIntent, &len, &discard_isname);
699
0
            if (code < 0)
700
0
                return code;
701
0
        }
702
44.0k
        if (argis(param, "FONTPATH")) {
703
0
            char *s = NULL;
704
0
            int slen;
705
0
            code = plist_value_get_string_or_name(ctx, &pvalue, &s , &slen, &discard_isname);
706
0
            if (code < 0)
707
0
                return code;
708
0
            code = pdfi_add_paths_to_search_paths(ctx, (const char *)s, slen, true);
709
0
            gs_free_object(ctx->memory, s, "FONTPATH param string");
710
0
        }
711
44.0k
        if (argis(param, "FONTMAP")) {
712
0
            char *s = NULL;
713
0
            int slen;
714
0
            code = plist_value_get_string_or_name(ctx, &pvalue, &s, &slen, &discard_isname);
715
0
            if (code < 0)
716
0
                return code;
717
0
            code = pdfi_add_fontmapfiles(ctx, (const char *)s, slen);
718
0
            gs_free_object(ctx->memory, s, "FONTMAP param string");
719
0
        }
720
44.0k
        if (argis(param, "CIDSubstPath")) {
721
0
            code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidfsubstpath.data, (int *)&ctx->args.cidfsubstpath.size, &discard_isname);
722
0
            if (code < 0)
723
0
                return code;
724
0
        }
725
44.0k
        if (argis(param, "CIDFSubstFont")) {
726
0
            code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.cidfsubstfont.data, (int *)&ctx->args.cidfsubstfont.size, &discard_isname);
727
0
            if (code < 0)
728
0
                return code;
729
0
        }
730
44.0k
        if (argis(param, "SUBSTFONT")) {
731
0
            code = plist_value_get_string_or_name(ctx, &pvalue, (char **)&ctx->args.defaultfont.data, (int *)&ctx->args.defaultfont.size, &ctx->args.defaultfont_is_name);
732
0
            if (code < 0)
733
0
                return code;
734
0
        }
735
44.0k
        if (argis(param, "IgnoreToUnicode")) {
736
0
            code = plist_value_get_bool(&pvalue, &ctx->args.ignoretounicode);
737
0
            if (code < 0)
738
0
                return code;
739
0
        }
740
44.0k
        if (argis(param, "OutputFile")) {
741
11.0k
            if (!Printed_set)
742
11.0k
                ctx->args.printed = true;
743
11.0k
        }
744
44.0k
    }
745
746
44.0k
 exit:
747
44.0k
    return code;
748
44.0k
}
749
750
static int
751
pdf_impl_add_path(pl_interp_implementation_t *impl, const char *path)
752
0
{
753
0
    pdf_interp_instance_t *instance = impl->interp_client_data;
754
0
    pdf_context *ctx = instance->ctx;
755
756
0
    return pdfi_add_paths_to_search_paths(ctx, path, strlen(path), false);
757
0
}
758
759
static int
760
pdf_impl_post_args_init(pl_interp_implementation_t *impl)
761
11.0k
{
762
11.0k
    return 0;
763
11.0k
}
764
765
/* Prepare interp instance for the next "job" */
766
static int
767
pdf_impl_init_job(pl_interp_implementation_t *impl,
768
                 gx_device                  *device)
769
315
{
770
315
    pdf_interp_instance_t *instance = impl->interp_client_data;
771
315
    pdf_context *ctx = instance->ctx;
772
773
315
    if (getenv("PDF_DISABLE_TRANSPARENCY"))
774
0
        ctx->args.notransparency = true;
775
776
315
    return pdf_impl_set_device(impl, device);
777
315
}
778
779
/* Wrap up interp instance after a "job" */
780
static int
781
pdf_impl_dnit_job(pl_interp_implementation_t *impl)
782
315
{
783
315
    pdf_interp_instance_t *instance = impl->interp_client_data;
784
315
    pdf_context *ctx = instance->ctx;
785
786
315
    return gs_grestoreall(ctx->pgs); /* pdf_impl_set_device does a gsave which we need to restore now.
787
                                      * Using grestoreall will restore any dangling gstates back to the last restore.
788
                                      * This should ensure we don't have dangling references to the device created by the
789
                                      * top level code.
790
                                      */
791
315
}
792
793
/* Deallocate a interpreter instance */
794
static int
795
pdf_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
796
11.0k
{
797
11.0k
    pdf_interp_instance_t *instance = impl->interp_client_data;
798
11.0k
    pdf_context *ctx = instance->ctx;
799
11.0k
    gs_memory_t *mem = instance->memory;
800
11.0k
    int code = 0;
801
802
11.0k
    code = pdfi_free_context(ctx);
803
804
11.0k
    gs_free_object(mem, instance, "pdf_impl_deallocate_interp_instance");
805
806
11.0k
    return code;
807
11.0k
}
808
809
/* Parser implementation descriptor */
810
pl_interp_implementation_t pdf_implementation =
811
{
812
    pdf_impl_characteristics,
813
    pdf_impl_allocate_interp_instance,
814
    NULL,  /* pdf_impl_get_device_memory, */
815
    pdf_impl_set_param,
816
    pdf_impl_add_path,
817
    pdf_impl_post_args_init,
818
    pdf_impl_init_job,
819
    NULL,                               /* run_prefix_commands */
820
    pdf_impl_process_file,
821
    pdf_impl_process_begin,
822
    pdf_impl_process,
823
    pdf_impl_process_end,
824
    pdf_impl_flush_to_eoj,
825
    pdf_impl_process_eof,
826
    pdf_impl_report_errors,
827
    pdf_impl_dnit_job,
828
    pdf_impl_deallocate_interp_instance,
829
    NULL,                               /* interp_client_data */
830
};
831
832
/*
833
 * We need to install a halftone ourselves, this is not
834
 * done automatically.
835
 */
836
837
static float
838
identity_transfer(double tint, const gx_transfer_map *ignore_map)
839
80.6k
{
840
80.6k
    return tint;
841
80.6k
}
842
843
/* The following is a 45 degree spot screen with the spots enumerated
844
 * in a defined order. */
845
static byte order16x16[256] = {
846
    38, 11, 14, 32, 165, 105, 90, 171, 38, 12, 14, 33, 161, 101, 88, 167,
847
    30, 6, 0, 16, 61, 225, 231, 125, 30, 6, 1, 17, 63, 222, 227, 122,
848
    27, 3, 8, 19, 71, 242, 205, 110, 28, 4, 9, 20, 74, 246, 208, 106,
849
    35, 24, 22, 40, 182, 46, 56, 144, 36, 25, 22, 41, 186, 48, 58, 148,
850
    152, 91, 81, 174, 39, 12, 15, 34, 156, 95, 84, 178, 40, 13, 16, 34,
851
    69, 212, 235, 129, 31, 7, 2, 18, 66, 216, 239, 133, 32, 8, 2, 18,
852
    79, 254, 203, 114, 28, 4, 10, 20, 76, 250, 199, 118, 29, 5, 10, 21,
853
    193, 44, 54, 142, 36, 26, 23, 42, 189, 43, 52, 139, 37, 26, 24, 42,
854
    39, 12, 15, 33, 159, 99, 87, 169, 38, 11, 14, 33, 163, 103, 89, 172,
855
    31, 7, 1, 17, 65, 220, 229, 123, 30, 6, 1, 17, 62, 223, 233, 127,
856
    28, 4, 9, 20, 75, 248, 210, 108, 27, 3, 9, 19, 72, 244, 206, 112,
857
    36, 25, 23, 41, 188, 49, 60, 150, 35, 25, 22, 41, 184, 47, 57, 146,
858
    157, 97, 85, 180, 40, 13, 16, 35, 154, 93, 83, 176, 39, 13, 15, 34,
859
    67, 218, 240, 135, 32, 8, 3, 19, 70, 214, 237, 131, 31, 7, 2, 18,
860
    78, 252, 197, 120, 29, 5, 11, 21, 80, 255, 201, 116, 29, 5, 10, 21,
861
    191, 43, 51, 137, 37, 27, 24, 43, 195, 44, 53, 140, 37, 26, 23, 42
862
};
863
864
#define source_phase_x 4
865
#define source_phase_y 0
866
867
static int
868
pdfi_install_halftone(pdf_context *ctx, gx_device *pdevice)
869
315
{
870
315
    gs_halftone ht;
871
315
    gs_string thresh;
872
315
    int code;
873
874
315
    int width = 16;
875
315
    int height = 16;
876
315
    thresh.data = order16x16;
877
315
    thresh.size = width * height;
878
879
315
    if (gx_device_must_halftone(pdevice))
880
315
    {
881
315
        memset(&ht.rc, 0x00, sizeof(ht.rc));
882
315
        ht.type = ht_type_threshold;
883
315
        ht.objtype = HT_OBJTYPE_DEFAULT;
884
315
        ht.params.threshold.width = width;
885
315
        ht.params.threshold.height = height;
886
315
        ht.params.threshold.thresholds.data = thresh.data;
887
315
        ht.params.threshold.thresholds.size = thresh.size;
888
315
        ht.params.threshold.transfer = 0;
889
315
        ht.params.threshold.transfer_closure.proc = 0;
890
891
315
        gs_settransfer(ctx->pgs, identity_transfer);
892
893
315
        code = gs_sethalftone(ctx->pgs, &ht);
894
315
        if (code < 0)
895
0
            return gs_throw(code, "could not install halftone");
896
897
315
        code = gs_sethalftonephase(ctx->pgs, 0, 0);
898
315
        if (code < 0)
899
0
            return gs_throw(code, "could not set halftone phase");
900
315
    }
901
902
315
    return 0;
903
315
}