Coverage Report

Created: 2026-04-09 07:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/pdf/pdftop.c
Line
Count
Source
1
/* Copyright (C) 2018-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
/* Top-level API implementation of PDF */
17
18
/* Language wrapper implementation (see pltop.h) */
19
20
#include "ghostpdf.h"
21
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
26.9k
#define GS_LIB_DEFAULT_STRING GS_STRINGIZE(GS_LIB_DEFAULT)
57
58
static int
59
pdf_detect_language(const char *s, int len)
60
19.2k
{
61
19.2k
    if (len >= 5 && memcmp(s, "%PDF-", 5) == 0)
62
81
        return 100;
63
19.1k
    return 0;
64
19.2k
}
65
66
static const pl_interp_characteristics_t *
67
pdf_impl_characteristics(const pl_interp_implementation_t *pimpl)
68
40.9k
{
69
40.9k
    static pl_interp_characteristics_t pdf_characteristics =
70
40.9k
    {
71
40.9k
        "PDF",
72
40.9k
        pdf_detect_language,
73
40.9k
    };
74
40.9k
    return &pdf_characteristics;
75
40.9k
}
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
0
{
102
0
    return pl_finish_page(ctx->memory->gs_lib_ctx->top_of_system, ctx->pgs, 1, true);
103
0
}
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
8.97k
{
110
8.97k
    pdf_interp_instance_t *instance;
111
8.97k
    pdf_context *ctx;
112
8.97k
    int code;
113
8.97k
    const char *rompathstr = "%rom%Resource/Init";
114
8.97k
    const char *deflibstr = GS_LIB_DEFAULT_STRING;
115
8.97k
    char *newpathsstr = (char *)deflibstr;
116
117
8.97k
    instance = (pdf_interp_instance_t *) gs_alloc_bytes(pmem,
118
8.97k
            sizeof(pdf_interp_instance_t), "pdf_impl_allocate_interp_instance");
119
120
8.97k
    if (!instance)
121
0
        return gs_error_VMerror;
122
123
8.97k
    ctx = pdfi_create_context(pmem);
124
125
8.97k
    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
8.97k
    ctx->finish_page = pdf_impl_finish_page;
131
132
8.97k
    ctx->instance = instance;
133
8.97k
    instance->ctx = ctx;
134
8.97k
    instance->scratch_file = NULL;
135
8.97k
    instance->scratch_name[0] = 0;
136
8.97k
    instance->memory = pmem;
137
138
8.97k
    impl->interp_client_data = instance;
139
8.97k
    if (COMPILE_INITS == 1) {
140
8.97k
        newpathsstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(rompathstr) + strlen(GS_LIB_DEFAULT_STRING) + 2, "temp paths string");
141
8.97k
        if (newpathsstr == NULL) {
142
0
            newpathsstr = (char *)rompathstr;
143
0
        }
144
8.97k
        else {
145
8.97k
            char sepstr[2];
146
147
8.97k
            sepstr[0] = gp_file_name_list_separator;
148
8.97k
            sepstr[1] = '\0';
149
150
8.97k
            memcpy(newpathsstr, rompathstr, strlen(rompathstr) + 1);
151
8.97k
            strncat(newpathsstr, sepstr, strlen(sepstr));
152
8.97k
            strncat(newpathsstr, GS_LIB_DEFAULT_STRING, strlen(GS_LIB_DEFAULT_STRING));
153
8.97k
        }
154
8.97k
    }
155
156
8.97k
    code = pdfi_add_initial_paths_to_search_paths(ctx, newpathsstr, strlen(newpathsstr));
157
8.97k
    if (newpathsstr != deflibstr && newpathsstr != rompathstr) {
158
8.97k
        gs_free_object(ctx->memory, newpathsstr, "temp paths string");
159
8.97k
    }
160
8.97k
    return code;
161
8.97k
}
162
163
static int
164
pdf_impl_set_device(pl_interp_implementation_t *impl, gx_device *pdevice)
165
81
{
166
81
    pdf_interp_instance_t *instance = impl->interp_client_data;
167
81
    pdf_context *ctx = instance->ctx;
168
81
    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
81
    code = gs_gsave(ctx->pgs);
181
81
    if (code < 0)
182
0
        goto cleanup_gsave;
183
184
81
    code = gs_setdevice_no_erase(ctx->pgs, pdevice);
185
81
    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
81
    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
81
    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
81
    } else {
222
        /* true for "low resolution" devices */
223
81
        gs_setstrokeadjust(ctx->pgs, true);
224
81
    }
225
226
81
    gs_setscanconverter(ctx->pgs, pl_main_get_scanconverter(ctx->memory));
227
228
81
    code = gs_erasepage(ctx->pgs);
229
81
    if (code < 0)
230
0
        goto cleanup_erase;
231
232
81
    code = pdfi_install_halftone(ctx, pdevice);
233
81
    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
81
    if (pdfi_device_check_param_exists(pdevice, "ForOPDFRead")) {
243
0
        gs_newpath(ctx->pgs);
244
0
        gs_fill(ctx->pgs);
245
0
    }
246
247
81
    ctx->job_gstate_level = ctx->pgs->level;
