Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/psi/ztoken.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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
17
/* Token reading operators */
18
#include "string_.h"
19
#include "stat_.h" /* get system header early to avoid name clash on Cygwin */
20
#include "ghost.h"
21
#include "oper.h"
22
#include "dstack.h"             /* for dict_find_name */
23
#include "estack.h"
24
#include "gsstruct.h"           /* for iscan.h */
25
#include "gsutil.h"
26
#include "stream.h"
27
#include "files.h"
28
#include "store.h"
29
#include "strimpl.h"            /* for sfilter.h */
30
#include "sfilter.h"            /* for iscan.h */
31
#include "idict.h"
32
#include "iname.h"
33
#include "iscan.h"
34
#include "itoken.h"             /* for prototypes */
35
36
/* <file> token <obj> -true- */
37
/* <string> token <post> <obj> -true- */
38
/* <string|file> token -false- */
39
static int ztoken_continue(i_ctx_t *);
40
static int token_continue(i_ctx_t *, scanner_state *, bool);
41
int
42
ztoken(i_ctx_t *i_ctx_p)
43
151M
{
44
151M
    os_ptr op = osp;
45
46
151M
    check_op(1);
47
151M
    switch (r_type(op)) {
48
8
        default:
49
8
            return_op_typecheck(op);
50
151M
        case t_file: {
51
151M
            stream *s;
52
151M
            scanner_state state;
53
54
151M
            check_read_file(i_ctx_p, s, op);
55
151M
            check_ostack(1);
56
151M
            gs_scanner_init(&state, op);
57
151M
            return token_continue(i_ctx_p, &state, true);
58
151M
        }
59
4.17k
        case t_string: {
60
4.17k
            ref token;
61
            /* -1 is to remove the string operand in case of error. */
62
4.17k
            int orig_ostack_depth = ref_stack_count(&o_stack) - 1;
63
4.17k
            int code;
64
65
            /* Don't pop the operand in case of invalidaccess. */
66
4.17k
            if (!r_has_attr(op, a_read))
67
0
                return_error(gs_error_invalidaccess);
68
4.17k
            code = gs_scan_string_token(i_ctx_p, op, &token);
69
            /* gs_scan_string_token() can relocate the operand stack if a
70
             * stack overflow occurs. If that happens then 'op' is no
71
             * longer valid, so reload it now just in case.
72
             */
73
4.17k
            op = osp;
74
4.17k
            switch (code) {
75
117
            case scan_EOF:      /* no tokens */
76
117
                make_false(op);
77
117
                return 0;
78
4.05k
            default:
79
4.05k
                if (code < 0) {
80
                    /*
81
                     * Clear anything that may have been left on the ostack,
82
                     * including the string operand.
83
                     */
84
17
                    if (orig_ostack_depth < ref_stack_count(&o_stack))
85
17
                        pop(ref_stack_count(&o_stack)- orig_ostack_depth);
86
17
                    return code;
87
17
                }
88
4.17k
            }
89
4.17k
            push(2);
90
4.03k
            op[-1] = token;
91
4.03k
            make_true(op);
92
4.03k
            return 0;
93
4.03k
        }
94
151M
    }
95
151M
}
96
/* Continue reading a token after an interrupt or callout. */
97
/* *op is the scanner state. */
98
static int
99
ztoken_continue(i_ctx_t *i_ctx_p)
100
0
{
101
0
    os_ptr op = osp;
102
0
    scanner_state *pstate;
103
104
0
    check_op(1);
105
0
    check_stype(*op, st_scanner_state_dynamic);
106
0
    pstate = r_ptr(op, scanner_state);
107
0
    return token_continue(i_ctx_p, pstate, false);
108
0
}
109
/* Common code for token reading. */
110
static int
111
token_continue(i_ctx_t *i_ctx_p, scanner_state * pstate, bool save)
112
151M
{
113
151M
    os_ptr op = osp;
114
151M
    int code;
115
151M
    ref token;
116
151M
    avm_space usevm, currentvm = ialloc_space(idmemory);
117
151M
    check_op(1);
118
119
    /* If we're going to reuse an existing scanner_state object in gs_scan_handle_refill()
120
       we need to make sure the ref (and anything else associated with it) is marked with
121
       the vm mode of that scanner_state's allocation, *not* currentglobal.
122
     */
123
151M
    usevm = save ? ialloc_space(idmemory) : r_space(op);
124
125
    /* Since we might free pstate below, and we're dealing with
126
     * gc memory referenced by the stack, we need to explicitly
127
     * remove the reference to pstate from the stack, otherwise
128
     * the garbager will fall over
129
     */
130
151M
    make_null(osp);
131
    /* Note that gs_scan_token may change osp! */
132
151M
    pop(1);                     /* remove the file or scanner state */
133
151M
again:
134
151M
    code = gs_scan_token(i_ctx_p, &token, pstate);
135
151M
    op = osp;
136
151M
    switch (code) {
137
0
        default:                /* error */
138
0
            if (code > 0)       /* comment, not possible */
139
0
                code = gs_note_error(gs_error_syntaxerror);
140
0
            gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
141
0
            make_op_estack(esp + 1, ztoken);
142
0
            break;
143
0
        case scan_BOS:
144
0
            code = 0;
145
151M
        case 0:         /* read a token */
146
151M
            push(2);
147
151M
            ref_assign(op - 1, &token);
148
151M
            make_true(op);
149
151M
            break;
150
334k
        case scan_EOF:          /* no tokens */
151
334k
            push(1);
152
334k
            make_false(op);
153
334k
            code = 0;
154
334k
            break;
155
0
        case scan_Refill:       /* need more data */
156
0
            ialloc_set_space(idmemory, usevm);
157
0
            code = gs_scan_handle_refill(i_ctx_p, pstate, save,
158
0
                                      ztoken_continue);
159
0
            ialloc_set_space(idmemory, currentvm);
160
0
            switch (code) {
161
0
                case 0: /* state is not copied to the heap */
162
0
                    goto again;
163
0
                case o_push_estack:
164
0
                    return code;
165
0
            }
166
0
            break;              /* error */
167
151M
    }
168
151M
    if (code <= 0 && !save) {   /* Deallocate the scanner state record. */
169
0
        ifree_object(pstate, "token_continue");
170
0
    }
171
151M
    if (code < 0)
172
151M
        make_op_estack(esp + 1, ztoken);
173
151M
    return code;
174
151M
}
175
176
/* <file> .tokenexec - */
177
/* Read a token and do what the interpreter would do with it. */
178
/* This is different from token + exec because literal procedures */
179
/* are not executed (although binary object sequences ARE executed). */
180
int ztokenexec_continue(i_ctx_t *);     /* export for interpreter */
181
static int tokenexec_continue(i_ctx_t *, scanner_state *, bool);
182
int
183
ztokenexec(i_ctx_t *i_ctx_p)
184
0
{
185
0
    os_ptr op = osp;
186
0
    stream *s;
187
0
    scanner_state state;
188
189
0
    check_op(1);
190
0
    check_read_file(i_ctx_p, s, op);
191
0
    check_estack(1);
192
0
    gs_scanner_init(&state, op);
193
0
    return tokenexec_continue(i_ctx_p, &state, true);
194
0
}
195
/* Continue reading a token for execution after an interrupt or callout. */
196
/* *op is the scanner state. */
197
/* We export this because this is how the interpreter handles a */
198
/* scan_Refill for an executable file. */
199
int
200
ztokenexec_continue(i_ctx_t *i_ctx_p)
201
3.30M
{
202
3.30M
    os_ptr op = osp;
203
3.30M
    scanner_state *pstate;
204
205
3.30M
    check_op(1);
206
3.30M
    check_stype(*op, st_scanner_state_dynamic);
207
3.30M
    pstate = r_ptr(op, scanner_state);
208
3.30M
    return tokenexec_continue(i_ctx_p, pstate, false);
209
3.30M
}
210
/* Common code for token reading + execution. */
211
static int
212
tokenexec_continue(i_ctx_t *i_ctx_p, scanner_state * pstate, bool save)
213
3.30M
{
214
3.30M
    os_ptr op = osp;
215
3.30M
    int code;
216
3.30M
    avm_space usevm, currentvm = ialloc_space(idmemory);
217
3.30M
    check_op(1);
218
219
    /* If we're going to reuse an existing scanner_state object in gs_scan_handle_refill()
220
       we need to make sure the ref (and anything else associated with it) is marked with
221
       the vm mode of that scanner_state's allocation, *not* currentglobal.
222
     */
223
3.30M
    usevm = save ? ialloc_space(idmemory) : r_space(op);
224
225
    /* Since we might free pstate below, and we're dealing with
226
     * gc memory referenced by the stack, we need to explicitly
227
     * remove the reference to pstate from the stack, otherwise
228
     * the garbager will fall over
229
     */
230
3.30M
    make_null(osp);
231
    /* Note that gs_scan_token may change osp! */
232
3.30M
    pop(1);
233
3.31M
again:
234
3.31M
    check_estack(1);
235
3.31M
    code = gs_scan_token(i_ctx_p, (ref *) (esp + 1), pstate);
236
3.31M
    op = osp;
237
3.31M
    switch (code) {
238
1.72M
        case 0:
239
1.72M
            if (r_is_proc(esp + 1)) {   /* Treat procedure as a literal. */
240
1.57k
                push(1);
241
1.57k
                ref_assign(op, esp + 1);
242
1.57k
                code = 0;
243
1.57k
                break;
244
1.57k
            }
245
            /* falls through */
246
1.72M
        case scan_BOS:
247
1.72M
            ++esp;
248
1.72M
            code = o_push_estack;
249
1.72M
            break;
250
4.55k
        case scan_EOF:          /* no tokens */
251
4.55k
            code = 0;
252
4.55k
            break;
253
166k
        case scan_Refill:       /* need more data */
254
166k
            ialloc_set_space(idmemory, usevm);
255
166k
            code = gs_scan_handle_refill(i_ctx_p, pstate, save,
256
166k
                                      ztokenexec_continue);
257
166k
            ialloc_set_space(idmemory, currentvm);
258
166k
            switch (code) {
259
3.51k
                case 0: /* state is not copied to the heap */
260
3.51k
                    goto again;
261
162k
                case o_push_estack:
262
162k
                    return code;
263
166k
            }
264
121
            break;              /* error */
265
121
        case scan_Comment:
266
1.41M
        case scan_DSC_Comment:
267
1.41M
            return ztoken_handle_comment(i_ctx_p, pstate, esp + 1, code,
268
1.41M
                                         save, true, ztokenexec_continue);
269
1.35k
        default:                /* error */
270
1.35k
            gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
271
1.35k
            break;
272
3.31M
    }
273
1.72M
    if (!save) {                /* Deallocate the scanner state record. */
274
1.72M
        gs_free_object(((scanner_state_dynamic *)pstate)->mem, pstate, "token_continue");
275
1.72M
    }
276
1.72M
    return code;
277
3.31M
}
278
279
/*
280
 * Handle a scan_Comment or scan_DSC_Comment return from gs_scan_token
281
 * (scan_code) by calling out to %Process[DSC]Comment.  The continuation
282
 * procedure expects the scanner state on the o-stack.
283
 */
