Coverage Report

Created: 2025-06-10 06:56

/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
537k
{
44
537k
    os_ptr op = osp;
45
46
537k
    check_op(1);
47
537k
    switch (r_type(op)) {
48
0
        default:
49
0
            return_op_typecheck(op);
50
537k
        case t_file: {
51
537k
            stream *s;
52
537k
            scanner_state state;
53
54
537k
            check_read_file(i_ctx_p, s, op);
55
537k
            check_ostack(1);
56
537k
            gs_scanner_init(&state, op);
57
537k
            return token_continue(i_ctx_p, &state, true);
58
537k
        }
59
0
        case t_string: {
60
0
            ref token;
61
            /* -1 is to remove the string operand in case of error. */
62
0
            int orig_ostack_depth = ref_stack_count(&o_stack) - 1;
63
0
            int code;
64
65
            /* Don't pop the operand in case of invalidaccess. */
66
0
            if (!r_has_attr(op, a_read))
67
0
                return_error(gs_error_invalidaccess);
68
0
            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
0
            op = osp;
74
0
            switch (code) {
75
0
            case scan_EOF:      /* no tokens */
76
0
                make_false(op);
77
0
                return 0;
78
0
            default:
79
0
                if (code < 0) {
80
                    /*
81
                     * Clear anything that may have been left on the ostack,
82
                     * including the string operand.
83
                     */
84
0
                    if (orig_ostack_depth < ref_stack_count(&o_stack))
85
0
                        pop(ref_stack_count(&o_stack)- orig_ostack_depth);
86
0
                    return code;
87
0
                }
88
0
            }
89
0
            push(2);
90
0
            op[-1] = token;
91
0
            make_true(op);
92
0
            return 0;
93
0
        }
94
537k
    }
95
537k
}
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
537k
{
113
537k
    os_ptr op = osp;
114
537k
    int code;
115
537k
    ref token;
116
537k
    avm_space usevm, currentvm = ialloc_space(idmemory);
117
537k
    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
537k
    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
537k
    make_null(osp);
131
    /* Note that gs_scan_token may change osp! */
132
537k
    pop(1);                     /* remove the file or scanner state */
133
537k
again:
134
537k
    code = gs_scan_token(i_ctx_p, &token, pstate);
135
537k
    op = osp;
136
537k
    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
533k
        case 0:         /* read a token */
146
533k
            push(2);
147
533k
            ref_assign(op - 1, &token);
148
533k
            make_true(op);
149
533k
            break;
150
3.56k
        case scan_EOF:          /* no tokens */
151
3.56k
            push(1);
152
3.56k
            make_false(op);
153
3.56k
            code = 0;
154
3.56k
            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
537k
    }
168
537k
    if (code <= 0 && !save) {   /* Deallocate the scanner state record. */
169
0
        ifree_object(pstate, "token_continue");
170
0
    }
171
537k
    if (code < 0)
172
537k
        make_op_estack(esp + 1, ztoken);
173
537k
    return code;
