1 /* Copyright (C) 2001-2019 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
ztoken(i_ctx_t * i_ctx_p)42 ztoken(i_ctx_t *i_ctx_p)
43 {
44 os_ptr op = osp;
45
46 switch (r_type(op)) {
47 default:
48 return_op_typecheck(op);
49 case t_file: {
50 stream *s;
51 scanner_state state;
52
53 check_read_file(i_ctx_p, s, op);
54 check_ostack(1);
55 gs_scanner_init(&state, op);
56 return token_continue(i_ctx_p, &state, true);
57 }
58 case t_string: {
59 ref token;
60 /* -1 is to remove the string operand in case of error. */
61 int orig_ostack_depth = ref_stack_count(&o_stack) - 1;
62 int code;
63
64 /* Don't pop the operand in case of invalidaccess. */
65 if (!r_has_attr(op, a_read))
66 return_error(gs_error_invalidaccess);
67 code = gs_scan_string_token(i_ctx_p, op, &token);
68 switch (code) {
69 case scan_EOF: /* no tokens */
70 make_false(op);
71 return 0;
72 default:
73 if (code < 0) {
74 /*
75 * Clear anything that may have been left on the ostack,
76 * including the string operand.
77 */
78 if (orig_ostack_depth < ref_stack_count(&o_stack))
79 pop(ref_stack_count(&o_stack)- orig_ostack_depth);
80 return code;
81 }
82 }
83 push(2);
84 op[-1] = token;
85 make_true(op);
86 return 0;
87 }
88 }
89 }
90 /* Continue reading a token after an interrupt or callout. */
91 /* *op is the scanner state. */
92 static int
ztoken_continue(i_ctx_t * i_ctx_p)93 ztoken_continue(i_ctx_t *i_ctx_p)
94 {
95 os_ptr op = osp;
96 scanner_state *pstate;
97
98 check_stype(*op, st_scanner_state_dynamic);
99 pstate = r_ptr(op, scanner_state);
100 return token_continue(i_ctx_p, pstate, false);
101 }
102 /* Common code for token reading. */
103 static int
token_continue(i_ctx_t * i_ctx_p,scanner_state * pstate,bool save)104 token_continue(i_ctx_t *i_ctx_p, scanner_state * pstate, bool save)
105 {
106 os_ptr op = osp;
107 int code;
108 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 make_null(osp);
116 /* Note that gs_scan_token may change osp! */
117 pop(1); /* remove the file or scanner state */
118 again:
119 code = gs_scan_token(i_ctx_p, &token, pstate);
120 op = osp;
121 switch (code) {
122 default: /* error */
123 if (code > 0) /* comment, not possible */
124 code = gs_note_error(gs_error_syntaxerror);
125 gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
126 make_op_estack(esp + 1, ztoken);
127 break;
128 case scan_BOS:
129 code = 0;
130 case 0: /* read a token */
131 push(2);
132 ref_assign(op - 1, &token);
133 make_true(op);
134 break;
135 case scan_EOF: /* no tokens */
136 push(1);
137 make_false(op);
138 code = 0;
139 break;
140 case scan_Refill: /* need more data */
141 code = gs_scan_handle_refill(i_ctx_p, pstate, save,
142 ztoken_continue);
143 switch (code) {
144 case 0: /* state is not copied to the heap */
145 goto again;
146 case o_push_estack:
147 return code;
148 }
149 break; /* error */
150 }
151 if (code <= 0 && !save) { /* Deallocate the scanner state record. */
152 ifree_object(pstate, "token_continue");
153 }
154 if (code < 0)
155 make_op_estack(esp + 1, ztoken);
156 return code;
157 }
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
ztokenexec(i_ctx_t * i_ctx_p)166 ztokenexec(i_ctx_t *i_ctx_p)
167 {
168 os_ptr op = osp;
169 stream *s;
170 scanner_state state;
171
172 check_read_file(i_ctx_p, s, op);
173 check_estack(1);
174 gs_scanner_init(&state, op);
175 return tokenexec_continue(i_ctx_p, &state, true);
176 }
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
ztokenexec_continue(i_ctx_t * i_ctx_p)182 ztokenexec_continue(i_ctx_t *i_ctx_p)
183 {
184 os_ptr op = osp;
185 scanner_state *pstate;
186
187 check_stype(*op, st_scanner_state_dynamic);
188 pstate = r_ptr(op, scanner_state);
189 return tokenexec_continue(i_ctx_p, pstate, false);
190 }
191 /* Common code for token reading + execution. */
192 static int
tokenexec_continue(i_ctx_t * i_ctx_p,scanner_state * pstate,bool save)193 tokenexec_continue(i_ctx_t *i_ctx_p, scanner_state * pstate, bool save)
194 {
195 os_ptr op = osp;
196 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 make_null(osp);
203 /* Note that gs_scan_token may change osp! */
204 pop(1);
205 again:
206 check_estack(1);
207 code = gs_scan_token(i_ctx_p, (ref *) (esp + 1), pstate);
208 op = osp;
209 switch (code) {
210 case 0:
211 if (r_is_proc(esp + 1)) { /* Treat procedure as a literal. */
212 push(1);
213 ref_assign(op, esp + 1);
214 code = 0;
215 break;
216 }
217 /* falls through */
218 case scan_BOS:
219 ++esp;
220 code = o_push_estack;
221 break;
222 case scan_EOF: /* no tokens */
223 code = 0;
224 break;
225 case scan_Refill: /* need more data */
226 code = gs_scan_handle_refill(i_ctx_p, pstate, save,
227 ztokenexec_continue);
228 switch (code) {
229 case 0: /* state is not copied to the heap */
230 goto again;
231 case o_push_estack:
232 return code;
233 }
234 break; /* error */
235 case scan_Comment:
236 case scan_DSC_Comment:
237 return ztoken_handle_comment(i_ctx_p, pstate, esp + 1, code,
238 save, true, ztokenexec_continue);
239 default: /* error */
240 gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
241 break;
242 }
243 if (!save) { /* Deallocate the scanner state record. */
244 gs_free_object(((scanner_state_dynamic *)pstate)->mem, pstate, "token_continue");
245 }
246 return code;
247 }
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
ztoken_handle_comment(i_ctx_t * i_ctx_p,scanner_state * sstate,const ref * ptoken,int scan_code,bool save,bool push_file,op_proc_t cont)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 {
259 const char *proc_name;
260 scanner_state *pstate;
261 os_ptr op;
262 ref *ppcproc;
263 int code;
264
265 switch (scan_code) {
266 case scan_Comment:
267 proc_name = "%ProcessComment";
268 break;
269 case scan_DSC_Comment:
270 proc_name = "%ProcessDSCComment";
271 break;
272 default:
273 return_error(gs_error_Fatal); /* can't happen */
274 }
275 /*
276 * We can't use check_ostack here, because it returns on overflow.
277 */
278 /*check_ostack(2);*/
279 if (ostop - osp < 2) {
280 code = ref_stack_extend(&o_stack, 2);
281 if (code < 0)
282 return code;
283 }
284 check_estack(3);
285 code = name_enter_string(imemory, proc_name, esp + 3);
286 if (code < 0)
287 return code;
288 if (save) {
289 pstate = (scanner_state *)ialloc_struct(scanner_state_dynamic, &st_scanner_state_dynamic,
290 "ztoken_handle_comment");
291 if (pstate == 0)
292 return_error(gs_error_VMerror);
293 ((scanner_state_dynamic *)pstate)->mem = imemory;
294 *pstate = *sstate;
295 } else
296 pstate = sstate;
297 /* Save the token now -- it might be on the e-stack. */
298 if (!pstate->s_pstack)
299 osp[2] = *ptoken;
300 /*
301 * Push the continuation, scanner state, file, and callout procedure
302 * on the e-stack.
303 */
304 make_op_estack(esp + 1, cont);
305 make_istruct(esp + 2, 0, pstate);
306 ppcproc = dict_find_name(esp + 3);
307 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 if (pstate->s_pstack)
313 --osp;
314 esp += 2; /* do run the continuation */
315 } 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 if (pstate->s_pstack) {
321 op = ++osp;
322 *op = op[-1];
323 } else {
324 op = osp += 2;
325 /* *op = *ptoken; */ /* saved above */
326 }
327 op[-1] = pstate->s_file;
328 esp[3] = *ppcproc;
329 esp += 3;
330 }
331 return o_push_estack;
332 }
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
ztoken_scanner_options(const ref * upref,int old_options)351 ztoken_scanner_options(const ref *upref, int old_options)
352 {
353 int options = old_options;
354 int i;
355
356 for (i = 0; i < countof(named_options); ++i) {
357 const named_scanner_option_t *pnso = &named_options[i];
358 ref *ppcproc;
359 int code = dict_find_string(upref, pnso->pname, &ppcproc);
360
361 /* Update the options only if the parameter has changed. */
362 if (code > 0) {
363 if (r_has_type(ppcproc, t_null))
364 options &= ~pnso->option;
365 else
366 options |= pnso->option;
367 }
368 }
369 return options;
370 }
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
ztoken_get_scanner_option(const ref * psref,int options,const char ** pname)376 ztoken_get_scanner_option(const ref *psref, int options, const char **pname)
377 {
378 const named_scanner_option_t *pnso;
379
380 for (pnso = named_options + countof(named_options); pnso-- != named_options;) {
381 if (!bytes_compare((const byte *)pnso->pname, strlen(pnso->pname),
382 psref->value.const_bytes, r_size(psref))) {
383 *pname = pnso->pname;
384 return (options & pnso->option ? 1 : 0);
385 }
386 }
387 return -1;
388 }
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 };
401