284
int
285
ztoken_handle_comment(i_ctx_t *i_ctx_p, scanner_state *sstate,
286
                      const ref *ptoken, int scan_code,
287
                      bool save, bool push_file, op_proc_t cont)
288
1.52M
{
289
1.52M
    const char *proc_name;
290
1.52M
    scanner_state *pstate;
291
1.52M
    os_ptr op;
292
1.52M
    ref *ppcproc;
293
1.52M
    int code;
294
295
1.52M
    switch (scan_code) {
296
0
    case scan_Comment:
297
0
        proc_name = "%ProcessComment";
298
0
        break;
299
1.52M
    case scan_DSC_Comment:
300
1.52M
        proc_name = "%ProcessDSCComment";
301
1.52M
        break;
302
0
    default:
303
0
        return_error(gs_error_Fatal);  /* can't happen */
304
1.52M
    }
305
    /*
306
     * We can't use check_ostack here, because it returns on overflow.
307
     */
308
    /*check_ostack(2);*/
309
1.52M
    if (ostop - osp < 2) {
310
78
        code = ref_stack_extend(&o_stack, 2);
311
78
        if (code < 0)
312
0
            return code;
313
78
    }
314
1.52M
    check_estack(3);
315
1.52M
    code = name_enter_string(imemory, proc_name, esp + 3);
316
1.52M
    if (code < 0)
317
0
        return code;
318
1.52M
    if (save) {
319
104k
        pstate = (scanner_state *)ialloc_struct(scanner_state_dynamic, &st_scanner_state_dynamic,
320
104k
                               "ztoken_handle_comment");
321
104k
        if (pstate == 0)
322
0
            return_error(gs_error_VMerror);
323
104k
        ((scanner_state_dynamic *)pstate)->mem = imemory;
324
104k
        *pstate = *sstate;
325
104k
    } else
326
1.41M
        pstate = sstate;
327
    /* Save the token now -- it might be on the e-stack. */
328
1.52M
    if (!pstate->s_pstack)
329
1.35M
        osp[2] = *ptoken;
330
    /*
331
     * Push the continuation, scanner state, file, and callout procedure
332
     * on the e-stack.
333
     */
334
1.52M
    make_op_estack(esp + 1, cont);
335
1.52M
    make_istruct(esp + 2, 0, pstate);
336
1.52M
    ppcproc = dict_find_name(esp + 3);
337
1.52M
    if (ppcproc == 0) {
338
        /*
339
         * This can only happen during initialization.
340
         * Pop the comment string from the o-stack if needed (see below).
341
         */
342
0
        if (pstate->s_pstack)
343
0
            --osp;
344
0
        esp += 2;               /* do run the continuation */
345
1.52M
    } else {
346
        /*
347
         * Push the file and comment string on the o-stack.
348
         * If we were inside { }, the comment string is already on the stack.
349
         */
350
1.52M
        if (pstate->s_pstack) {
351
164k
            op = ++osp;
352
164k
            *op = op[-1];
353
1.35M
        } else {
354
1.35M
            op = osp += 2;
355
            /* *op = *ptoken; */        /* saved above */
356
1.35M
        }
357
1.52M
        op[-1] = pstate->s_file;
358
1.52M
        esp[3] = *ppcproc;
359
1.52M
        esp += 3;
360
1.52M
    }
361
1.52M
    return o_push_estack;
362
1.52M
}
363
364
typedef struct named_scanner_option_s {
365
    const char *pname;
366
    int option;
367
} named_scanner_option_t;
368
static const named_scanner_option_t named_options[] = {
369
    {"PDFScanRules", SCAN_PDF_RULES},
370
    {"ProcessComment", SCAN_PROCESS_COMMENTS},
371
    {"ProcessDSCComment", SCAN_PROCESS_DSC_COMMENTS},
372
    {"PDFScanInvNum", SCAN_PDF_INV_NUM},
373
    {"PDFScanUnsigned", SCAN_PDF_UNSIGNED}
374
};
375
376
/*
377
 * Update the cached scanner_options in the context state after doing a
378
 * setuserparams.  (We might move this procedure somewhere else eventually.)
379
 */