174
537k
}
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
26.4k
{
202
26.4k
    os_ptr op = osp;
203
26.4k
    scanner_state *pstate;
204
205
26.4k
    check_op(1);
206
26.4k
    check_stype(*op, st_scanner_state_dynamic);
207
26.4k
    pstate = r_ptr(op, scanner_state);
208
26.4k
    return tokenexec_continue(i_ctx_p, pstate, false);
209
26.4k
}
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
26.4k
{
214
26.4k
    os_ptr op = osp;
215
26.4k
    int code;
216
26.4k
    avm_space usevm, currentvm = ialloc_space(idmemory);
217
26.4k
    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
26.4k
    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
26.4k
    make_null(osp);
231
    /* Note that gs_scan_token may change osp! */
232
26.4k
    pop(1);
233
26.6k
again:
234
26.6k
    check_estack(1);
235
26.6k
    code = gs_scan_token(i_ctx_p, (ref *) (esp + 1), pstate);
236
26.6k
    op = osp;
237
26.6k
    switch (code) {
238
17.8k
        case 0:
239
17.8k
            if (r_is_proc(esp + 1)) {   /* Treat procedure as a literal. */
240
8
                push(1);
241
8
                ref_assign(op, esp + 1);
242
8
                code = 0;
243
8
                break;
244
8
            }
245
            /* falls through */
246
17.8k
        case scan_BOS:
247
17.8k
            ++esp;
248
17.8k
            code = o_push_estack;
249
17.8k
            break;
250
0
        case scan_EOF:          /* no tokens */
251
0
            code = 0;
252
0
            break;
253
1.96k
        case scan_Refill:       /* need more data */
254
1.96k
            ialloc_set_space(idmemory, usevm);
255
1.96k
            code = gs_scan_handle_refill(i_ctx_p, pstate, save,
256
1.96k
                                      ztokenexec_continue);
257
1.96k
            ialloc_set_space(idmemory, currentvm);
258
1.96k
            switch (code) {
259
179
                case 0: /* state is not copied to the heap */
260
179
                    goto again;
261
1.78k
                case o_push_estack:
262
1.78k
                    return code;
263
1.96k
            }
264
3
            break;              /* error */
265
3
        case scan_Comment:
266
6.79k
        case scan_DSC_Comment:
267
6.79k
            return ztoken_handle_comment(i_ctx_p, pstate, esp + 1, code,
268
6.79k
                                         save, true, ztokenexec_continue);
269
10
        default:                /* error */
270
10
            gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
271
10
            break;
272
26.6k
    }
273
17.9k
    if (!save) {                /* Deallocate the scanner state record. */
274
17.9k
        gs_free_object(((scanner_state_dynamic *)pstate)->mem, pstate, "token_continue");
275
17.9k
    }
276
17.9k
    return code;
277
26.6k
}
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
6.85k
{
289
6.85k
    const char *proc_name;
290
6.85k
    scanner_state *pstate;
291
6.85k
    os_ptr op;
292
6.85k
    ref *ppcproc;
293
6.85k
    int code;
294
295
6.85k
    switch (scan_code) {
296
0
    case scan_Comment:
297
0
        proc_name = "%ProcessComment";
298
0
        break;
299
6.85k
    case scan_DSC_Comment:
300
6.85k
        proc_name = "%ProcessDSCComment";
301
6.85k
        break;
302
0
    default:
303
0
        return_error(gs_error_Fatal);  /* can't happen */
304
6.85k
    }
305
    /*
306
     * We can't use check_ostack here, because it returns on overflow.
307
     */
308
    /*check_ostack(2);*/
309
6.85k
    if (ostop - osp < 2) {
310
0
        code = ref_stack_extend(&o_stack, 2);
311
0
        if (code < 0)
312
0
            return code;
313
0
    }
314
6.85k
    check_estack(3);
315
6.85k
    code = name_enter_string(imemory, proc_name, esp + 3);
316
6.85k
    if (code < 0)
317
0
        return code;
318
6.85k
    if (save) {
319
61
        pstate = (scanner_state *)ialloc_struct(scanner_state_dynamic, &st_scanner_state_dynamic,
320
61
                               "ztoken_handle_comment");
321
61
        if (pstate == 0)
322
0
            return_error(gs_error_VMerror);
323
61
        ((scanner_state_dynamic *)pstate)->mem = imemory;
324
61
        *pstate = *sstate;
325
61
    } else
326
6.79k
        pstate = sstate;
327
    /* Save the token now -- it might be on the e-stack. */
328
6.85k
    if (!pstate->s_pstack)
329
128
        osp[2] = *ptoken;
330
    /*
331
     * Push the continuation, scanner state, file, and callout procedure
332
     * on the e-stack.
333
     */
334
6.85k
    make_op_estack(esp + 1, cont);
335
6.85k
    make_istruct(esp + 2, 0, pstate);
336
6.85k
    ppcproc = dict_find_name(esp + 3);
337
6.85k
    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
6.85k
    } 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
6.85k
        if (pstate->s_pstack) {
351
6.72k
            op = ++osp;
352
6.72k
            *op = op[-1];
353
6.72k
        } else {
354
128
            op = osp += 2;
355
            /* *op = *ptoken; */        /* saved above */
356
128
        }
357
6.85k
        op[-1] = pstate->s_file;
358
6.85k
        esp[3] = *ppcproc;
359
6.85k
        esp += 3;
360
6.85k
    }
361
6.85k
    return o_push_estack;
362
6.85k
}
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
44.2k
{
383
44.2k
    int options = old_options;
384
44.2k
    int i;
385
386
265k
    for (i = 0; i < countof(named_options); ++i) {
387
221k
        const named_scanner_option_t *pnso = &named_options[i];
388
221k
        ref *ppcproc;
389
221k
        int code = dict_find_string(upref, pnso->pname, &ppcproc);
390
391
        /* Update the options only if the parameter has changed. */
392
221k
        if (code > 0) {
393
17.2k
            if (r_has_type(ppcproc, t_null))
394
3.26k
                options &= ~pnso->option;
395
13.9k
            else
396
13.9k
                options |= pnso->option;
397
17.2k
        }
398
221k
    }
399
44.2k
    return options;
400
44.2k
}
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
10.7k
{
408
10.7k
    const named_scanner_option_t *pnso;
409
410
64.2k
    for (pnso = named_options + countof(named_options); pnso-- != named_options;) {
411
53.5k
        if (!bytes_compare((const byte *)pnso->pname, strlen(pnso->pname),
412
53.5k
                        psref->value.const_bytes, r_size(psref))) {
413
0
            *pname = pnso->pname;
414
0
            return (options & pnso->option ? 1 : 0);
415
0
        }
416
53.5k
    }
417
10.7k
    return -1;
418
10.7k
}
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
};