Coverage Report

Created: 2026-04-01 07:17

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
24.2k
#define GS_LIB_DEFAULT_STRING GS_STRINGIZE(GS_LIB_DEFAULT)
57
58
static int
59
pdf_detect_language(const char *s, int len)
60
17.7k
{
61
17.7k
    if (len >= 5 && memcmp(s, "%PDF-", 5) == 0)
62
8
        return 100;
63
17.7k
    return 0;
64
17.7k
}
65
66
static const pl_interp_characteristics_t *
67
pdf_impl_characteristics(const pl_interp_implementation_t *pimpl)
68
37.5k
{
69
37.5k
    static pl_interp_characteristics_t pdf_characteristics =
70
37.5k
    {
71
37.5k
        "PDF",
72
37.5k
        pdf_detect_language,
73
37.5k
    };
74
37.5k
    return &pdf_characteristics;
75
37.5k
}
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.09k
{
110
8.09k
    pdf_interp_instance_t *instance;
111
8.09k
    pdf_context *ctx;
112
8.09k
    int code;
113
8.09k
    const char *rompathstr = "%rom%Resource/Init";
114
8.09k
    const char *deflibstr = GS_LIB_DEFAULT_STRING;
115
8.09k
    char *newpathsstr = (char *)deflibstr;
116
117
8.09k
    instance = (pdf_interp_instance_t *) gs_alloc_bytes(pmem,
118
8.09k
            sizeof(pdf_interp_instance_t), "pdf_impl_allocate_interp_instance");
119
120
8.09k
    if (!instance)
121
0
        return gs_error_VMerror;
122
123
8.09k
    ctx = pdfi_create_context(pmem);
124
125
8.09k
    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.09k
    ctx->finish_page = pdf_impl_finish_page;
131
132
8.09k
    ctx->instance = instance;
133
8.09k
    instance->ctx = ctx;
134
8.09k
    instance->scratch_file = NULL;
135
8.09k
    instance->scratch_name[0] = 0;
136
8.09k
    instance->memory = pmem;
137
138
8.09k
    impl->interp_client_data = instance;
139
8.09k
    if (COMPILE_INITS == 1) {
140
8.09k
        newpathsstr = (char *)gs_alloc_bytes(ctx->memory, (size_t)strlen(rompathstr) + strlen(GS_LIB_DEFAULT_STRING) + 2, "temp paths string");
141
8.09k
        if (newpathsstr == NULL) {
142
0
            newpathsstr = (char *)rompathstr;
143
0
        }
144
8.09k
        else {
145
8.09k
            char sepstr[2];
146
147
8.09k
            sepstr[0] = gp_file_name_list_separator;
148
8.09k
            sepstr[1] = '\0';
149
150
8.09k
            memcpy(newpathsstr, rompathstr, strlen(rompathstr) + 1);
151
8.09k
            strncat(newpathsstr, sepstr, strlen(sepstr));
152
8.09k
            strncat(newpathsstr, GS_LIB_DEFAULT_STRING, strlen(GS_LIB_DEFAULT_STRING));
153
8.09k
        }
154
8.09k
    }
155
156
8.09k
    code = pdfi_add_initial_paths_to_search_paths(ctx, newpathsstr, strlen(newpathsstr));
157
8.09k
    if (newpathsstr != deflibstr && newpathsstr != rompathstr) {
158
8.09k
        gs_free_object(ctx->memory, newpathsstr, "temp paths string");
159
8.09k
    }
160
8.09k
    return code;
161
8.09k
}
162
163
static int
164
pdf_impl_set_device(pl_interp_implementation_t *impl, gx_device *pdevice)
165
8
{
166
8
    pdf_interp_instance_t *instance = impl->interp_client_data;
167
8
    pdf_context *ctx = instance->ctx;
168
8
    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
8
    code = gs_gsave(ctx->pgs);
181
8
    if (code < 0)
182
0
        goto cleanup_gsave;
183
184
8
    code = gs_setdevice_no_erase(ctx->pgs, pdevice);
185
8
    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
8
    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
8
    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
8
    } else {
222
        /* true for "low resolution" devices */
223
8
        gs_setstrokeadjust(ctx->pgs, true);
224
8
    }
225
226
8
    gs_setscanconverter(ctx->pgs, pl_main_get_scanconverter(ctx->memory));
227
228
8
    code = gs_erasepage(ctx->pgs);
229
8
    if (code < 0)
230
0
        goto cleanup_erase;
231
232
8
    code = pdfi_install_halftone(ctx, pdevice);
233
8
    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
8
    if (pdfi_device_check_param_exists(pdevice, "ForOPDFRead")) {
243
0
        gs_newpath(ctx->pgs);
244
0
        gs_fill(ctx->pgs);
245
0
    }
246
247
8
    ctx->job_gstate_level = ctx->pgs->level;
248
8
    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
