xref: /plan9/sys/src/cmd/gs/src/iscan.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: iscan.c,v 1.20 2005/04/25 12:28:49 igor Exp $ */
18 /* Token scanner for Ghostscript interpreter */
19 #include "ghost.h"
20 #include "memory_.h"
21 #include "stream.h"
22 #include "ierrors.h"
23 #include "btoken.h"		/* for ref_binary_object_format */
24 #include "files.h"		/* for fptr */
25 #include "ialloc.h"
26 #include "idict.h"		/* for //name lookup */
27 #include "dstack.h"		/* ditto */
28 #include "ilevel.h"
29 #include "iname.h"
30 #include "ipacked.h"
31 #include "iparray.h"
32 #include "strimpl.h"		/* for string decoding */
33 #include "sa85d.h"		/* ditto */
34 #include "sfilter.h"		/* ditto */
35 #include "ostack.h"		/* for accumulating proc bodies; */
36 					/* must precede iscan.h */
37 #include "iscan.h"		/* defines interface */
38 #include "iscanbin.h"
39 #include "iscannum.h"
40 #include "istream.h"
41 #include "istruct.h"		/* for RELOC_REF_VAR */
42 #include "iutil.h"
43 #include "ivmspace.h"
44 #include "store.h"
45 #include "scanchar.h"
46 
47 #define recognize_btokens()\
48   (ref_binary_object_format.value.intval != 0 && level2_enabled)
49 
50 /* Procedure for handling DSC comments if desired. */
51 /* Set at initialization if a DSC handling module is included. */
52 int (*scan_dsc_proc) (const byte *, uint) = NULL;
53 
54 /* Procedure for handling all comments if desired. */
55 /* Set at initialization if a comment handling module is included. */
56 /* If both scan_comment_proc and scan_dsc_proc are set, */
57 /* scan_comment_proc is called only for non-DSC comments. */
58 int (*scan_comment_proc) (const byte *, uint) = NULL;
59 
60 /*
61  * Level 2 includes some changes in the scanner:
62  *      - \ is always recognized in strings, regardless of the data source;
63  *      - << and >> are legal tokens;
64  *      - <~ introduces an ASCII85 encoded string (terminated by ~>);
65  *      - Character codes above 127 introduce binary objects.
66  * We explicitly enable or disable these changes here.
67  */
68 #define scan_enable_level2 level2_enabled	/* from ilevel.h */
69 
70 /* ------ Dynamic strings ------ */
71 
72 /* Begin collecting a dynamically allocated string. */
73 inline private void
dynamic_init(da_ptr pda,gs_memory_t * mem)74 dynamic_init(da_ptr pda, gs_memory_t *mem)
75 {
76     pda->is_dynamic = false;
77     pda->limit = pda->buf + da_buf_size;
78     pda->next = pda->base = pda->buf;
79     pda->memory = mem;
80 }
81 
82 /* Free a dynamic string. */
83 private void
dynamic_free(da_ptr pda)84 dynamic_free(da_ptr pda)
85 {
86     if (pda->is_dynamic)
87 	gs_free_string(pda->memory, pda->base, da_size(pda), "scanner");
88 }
89 
90 /* Resize a dynamic string. */
91 /* If the allocation fails, return e_VMerror; otherwise, return 0. */
92 private int
dynamic_resize(da_ptr pda,uint new_size)93 dynamic_resize(da_ptr pda, uint new_size)
94 {
95     uint old_size = da_size(pda);
96     uint pos = pda->next - pda->base;
97     gs_memory_t *mem = pda->memory;
98     byte *base;
99 
100     if (pda->is_dynamic) {
101 	base = gs_resize_string(mem, pda->base, old_size,
102 				new_size, "scanner");
103 	if (base == 0)
104 	    return_error(e_VMerror);
105     } else {			/* switching from static to dynamic */
106 	base = gs_alloc_string(mem, new_size, "scanner");
107 	if (base == 0)
108 	    return_error(e_VMerror);
109 	memcpy(base, pda->base, min(old_size, new_size));
110 	pda->is_dynamic = true;
111     }
112     pda->base = base;
113     pda->next = base + pos;
114     pda->limit = base + new_size;
115     return 0;
116 }
117 
118 /* Grow a dynamic string. */
119 /* Return 0 if the allocation failed, the new 'next' ptr if OK. */
120 /* Return 0 or an error code, updating pda->next to point to the first */
121 /* available byte after growing. */
122 private int
dynamic_grow(da_ptr pda,byte * next,uint max_size)123 dynamic_grow(da_ptr pda, byte * next, uint max_size)
124 {
125     uint old_size = da_size(pda);
126     uint new_size = (old_size < 10 ? 20 :
127 		     old_size >= (max_size >> 1) ? max_size :
128 		     old_size << 1);
129     int code;
130 
131     pda->next = next;
132     if (old_size == max_size)
133 	return_error(e_limitcheck);
134     while ((code = dynamic_resize(pda, new_size)) < 0 &&
135 	   new_size > old_size
136 	) {			/* Try trimming down the requested new size. */
137 	new_size -= (new_size - old_size + 1) >> 1;
138     }
139     return code;
140 }
141 
142 /* Ensure that a dynamic string is either on the heap or in the */
143 /* private buffer. */
144 private void
dynamic_save(da_ptr pda)145 dynamic_save(da_ptr pda)
146 {
147     if (!pda->is_dynamic && pda->base != pda->buf) {
148 	memcpy(pda->buf, pda->base, da_size(pda));
149 	pda->next = pda->buf + da_size(pda);
150 	pda->base = pda->buf;
151     }
152 }
153 
154 /* Finish collecting a dynamic string. */
155 private int
dynamic_make_string(i_ctx_t * i_ctx_p,ref * pref,da_ptr pda,byte * next)156 dynamic_make_string(i_ctx_t *i_ctx_p, ref * pref, da_ptr pda, byte * next)
157 {
158     uint size = (pda->next = next) - pda->base;
159     int code = dynamic_resize(pda, size);
160 
161     if (code < 0)
162 	return code;
163     make_tasv_new(pref, t_string,
164 		  a_all | imemory_space((gs_ref_memory_t *) pda->memory),
165 		  size, bytes, pda->base);
166     return 0;
167 }
168 
169 /* ------ Main scanner ------ */
170 
171 /* GC procedures */
172 #define ssarray ssptr->s_ss.binary.bin_array
173 private
CLEAR_MARKS_PROC(scanner_clear_marks)174 CLEAR_MARKS_PROC(scanner_clear_marks)
175 {
176     scanner_state *const ssptr = vptr;
177 
178     r_clear_attrs(&ssarray, l_mark);
179 }
180 private
181 ENUM_PTRS_WITH(scanner_enum_ptrs, scanner_state *ssptr) return 0;
182 case 0:
183     if (ssptr->s_scan_type == scanning_none ||
184 	!ssptr->s_da.is_dynamic
185 	)
186 	ENUM_RETURN(0);
187     return ENUM_STRING2(ssptr->s_da.base, da_size(&ssptr->s_da));
188 case 1:
189     if (ssptr->s_scan_type != scanning_binary)
190 	return 0;
191     ENUM_RETURN_REF(&ssarray);
192 ENUM_PTRS_END
RELOC_PTRS_WITH(scanner_reloc_ptrs,scanner_state * ssptr)193 private RELOC_PTRS_WITH(scanner_reloc_ptrs, scanner_state *ssptr)
194 {
195     if (ssptr->s_scan_type != scanning_none && ssptr->s_da.is_dynamic) {
196 	gs_string sda;
197 
198 	sda.data = ssptr->s_da.base;
199 	sda.size = da_size(&ssptr->s_da);
200 	RELOC_STRING_VAR(sda);
201 	ssptr->s_da.limit = sda.data + sda.size;
202 	ssptr->s_da.next = sda.data + (ssptr->s_da.next - ssptr->s_da.base);
203 	ssptr->s_da.base = sda.data;
204     }
205     if (ssptr->s_scan_type == scanning_binary) {
206 	RELOC_REF_VAR(ssarray);
207 	r_clear_attrs(&ssarray, l_mark);
208     }
209 }
210 RELOC_PTRS_END
211 /* Structure type */
212 public_st_scanner_state();
213 
214 /* Initialize a scanner. */
215 void
scanner_state_init_options(scanner_state * sstate,int options)216 scanner_state_init_options(scanner_state *sstate, int options)
217 {
218     sstate->s_scan_type = scanning_none;
219     sstate->s_pstack = 0;
220     sstate->s_options = options;
221 }
222 
223 /* Handle a scan_Refill return from scan_token. */
224 /* This may return o_push_estack, 0 (meaning just call scan_token again), */
225 /* or an error code. */
226 int
scan_handle_refill(i_ctx_t * i_ctx_p,const ref * fop,scanner_state * sstate,bool save,bool push_file,op_proc_t cont)227 scan_handle_refill(i_ctx_t *i_ctx_p, const ref * fop, scanner_state * sstate,
228 		   bool save, bool push_file, op_proc_t cont)
229 {
230     stream *s = fptr(fop);
231     uint avail = sbufavailable(s);
232     int status;
233 
234     if (s->end_status == EOFC) {
235 	/* More data needed, but none available, so this is a syntax error. */
236 	return_error(e_syntaxerror);
237     }
238     status = s_process_read_buf(s);
239     if (sbufavailable(s) > avail)
240 	return 0;
241     if (status == 0)
242 	status = s->end_status;
243     switch (status) {
244 	case EOFC:
245 	    /* We just discovered that we're at EOF. */
246 	    /* Let the caller find this out. */
247 	    return 0;
248 	case ERRC:
249 	    return_error(e_ioerror);
250 	case INTC:
251 	case CALLC:
252 	    {
253 		ref rstate[2];
254 		scanner_state *pstate;
255 		int nstate = (push_file ? 2 : 1);
256 
257 		if (save) {
258 		    pstate =
259 			ialloc_struct(scanner_state, &st_scanner_state,
260 				      "scan_handle_refill");
261 		    if (pstate == 0)
262 			return_error(e_VMerror);
263 		    *pstate = *sstate;
264 		} else
265 		    pstate = sstate;
266 		/* If push_file is true, we want to push the file on the */
267 		/* o-stack before the state, for the continuation proc. */
268 		/* Since the refs passed to s_handle_read_exception */
269 		/* are pushed on the e-stack, we must ensure they are */
270 		/* literal, and also pass them in the opposite order! */
271 		make_istruct(&rstate[0], 0, pstate);
272 		rstate[1] = *fop;
273 		r_clear_attrs(&rstate[1], a_executable);
274 		return s_handle_read_exception(i_ctx_p, status, fop,
275 					       rstate, nstate, cont);
276 	    }
277     }
278     /* No more data available, but no exception.  How can this be? */
279     lprintf("Can't refill scanner input buffer!");
280     return_error(e_Fatal);
281 }
282 
283 /*
284  * Handle a comment.  The 'saved' argument is needed only for
285  * tracing printout.
286  */
287 private int
scan_comment(i_ctx_t * i_ctx_p,ref * pref,scanner_state * pstate,const byte * base,const byte * end,bool saved)288 scan_comment(i_ctx_t *i_ctx_p, ref *pref, scanner_state *pstate,
289 	     const byte * base, const byte * end, bool saved)
290 {
291     uint len = (uint) (end - base);
292     int code;
293 #ifdef DEBUG
294     const char *sstr = (saved ? ">" : "");
295 #endif
296 
297     if (len > 1 && (base[1] == '%' || base[1] == '!')) {
298 	/* Process as a DSC comment if requested. */
299 #ifdef DEBUG
300 	if (gs_debug_c('%')) {
301 	    dlprintf2("[%%%%%s%c]", sstr, (len >= 3 ? '+' : '-'));
302 	    debug_print_string(base, len);
303 	    dputs("\n");
304 	}
305 #endif
306 	if (scan_dsc_proc != NULL) {
307 	    code = scan_dsc_proc(base, len);
308 	    return (code < 0 ? code : 0);
309 	}
310 	if (pstate->s_options & SCAN_PROCESS_DSC_COMMENTS) {
311 	    code = scan_DSC_Comment;
312 	    goto comment;
313 	}
314 	/* Treat as an ordinary comment. */
315     }
316 #ifdef DEBUG
317     else {
318 	if (gs_debug_c('%')) {
319 	    dlprintf2("[%% %s%c]", sstr, (len >= 2 ? '+' : '-'));
320 	    debug_print_string(base, len);
321 	    dputs("\n");
322 	}
323     }
324 #endif
325     if (scan_comment_proc != NULL) {
326 	code = scan_comment_proc(base, len);
327 	return (code < 0 ? code : 0);
328     }
329     if (pstate->s_options & SCAN_PROCESS_COMMENTS) {
330 	code = scan_Comment;
331 	goto comment;
332     }
333     return 0;
334  comment:
335     {
336 	byte *cstr = ialloc_string(len, "scan_comment");
337 
338 	if (cstr == 0)
339 	    return_error(e_VMerror);
340 	memcpy(cstr, base, len);
341 	make_string(pref, a_all | icurrent_space, len, cstr);
342     }
343     return code;
344 }
345 
346 /* Read a token from a string. */
347 /* Update the string if succesful. */
348 int
scan_string_token_options(i_ctx_t * i_ctx_p,ref * pstr,ref * pref,int options)349 scan_string_token_options(i_ctx_t *i_ctx_p, ref * pstr, ref * pref,
350 			  int options)
351 {
352     stream st;
353     stream *s = &st;
354     scanner_state state;
355     int code;
356 
357     if (!r_has_attr(pstr, a_read))
358 	return_error(e_invalidaccess);
359     s_init(s, NULL);
360     sread_string(s, pstr->value.bytes, r_size(pstr));
361     scanner_state_init_options(&state, options | SCAN_FROM_STRING);
362     switch (code = scan_token(i_ctx_p, s, pref, &state)) {
363 	default:		/* error or comment */
364 	    if (code < 0)
365 		break;
366 	    /* falls through */
367 	case 0:		/* read a token */
368 	case scan_BOS:
369 	    {
370 		uint pos = stell(s);
371 
372 		pstr->value.bytes += pos;
373 		r_dec_size(pstr, pos);
374 	    }
375 	    break;
376 	case scan_Refill:	/* error */
377 	    code = gs_note_error(e_syntaxerror);
378 	case scan_EOF:
379 	    break;
380     }
381     return code;
382 }
383 
384 /*
385  * Read a token from a stream.  Return 0 if an ordinary token was read,
386  * >0 for special situations (see iscan.h).
387  * If the token required a terminating character (i.e., was a name or
388  * number) and the next character was whitespace, read and discard
389  * that character.  Note that the state is relevant for e_VMerror
390  * as well as for scan_Refill.
391  */
392 int
scan_token(i_ctx_t * i_ctx_p,stream * s,ref * pref,scanner_state * pstate)393 scan_token(i_ctx_t *i_ctx_p, stream * s, ref * pref, scanner_state * pstate)
394 {
395     ref *myref = pref;
396     int retcode = 0;
397     int c;
398 
399     s_declare_inline(s, sptr, endptr);
400 #define scan_begin_inline() s_begin_inline(s, sptr, endptr)
401 #define scan_getc() sgetc_inline(s, sptr, endptr)
402 #define scan_putback() sputback_inline(s, sptr, endptr)
403 #define scan_end_inline() s_end_inline(s, sptr, endptr)
404     const byte *newptr;
405     byte *daptr;
406 
407 #define sreturn(code)\
408   { retcode = gs_note_error(code); goto sret; }
409 #define sreturn_no_error(code)\
410   { scan_end_inline(); return(code); }
411 #define if_not_spush1()\
412   if ( osp < ostop ) osp++;\
413   else if ( (retcode = ref_stack_push(&o_stack, 1)) >= 0 )\
414     ;\
415   else
416 #define spop1()\
417   if ( osp >= osbot ) osp--;\
418   else ref_stack_pop(&o_stack, 1)
419     int max_name_ctype =
420     (recognize_btokens()? ctype_name : ctype_btoken);
421 
422 #define scan_sign(sign, ptr)\
423   switch ( *ptr ) {\
424     case '-': sign = -1; ptr++; break;\
425     case '+': sign = 1; ptr++; break;\
426     default: sign = 0;\
427   }
428 #define ensure2_back(styp,nback)\
429   if ( sptr >= endptr ) { sptr -= nback; scan_type = styp; goto pause; }
430 #define ensure2(styp) ensure2_back(styp, 1)
431     byte s1[2];
432     const byte *const decoder = scan_char_decoder;
433     int status;
434     int sign;
435     const bool check_only = (pstate->s_options & SCAN_CHECK_ONLY) != 0;
436     const bool PDFScanRules = (i_ctx_p->scanner_options & SCAN_PDF_RULES) != 0;
437     const bool PDFScanInvNum = (i_ctx_p->scanner_options & SCAN_PDF_INV_NUM) != 0;
438     scanner_state sstate;
439 
440 #define pstack sstate.s_pstack
441 #define pdepth sstate.s_pdepth
442 #define scan_type sstate.s_scan_type
443 #define da sstate.s_da
444 #define name_type sstate.s_ss.s_name.s_name_type
445 #define try_number sstate.s_ss.s_name.s_try_number
446 
447     sptr = endptr = NULL; /* Quiet compiler */
448     if (pstate->s_pstack != 0) {
449 	if_not_spush1()
450 	    return retcode;
451 	myref = osp;
452     }
453     /* Check whether we are resuming after an interruption. */
454     if (pstate->s_scan_type != scanning_none) {
455 	sstate = *pstate;
456 	if (!da.is_dynamic && da.base != da.buf) {
457 	    /* The da contains some self-referencing pointers. */
458 	    /* Fix them up now. */
459 	    uint next = da.next - da.base;
460 	    uint limit = da.limit - da.base;
461 
462 	    da.base = da.buf;
463 	    da.next = da.buf + next;
464 	    da.limit = da.buf + limit;
465 	}
466 	daptr = da.next;
467 	switch (scan_type) {
468 	    case scanning_binary:
469 		retcode = (*sstate.s_ss.binary.cont)
470 		    (i_ctx_p, s, myref, &sstate);
471 		scan_begin_inline();
472 		if (retcode == scan_Refill)
473 		    goto pause;
474 		goto sret;
475 	    case scanning_comment:
476 		scan_begin_inline();
477 		goto cont_comment;
478 	    case scanning_name:
479 		goto cont_name;
480 	    case scanning_string:
481 		goto cont_string;
482 	    default:
483 		return_error(e_Fatal);
484 	}
485     }
486     /* Fetch any state variables that are relevant even if */
487     /* scan_type == scanning_none. */
488     pstack = pstate->s_pstack;
489     pdepth = pstate->s_pdepth;
490     sstate.s_options = pstate->s_options;
491     scan_begin_inline();
492     /*
493      * Loop invariants:
494      *      If pstack != 0, myref = osp, and *osp is a valid slot.
495      */
496   top:c = scan_getc();
497     if_debug1('S', (c >= 32 && c <= 126 ? "`%c'" : c >= 0 ? "`\\%03o'" : "`%d'"), c);
498     switch (c) {
499 	case ' ':
500 	case '\f':
501 	case '\t':
502 	case char_CR:
503 	case char_EOL:
504 	case char_NULL:
505 	    goto top;
506         case 0x4:	/* ^D is a self-delimiting token */
507 	case '[':
508 	case ']':
509 	    s1[0] = (byte) c;
510 	    retcode = name_ref(imemory, s1, 1, myref, 1);	/* can't fail */
511 	    r_set_attrs(myref, a_executable);
512 	    break;
513 	case '<':
514 	    if (scan_enable_level2) {
515 		ensure2(scanning_none);
516 		c = scan_getc();
517 		switch (c) {
518 		    case '<':
519 			scan_putback();
520 			name_type = 0;
521 			try_number = false;
522 			goto try_funny_name;
523 		    case '~':
524 			s_A85D_init_inline(&sstate.s_ss.a85d);
525 			sstate.s_ss.st.template = &s_A85D_template;
526 			goto str;
527 		}
528 		scan_putback();
529 	    }
530 	    s_AXD_init_inline(&sstate.s_ss.axd);
531 	    sstate.s_ss.st.template = &s_AXD_template;
532 	  str:scan_end_inline();
533 	    dynamic_init(&da, imemory);
534 	  cont_string:for (;;) {
535 		stream_cursor_write w;
536 
537 		w.ptr = da.next - 1;
538 		w.limit = da.limit - 1;
539 		status = (*sstate.s_ss.st.template->process)
540 		    (&sstate.s_ss.st, &s->cursor.r, &w,
541 		     s->end_status == EOFC);
542 		if (!check_only)
543 		    da.next = w.ptr + 1;
544 		switch (status) {
545 		    case 0:
546 			status = s->end_status;
547 			if (status < 0) {
548 			    if (status == EOFC) {
549 				if (check_only) {
550 				    retcode = scan_Refill;
551 				    scan_type = scanning_string;
552 				    goto suspend;
553 				} else
554 				    sreturn(e_syntaxerror);
555 			    }
556 			    break;
557 			}
558 			s_process_read_buf(s);
559 			continue;
560 		    case 1:
561 			if (!check_only) {
562 			    retcode = dynamic_grow(&da, da.next, max_string_size);
563 			    if (retcode == e_VMerror) {
564 				scan_type = scanning_string;
565 				goto suspend;
566 			    } else if (retcode < 0)
567 				sreturn(retcode);
568 			}
569 			continue;
570 		}
571 		break;
572 	    }
573 	    scan_begin_inline();
574 	    switch (status) {
575 		default:
576 		    /*case ERRC: */
577 		    sreturn(e_syntaxerror);
578 		case INTC:
579 		case CALLC:
580 		    scan_type = scanning_string;
581 		    goto pause;
582 		case EOFC:
583 		    ;
584 	    }
585 	    retcode = dynamic_make_string(i_ctx_p, myref, &da, da.next);
586 	    if (retcode < 0) {	/* VMerror */
587 		sputback(s);	/* rescan ) */
588 		scan_type = scanning_string;
589 		goto suspend;
590 	    }
591 	    break;
592 	case '(':
593 	    sstate.s_ss.pssd.from_string =
594 		((pstate->s_options & SCAN_FROM_STRING) != 0) &&
595 		!scan_enable_level2;
596 	    s_PSSD_partially_init_inline(&sstate.s_ss.pssd);
597 	    sstate.s_ss.st.template = &s_PSSD_template;
598 	    goto str;
599 	case '{':
600 	    if (pstack == 0) {	/* outermost procedure */
601 		if_not_spush1() {
602 		    scan_putback();
603 		    scan_type = scanning_none;
604 		    goto pause_ret;
605 		}
606 		pdepth = ref_stack_count_inline(&o_stack);
607 	    }
608 	    make_int(osp, pstack);
609 	    pstack = ref_stack_count_inline(&o_stack);
610 	    if_debug3('S', "[S{]d=%d, s=%d->%d\n",
611 		      pdepth, (int)osp->value.intval, pstack);
612 	    goto snext;
613 	case '>':
614 	    if (scan_enable_level2) {
615 		ensure2(scanning_none);
616 		name_type = 0;
617 		try_number = false;
618 		goto try_funny_name;
619 	    }
620 	    /* falls through */
621 	case ')':
622 	    sreturn(e_syntaxerror);
623 	case '}':
624 	    if (pstack == 0)
625 		sreturn(e_syntaxerror);
626 	    osp--;
627 	    {
628 		uint size = ref_stack_count_inline(&o_stack) - pstack;
629 		ref arr;
630 
631 		if_debug4('S', "[S}]d=%d, s=%d->%ld, c=%d\n",
632 			  pdepth, pstack,
633 			  (pstack == pdepth ? 0 :
634 			   ref_stack_index(&o_stack, size)->value.intval),
635 			  size + pstack);
636 		myref = (pstack == pdepth ? pref : &arr);
637 		if (check_only) {
638 		    make_empty_array(myref, 0);
639 		    ref_stack_pop(&o_stack, size);
640 		} else if (ref_array_packing.value.boolval) {
641 		    retcode = make_packed_array(myref, &o_stack, size,
642 						idmemory, "scanner(packed)");
643 		    if (retcode < 0) {	/* must be VMerror */
644 			osp++;
645 			scan_putback();
646 			scan_type = scanning_none;
647 			goto pause_ret;
648 		    }
649 		    r_set_attrs(myref, a_executable);
650 		} else {
651 		    retcode = ialloc_ref_array(myref,
652 					       a_executable + a_all, size,
653 					       "scanner(proc)");
654 		    if (retcode < 0) {	/* must be VMerror */
655 			osp++;
656 			scan_putback();
657 			scan_type = scanning_none;
658 			goto pause_ret;
659 		    }
660 		    retcode = ref_stack_store(&o_stack, myref, size, 0, 1,
661 					      false, idmemory, "scanner");
662 		    if (retcode < 0) {
663 			ifree_ref_array(myref, "scanner(proc)");
664 			sreturn(retcode);
665 		    }
666 		    ref_stack_pop(&o_stack, size);
667 		}
668 		if (pstack == pdepth) {		/* This was the top-level procedure. */
669 		    spop1();
670 		    pstack = 0;
671 		} else {
672 		    if (osp < osbot)
673 			ref_stack_pop_block(&o_stack);
674 		    pstack = osp->value.intval;
675 		    *osp = arr;
676 		    goto snext;
677 		}
678 	    }
679 	    break;
680 	case '/':
681 	    ensure2(scanning_none);
682 	    c = scan_getc();
683 	    if (!PDFScanRules && (c == '/')) {
684 		name_type = 2;
685 		c = scan_getc();
686 	    } else
687 		name_type = 1;
688 	    try_number = false;
689 	    switch (decoder[c]) {
690 		case ctype_name:
691 		default:
692 		    goto do_name;
693 		case ctype_btoken:
694 		    if (!recognize_btokens())
695 			goto do_name;
696 		    /* otherwise, an empty name */
697 		case ctype_exception:
698 		case ctype_space:
699 		    /*
700 		     * Amazingly enough, the Adobe implementations don't accept
701 		     * / or // followed by [, ], <<, or >>, so we do the same.
702 		     * (Older versions of our code had a ctype_other case here
703 		     * that handled these specially.)
704 		     */
705 		case ctype_other:
706 		    da.base = da.limit = daptr = 0;
707 		    da.is_dynamic = false;
708 		    goto nx;
709 	    }
710 	case '%':
711 	    {			/* Scan as much as possible within the buffer. */
712 		const byte *base = sptr;
713 		const byte *end;
714 
715 		while (++sptr < endptr)		/* stop 1 char early */
716 		    switch (*sptr) {
717 			case char_CR:
718 			    end = sptr;
719 			    if (sptr[1] == char_EOL)
720 				sptr++;
721 			  cend:	/* Check for externally processed comments. */
722 			    retcode = scan_comment(i_ctx_p, myref, &sstate,
723 						   base, end, false);
724 			    if (retcode != 0)
725 				goto comment;
726 			    goto top;
727 			case char_EOL:
728 			case '\f':
729 			    end = sptr;
730 			    goto cend;
731 		    }
732 		/*
733 		 * We got to the end of the buffer while inside a comment.
734 		 * If there is a possibility that we must pass the comment
735 		 * to an external procedure, move what we have collected
736 		 * so far into a private buffer now.
737 		 */
738 #define comment_line da.buf
739 		--sptr;
740 		comment_line[1] = 0;
741 		{
742 		    /* Could be an externally processable comment. */
743 		    uint len = sptr + 1 - base;
744 		    if (len > sizeof(comment_line))
745 			len = sizeof(comment_line);
746 
747 		    memcpy(comment_line, base, len);
748 		    daptr = comment_line + len;
749 		}
750 		da.base = comment_line;
751 		da.is_dynamic = false;
752 	    }
753 	    /* Enter here to continue scanning a comment. */
754 	    /* daptr must be set. */
755 	  cont_comment:for (;;) {
756 		switch ((c = scan_getc())) {
757 		    default:
758 			if (c < 0)
759 			    switch (c) {
760 				case INTC:
761 				case CALLC:
762 				    da.next = daptr;
763 				    scan_type = scanning_comment;
764 				    goto pause;
765 				case EOFC:
766 				    /*
767 				     * One would think that an EOF in a comment
768 				     * should be a syntax error, but there are
769 				     * quite a number of files that end that way.
770 				     */
771 				    goto end_comment;
772 				default:
773 				    sreturn(e_syntaxerror);
774 			    }
775 			if (daptr < comment_line + max_comment_line)
776 			    *daptr++ = c;
777 			continue;
778 		    case char_CR:
779 		    case char_EOL:
780 		    case '\f':
781 		      end_comment:
782 			retcode = scan_comment(i_ctx_p, myref, &sstate,
783 					       comment_line, daptr, true);
784 			if (retcode != 0)
785 			    goto comment;
786 			goto top;
787 		}
788 	    }
789 #undef comment_line
790 	    /*NOTREACHED */
791 	case EOFC:
792 	    if (pstack != 0) {
793 		if (check_only)
794 		    goto pause;
795 		sreturn(e_syntaxerror);
796 	    }
797 	    retcode = scan_EOF;
798 	    break;
799 	case ERRC:
800 	    sreturn(e_ioerror);
801 
802 	    /* Check for a Level 2 funny name (<< or >>). */
803 	    /* c is '<' or '>'.  We already did an ensure2. */
804 	  try_funny_name:
805 	    {
806 		int c1 = scan_getc();
807 
808 		if (c1 == c) {
809 		    s1[0] = s1[1] = c;
810 		    name_ref(imemory, s1, 2, myref, 1);	/* can't fail */
811 		    goto have_name;
812 		}
813 		scan_putback();
814 	    }
815 	    sreturn(e_syntaxerror);
816 
817 	    /* Handle separately the names that might be a number. */
818 	case '0':
819 	case '1':
820 	case '2':
821 	case '3':
822 	case '4':
823 	case '5':
824 	case '6':
825 	case '7':
826 	case '8':
827 	case '9':
828 	case '.':
829 	    sign = 0;
830     nr:	    /*
831 	     * Skip a leading sign, if any, by conditionally passing
832 	     * sptr + 1 rather than sptr.  Also, if the last character
833 	     * in the buffer is a CR, we must stop the scan 1 character
834 	     * early, to be sure that we can test for CR+LF within the
835 	     * buffer, by passing endptr rather than endptr + 1.
836 	     */
837 	    retcode = scan_number(sptr + (sign & 1),
838 		    endptr /*(*endptr == char_CR ? endptr : endptr + 1) */ ,
839 				  sign, myref, &newptr, PDFScanInvNum);
840 	    if (retcode == 1 && decoder[newptr[-1]] == ctype_space) {
841 		sptr = newptr - 1;
842 		if (*sptr == char_CR && sptr[1] == char_EOL)
843 		    sptr++;
844 		retcode = 0;
845 		ref_mark_new(myref);
846 		break;
847 	    }
848 	    name_type = 0;
849 	    try_number = true;
850 	    goto do_name;
851 	case '+':
852 	    sign = 1;
853 	    goto nr;
854 	case '-':
855 	    sign = -1;
856 	    goto nr;
857 
858 	    /* Check for a binary object */
859 #define case4(c) case c: case c+1: case c+2: case c+3
860 	  case4(128): case4(132): case4(136): case4(140):
861 	  case4(144): case4(148): case4(152): case4(156):
862 #undef case4
863 	    if (recognize_btokens()) {
864 		scan_end_inline();
865 		retcode = scan_binary_token(i_ctx_p, s, myref, &sstate);
866 		scan_begin_inline();
867 		if (retcode == scan_Refill)
868 		    goto pause;
869 		break;
870 	    }
871 	    /* Not a binary object, fall through. */
872 
873 	    /* The default is a name. */
874 	default:
875 	    if (c < 0) {
876 		dynamic_init(&da, name_memory(imemory));	/* da state must be clean */
877 		scan_type = scanning_none;
878 		goto pause;
879 	    }
880 	    /* Populate the switch with enough cases to force */
881 	    /* simple compilers to use a dispatch rather than tests. */
882 	case '!':
883 	case '"':
884 	case '#':
885 	case '$':
886 	case '&':
887 	case '\'':
888 	case '*':
889 	case ',':
890 	case '=':
891 	case ':':
892 	case ';':
893 	case '?':
894 	case '@':
895 	case 'A':
896 	case 'B':
897 	case 'C':
898 	case 'D':
899 	case 'E':
900 	case 'F':
901 	case 'G':
902 	case 'H':
903 	case 'I':
904 	case 'J':
905 	case 'K':
906 	case 'L':
907 	case 'M':
908 	case 'N':
909 	case 'O':
910 	case 'P':
911 	case 'Q':
912 	case 'R':
913 	case 'S':
914 	case 'T':
915 	case 'U':
916 	case 'V':
917 	case 'W':
918 	case 'X':
919 	case 'Y':
920 	case 'Z':
921 	case '\\':
922 	case '^':
923 	case '_':
924 	case '`':
925 	case 'a':
926 	case 'b':
927 	case 'c':
928 	case 'd':
929 	case 'e':
930 	case 'f':
931 	case 'g':
932 	case 'h':
933 	case 'i':
934 	case 'j':
935 	case 'k':
936 	case 'l':
937 	case 'm':
938 	case 'n':
939 	case 'o':
940 	case 'p':
941 	case 'q':
942 	case 'r':
943 	case 's':
944 	case 't':
945 	case 'u':
946 	case 'v':
947 	case 'w':
948 	case 'x':
949 	case 'y':
950 	case 'z':
951 	case '|':
952 	case '~':
953 	    /* Common code for scanning a name. */
954 	    /* try_number and name_type are already set. */
955 	    /* We know c has ctype_name (or maybe ctype_btoken) */
956 	    /* or is a digit. */
957 	    name_type = 0;
958 	    try_number = false;
959 	  do_name:
960 	    /* Try to scan entirely within the stream buffer. */
961 	    /* We stop 1 character early, so we don't switch buffers */
962 	    /* looking ahead if the name is terminated by \r\n. */
963 	    da.base = (byte *) sptr;
964 	    da.is_dynamic = false;
965 	    {
966 		const byte *endp1 = endptr - 1;
967 
968 		do {
969 		    if (sptr >= endp1)	/* stop 1 early! */
970 			goto dyn_name;
971 		}
972 		while (decoder[*++sptr] <= max_name_ctype);	/* digit or name */
973 	    }
974 	    /* Name ended within the buffer. */
975 	    daptr = (byte *) sptr;
976 	    c = *sptr;
977 	    goto nx;
978 	  dyn_name:		/* Name extended past end of buffer. */
979 	    scan_end_inline();
980 	    /* Initialize the dynamic area. */
981 	    /* We have to do this before the next */
982 	    /* sgetc, which will overwrite the buffer. */
983 	    da.limit = (byte *)++ sptr;
984 	    da.memory = name_memory(imemory);
985 	    retcode = dynamic_grow(&da, da.limit, name_max_string);
986 	    if (retcode < 0) {
987 		dynamic_save(&da);
988 		if (retcode != e_VMerror)
989 		    sreturn(retcode);
990 		scan_type = scanning_name;
991 		goto pause_ret;
992 	    }
993 	    daptr = da.next;
994 	    /* Enter here to continue scanning a name. */
995 	    /* daptr must be set. */
996 	  cont_name:scan_begin_inline();
997 	    while (decoder[c = scan_getc()] <= max_name_ctype) {
998 		if (daptr == da.limit) {
999 		    retcode = dynamic_grow(&da, daptr,
1000 					   name_max_string);
1001 		    if (retcode < 0) {
1002 			dynamic_save(&da);
1003 			if (retcode != e_VMerror)
1004 			    sreturn(retcode);
1005 			scan_putback();
1006 			scan_type = scanning_name;
1007 			goto pause_ret;
1008 		    }
1009 		    daptr = da.next;
1010 		}
1011 		*daptr++ = c;
1012 	    }
1013 	  nx:switch (decoder[c]) {
1014 		case ctype_btoken:
1015 		case ctype_other:
1016 		    scan_putback();
1017 		    break;
1018 		case ctype_space:
1019 		    /* Check for \r\n */
1020 		    if (c == char_CR) {
1021 			if (sptr >= endptr) {	/* ensure2 *//* We have to check specially for */
1022 			    /* the case where the very last */
1023 			    /* character of a file is a CR. */
1024 			    if (s->end_status != EOFC) {
1025 				sptr--;
1026 				goto pause_name;
1027 			    }
1028 			} else if (sptr[1] == char_EOL)
1029 			    sptr++;
1030 		    }
1031 		    break;
1032 		case ctype_exception:
1033 		    switch (c) {
1034 			case INTC:
1035 			case CALLC:
1036 			    goto pause_name;
1037 			case ERRC:
1038 			    sreturn(e_ioerror);
1039 			case EOFC:
1040 			    break;
1041 		    }
1042 	    }
1043 	    /* Check for a number */
1044 	    if (try_number) {
1045 		const byte *base = da.base;
1046 
1047 		scan_sign(sign, base);
1048 		retcode = scan_number(base, daptr, sign, myref, &newptr, PDFScanInvNum);
1049 		if (retcode == 1) {
1050 		    ref_mark_new(myref);
1051 		    retcode = 0;
1052 		} else if (retcode != e_syntaxerror) {
1053 		    dynamic_free(&da);
1054 		    if (name_type == 2)
1055 			sreturn(e_syntaxerror);
1056 		    break;	/* might be e_limitcheck */
1057 		}
1058 	    }
1059 	    if (da.is_dynamic) {	/* We've already allocated the string on the heap. */
1060 		uint size = daptr - da.base;
1061 
1062 		retcode = name_ref(imemory, da.base, size, myref, -1);
1063 		if (retcode >= 0) {
1064 		    dynamic_free(&da);
1065 		} else {
1066 		    retcode = dynamic_resize(&da, size);
1067 		    if (retcode < 0) {	/* VMerror */
1068 			if (c != EOFC)
1069 			    scan_putback();
1070 			scan_type = scanning_name;
1071 			goto pause_ret;
1072 		    }
1073 		    retcode = name_ref(imemory, da.base, size, myref, 2);
1074 		}
1075 	    } else {
1076 		retcode = name_ref(imemory, da.base, (uint) (daptr - da.base),
1077 				   myref, !s->foreign);
1078 	    }
1079 	    /* Done scanning.  Check for preceding /'s. */
1080 	    if (retcode < 0) {
1081 		if (retcode != e_VMerror)
1082 		    sreturn(retcode);
1083 		if (!da.is_dynamic) {
1084 		    da.next = daptr;
1085 		    dynamic_save(&da);
1086 		}
1087 		if (c != EOFC)
1088 		    scan_putback();
1089 		scan_type = scanning_name;
1090 		goto pause_ret;
1091 	    }
1092 	  have_name:switch (name_type) {
1093 		case 0:	/* ordinary executable name */
1094 		    if (r_has_type(myref, t_name))	/* i.e., not a number */
1095 			r_set_attrs(myref, a_executable);
1096 		case 1:	/* quoted name */
1097 		    break;
1098 		case 2:	/* immediate lookup */
1099 		    {
1100 			ref *pvalue;
1101 
1102 			if (!r_has_type(myref, t_name))
1103 			    sreturn(e_undefined);
1104 			if ((pvalue = dict_find_name(myref)) == 0)
1105 			    sreturn(e_undefined);
1106 			if (pstack != 0 &&
1107 			    r_space(pvalue) > ialloc_space(idmemory)
1108 			    )
1109 			    sreturn(e_invalidaccess);
1110 			ref_assign_new(myref, pvalue);
1111 		    }
1112 	    }
1113     }
1114   sret:if (retcode < 0) {
1115 	scan_end_inline();
1116 	if (pstack != 0) {
1117 	    if (retcode == e_undefined)
1118 		*pref = *osp;	/* return undefined name as error token */
1119 	    ref_stack_pop(&o_stack,
1120 			  ref_stack_count(&o_stack) - (pdepth - 1));
1121 	}
1122 	return retcode;
1123     }
1124     /* If we are at the top level, return the object, */
1125     /* otherwise keep going. */
1126     if (pstack == 0) {
1127 	scan_end_inline();
1128 	return retcode;
1129     }
1130   snext:if_not_spush1() {
1131 	scan_end_inline();
1132 	scan_type = scanning_none;
1133 	goto save;
1134     }
1135     myref = osp;
1136     goto top;
1137 
1138     /* Pause for an interrupt or callout. */
1139   pause_name:
1140     /* If we're still scanning within the stream buffer, */
1141     /* move the characters to the private buffer (da.buf) now. */
1142     da.next = daptr;
1143     dynamic_save(&da);
1144     scan_type = scanning_name;
1145   pause:
1146     retcode = scan_Refill;
1147   pause_ret:
1148     scan_end_inline();
1149   suspend:
1150     if (pstack != 0)
1151 	osp--;			/* myref */
1152   save:
1153     *pstate = sstate;
1154     return retcode;
1155 
1156     /* Handle a scanned comment. */
1157  comment:
1158     if (retcode < 0)
1159 	goto sret;
1160     scan_end_inline();
1161     scan_type = scanning_none;
1162     goto save;
1163 }
1164