Coverage Report

Created: 2025-06-10 07:27

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