Coverage Report

Created: 2022-04-16 11:23

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