248
81
    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
81
{
268
81
    pdf_interp_instance_t *instance = impl->interp_client_data;
269
81
    pdf_context *ctx = instance->ctx;
270
81
    int code;
271
272
81
    code = pdfi_process_pdf_file(ctx, (char *)filename);
273
81
    if (code)
274
81
        return code;
275
276
0
    return 0;
277
81
}
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
8.97k
{
468
8.97k
    if (pvalue->type == gs_param_type_bool) {
469
8.97k
        *pbool = pvalue->value.b;
470
8.97k
        return 0;
471
8.97k
    }
472
8.97k
    return_error(gs_error_typecheck);
473
8.97k
}
474
475
1.54M
#define argis(P, S) \
476
1.54M
(!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
35.8k
{
482
35.8k
    pdf_interp_instance_t *instance = impl->interp_client_data;
483
35.8k
    pdf_context *ctx = instance->ctx;
484
35.8k
    gs_param_enumerator_t enumerator;
485
35.8k
    gs_param_key_t key;
486
35.8k
    int code;
487
35.8k
    int len;
488
35.8k
    bool discard_isname;
489
35.8k
    bool Printed_set = false;
490
491
35.8k
    param_init_enumerator(&enumerator);
492
35.8k
    if ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
493
35.8k
        char param[256];  /* big enough for any reasonable key */
494
35.8k
        gs_param_typed_value pvalue;
495
496
35.8k
        if (key.size > sizeof(param) - 1) {
497
0
            code = gs_note_error(gs_error_rangecheck);
498
0
            goto exit;
499
0
        }
500
35.8k
        memcpy(param, key.data, key.size);
501
35.8k
        param[key.size] = 0;
502
35.8k
        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
35.8k
        if (argis(param, "QUIET")) {
508
8.97k
            code = plist_value_get_bool(&pvalue, &ctx->args.QUIET);
509
8.97k
            if (code < 0)
510
0
                return code;
511
8.97k
        }
512
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        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
35.8k
        if (argis(param, "OutputFile")) {
741
8.97k
            if (!Printed_set)
742
8.97k
                ctx->args.printed = true;
743
8.97k
        }
744
35.8k
    }
745
746
35.8k
 exit:
747
35.8k
    return code;
748
35.8k
}
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
8.97k
{
762
8.97k
    return 0;
763
8.97k
}
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
81
{
770
81
    pdf_interp_instance_t *instance = impl->interp_client_data;
771
81
    pdf_context *ctx = instance->ctx;
772
773
81
    if (getenv("PDF_DISABLE_TRANSPARENCY"))
774
0
        ctx->args.notransparency = true;
775
776
81
    return pdf_impl_set_device(impl, device);
777
81
}
778
779
/* Wrap up interp instance after a "job" */
780
static int
781
pdf_impl_dnit_job(pl_interp_implementation_t *impl)
782
81
{
783
81
    pdf_interp_instance_t *instance = impl->interp_client_data;
784
81
    pdf_context *ctx = instance->ctx;
785
786
81
    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
81
}
792
793
/* Deallocate a interpreter instance */
794
static int
795
pdf_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
796
8.97k
{
797
8.97k
    pdf_interp_instance_t *instance = impl->interp_client_data;
798
8.97k
    pdf_context *ctx = instance->ctx;
799
8.97k
    gs_memory_t *mem = instance->memory;
800
8.97k
    int code = 0;
801
802
8.97k
    code = pdfi_free_context(ctx);
803
804
8.97k
    gs_free_object(mem, instance, "pdf_impl_deallocate_interp_instance");
805
806
8.97k
    return code;
807
8.97k
}
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
20.7k
{
840
20.7k
    return tint;
841
20.7k
}
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
81
{
870
81
    gs_halftone ht;
871
81
    gs_string thresh;
872
81
    int code;
873
874
81
    int width = 16;
875
81
    int height = 16;
876
81
    thresh.data = order16x16;
877
81
    thresh.size = width * height;
878
879
81
    if (gx_device_must_halftone(pdevice))
880
81
    {
881
81
        memset(&ht.rc, 0x00, sizeof(ht.rc));
882
81
        ht.type = ht_type_threshold;
883
81
        ht.objtype = HT_OBJTYPE_DEFAULT;
884
81
        ht.params.threshold.width = width;
885
81
        ht.params.threshold.height = height;
886
81
        ht.params.threshold.thresholds.data = thresh.data;
887
81
        ht.params.threshold.thresholds.size = thresh.size;
888
81
        ht.params.threshold.transfer = 0;
889
81
        ht.params.threshold.transfer_closure.proc = 0;
890
891
81
        gs_settransfer(ctx->pgs, identity_transfer);
892
893
81
        code = gs_sethalftone(ctx->pgs, &ht);
894
81
        if (code < 0)
895
0
            return gs_throw(code, "could not install halftone");
896
897
81
        code = gs_sethalftonephase(ctx->pgs, 0, 0);
898
81
        if (code < 0)
899
0
            return gs_throw(code, "could not set halftone phase");
900
81
    }
901
902
81
    return 0;
903
81
}