380
int
381
ztoken_scanner_options(const ref *upref, int old_options)
382
3.94M
{
383
3.94M
    int options = old_options;
384
3.94M
    int i;
385
386
23.6M
    for (i = 0; i < countof(named_options); ++i) {
387
19.7M
        const named_scanner_option_t *pnso = &named_options[i];
388
19.7M
        ref *ppcproc;
389
19.7M
        int code = dict_find_string(upref, pnso->pname, &ppcproc);
390
391
        /* Update the options only if the parameter has changed. */
392
19.7M
        if (code > 0) {
393
1.38M
            if (r_has_type(ppcproc, t_null))
394
203k
                options &= ~pnso->option;
395
1.17M
            else
396
1.17M
                options |= pnso->option;
397
1.38M
        }
398
19.7M
    }
399
3.94M
    return options;
400
3.94M
}
401
/*
402
 * Get the value for a scanner option.
403
 * return -1 if no such option, 1/0 for on/off and option's name in *pname as a C string
404
 */
405
int
406
ztoken_get_scanner_option(const ref *psref, int options, const char **pname)
407
974k
{
408
974k
    const named_scanner_option_t *pnso;
409
410
5.84M
    for (pnso = named_options + countof(named_options); pnso-- != named_options;) {
411
4.87M
        if (!bytes_compare((const byte *)pnso->pname, strlen(pnso->pname),
412
4.87M
                        psref->value.const_bytes, r_size(psref))) {
413
0
            *pname = pnso->pname;
414
0
            return (options & pnso->option ? 1 : 0);
415
0
        }
416
4.87M
    }
417
974k
    return -1;
418
974k
}
419
420
/* ------ Initialization procedure ------ */
421
422
const op_def ztoken_op_defs[] =
423
{
424
    {"1token", ztoken},
425
    {"1.tokenexec", ztokenexec},
426
                /* Internal operators */
427
    {"2%ztoken_continue", ztoken_continue},
428
    {"2%ztokenexec_continue", ztokenexec_continue},
429
    op_def_end(0)
430
};