Coverage Report

Created: 2026-07-24 07:44

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