8
{
268
8
    pdf_interp_instance_t *instance = impl->interp_client_data;
269
8
    pdf_context *ctx = instance->ctx;
270
8
    int code;
271
272
8
    code = pdfi_process_pdf_file(ctx, (char *)filename);
273
8
    if (code)
274
8
        return code;
275
276
0
    return 0;
277
8
}
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.09k
{
468
8.09k
    if (pvalue->type == gs_param_type_bool) {
469
8.09k
        *pbool = pvalue->value.b;
470
8.09k
        return 0;
471
8.09k
    }
472
8.09k
    return_error(gs_error_typecheck);
473
8.09k
}
474
475
1.39M
#define argis(P, S) \
476
1.39M
(!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
32.3k
{
482
32.3k
    pdf_interp_instance_t *instance = impl->interp_client_data;
483
32.3k
    pdf_context *ctx = instance->ctx;
484
32.3k
    gs_param_enumerator_t enumerator;
485
32.3k
    gs_param_key_t key;
486
32.3k
    int code;
487
32.3k
    int len;
488
32.3k
    bool discard_isname;
489
32.3k
    bool Printed_set = false;
490
491
32.3k
    param_init_enumerator(&enumerator);
492
32.3k
    if ((code = param_get_next_key(plist, &enumerator, &key)) == 0) {
493
32.3k
        char param[256];  /* big enough for any reasonable key */
494
32.3k
        gs_param_typed_value pvalue;
495
496
32.3k
        if (key.size > sizeof(param) - 1) {
497
0
            code = gs_note_error(gs_error_rangecheck);
498
0
            goto exit;
499
0
        }
500
32.3k
        memcpy(param, key.data, key.size);
501
32.3k
        param[key.size] = 0;
502
32.3k
        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
32.3k
        if (argis(param, "QUIET")) {
508
8.09k
            code = plist_value_get_bool(&pvalue, &ctx->args.QUIET);
509
8.09k
            if (code < 0)
510
0
                return code;
511
8.09k
        }
512
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        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
32.3k
        if (argis(param, "OutputFile")) {
741
8.09k
            if (!Printed_set)
742
8.09k
                ctx->args.printed = true;
743
8.09k
        }
744
32.3k
    }
745
746
32.3k
 exit:
747
32.3k
    return code;
748
32.3k
}
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.09k
{
762
8.09k
    return 0;
763
8.09k
}
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
8
{
770
8
    pdf_interp_instance_t *instance = impl->interp_client_data;
771
8
    pdf_context *ctx = instance->ctx;
772
773
8
    if (getenv("PDF_DISABLE_TRANSPARENCY"))
774
0
        ctx->args.notransparency = true;
775
776
8
    return pdf_impl_set_device(impl, device);
777
8
}
778
779
/* Wrap up interp instance after a "job" */
780
static int
781
pdf_impl_dnit_job(pl_interp_implementation_t *impl)
782
8
{
783
8
    pdf_interp_instance_t *instance = impl->interp_client_data;
784
8
    pdf_context *ctx = instance->ctx;
785
786
8
    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
8
}
792
793
/* Deallocate a interpreter instance */
794
static int
795
pdf_impl_deallocate_interp_instance(pl_interp_implementation_t *impl)
796
8.09k
{
797
8.09k
    pdf_interp_instance_t *instance = impl->interp_client_data;
798
8.09k
    pdf_context *ctx = instance->ctx;
799
8.09k
    gs_memory_t *mem = instance->memory;
800
8.09k
    int code = 0;
801
802
8.09k
    code = pdfi_free_context(ctx);
803
804
8.09k
    gs_free_object(mem, instance, "pdf_impl_deallocate_interp_instance");
805
806
8.09k
    return code;
807
8.09k
}
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
2.04k
{
840
2.04k
    return tint;
841
2.04k
}
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
8
{
870
8
    gs_halftone ht;
871
8
    gs_string thresh;
872
8
    int code;
873
874
8
    int width = 16;
875
8
    int height = 16;
876
8
    thresh.data = order16x16;
877
8
    thresh.size = width * height;
878
879
8
    if (gx_device_must_halftone(pdevice))
880
8
    {
881
8
        memset(&ht.rc, 0x00, sizeof(ht.rc));
882
8
        ht.type = ht_type_threshold;
883
8
        ht.objtype = HT_OBJTYPE_DEFAULT;
884
8
        ht.params.threshold.width = width;
885
8
        ht.params.threshold.height = height;
886
8
        ht.params.threshold.thresholds.data = thresh.data;
887
8
        ht.params.threshold.thresholds.size = thresh.size;
888
8
        ht.params.threshold.transfer = 0;
889
8
        ht.params.threshold.transfer_closure.proc = 0;
890
891
8
        gs_settransfer(ctx->pgs, identity_transfer);
892
893
8
        code = gs_sethalftone(ctx->pgs, &ht);
894
8
        if (code < 0)
895
0
            return gs_throw(code, "could not install halftone");
896
897
8
        code = gs_sethalftonephase(ctx->pgs, 0, 0);
898
8
        if (code < 0)
899
0
            return gs_throw(code, "could not set halftone phase");
900
8
    }
901
902
8
    return 0;
903
8
}