1 /*
2  * Copyright © 2008 Chris Wilson <chris@chris-wilson.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it either under the terms of the GNU Lesser General Public
6  * License version 2.1 as published by the Free Software Foundation
7  * (the "LGPL") or, at your option, under the terms of the Mozilla
8  * Public License Version 1.1 (the "MPL"). If you do not alter this
9  * notice, a recipient may use your version of this file under either
10  * the MPL or the LGPL.
11  *
12  * You should have received a copy of the LGPL along with this library
13  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15  * You should have received a copy of the MPL along with this library
16  * in the file COPYING-MPL-1.1
17  *
18  * The contents of this file are subject to the Mozilla Public License
19  * Version 1.1 (the "License"); you may not use this file except in
20  * compliance with the License. You may obtain a copy of the License at
21  * http://www.mozilla.org/MPL/
22  *
23  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
24  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
25  * the specific language governing rights and limitations.
26  *
27  * The Original Code is the cairo graphics library.
28  *
29  * The Initial Developer of the Original Code is Chris Wilson.
30  *
31  * Contributor(s):
32  *	Chris Wilson <chris@chris-wilson.co.uk>
33  */
34 
35 #include "config.h"
36 
37 #include "cairo-script-private.h"
38 
39 #include <limits.h> /* INT_MAX */
40 #include <math.h> /* pow */
41 #include <stdio.h> /* EOF */
42 #include <stdint.h> /* for {INT,UINT}*_{MIN,MAX} */
43 #include <stdlib.h> /* malloc/free */
44 #include <string.h> /* memset */
45 #include <assert.h>
46 #include <zlib.h>
47 
48 #if HAVE_LZO
49 #include <lzo/lzo2a.h>
50 #endif
51 
52 #define DEBUG_SCAN 0
53 
54 #if WORDS_BIGENDIAN
55 #define le16(x) bswap_16 (x)
56 #define le32(x) bswap_32 (x)
57 #define be16(x) x
58 #define be32(x) x
59 #define to_be32(x) x
60 #else
61 #define le16(x) x
62 #define le32(x) x
63 #define be16(x) bswap_16 (x)
64 #define be32(x) bswap_32 (x)
65 #define to_be32(x) bswap_32 (x)
66 #endif
67 
68 /*
69  * whitespace:
70  * 0 - nul
71  * 9 - tab
72  * A - LF
73  * C - FF
74  * D - CR
75  *
76  * syntax delimiters
77  * ( = 28, ) = 29 - literal strings
78  * < = 3C, > = 3E - hex/base85 strings, dictionary name
79  * [ = 5B, ] = 5D - array
80  * { = 7B, } = 7C - procedure
81  * / = 5C - literal marker
82  * % = 25 - comment
83  */
84 
85 static void
fprintf_obj(FILE * stream,csi_t * ctx,const csi_object_t * obj)86 fprintf_obj (FILE *stream, csi_t *ctx, const csi_object_t *obj)
87 {
88     switch (csi_object_get_type (obj)) {
89 	case CSI_OBJECT_TYPE_NULL:
90 	    fprintf (stream, "NULL\n");
91 	    break;
92 
93 	    /* atomics */
94 	case CSI_OBJECT_TYPE_BOOLEAN:
95 	    fprintf (stream, "boolean: %s\n",
96 		    obj->datum.boolean ? "true" : "false");
97 	    break;
98 	case CSI_OBJECT_TYPE_INTEGER:
99 	    fprintf (stream, "integer: %ld\n", obj->datum.integer);
100 	    break;
101 	case CSI_OBJECT_TYPE_MARK:
102 	    fprintf (stream, "mark\n");
103 	    break;
104 	case CSI_OBJECT_TYPE_NAME:
105 	    fprintf (stream, "name: %s\n", (char *) obj->datum.name);
106 	    break;
107 	case CSI_OBJECT_TYPE_OPERATOR:
108 	    fprintf (stream, "operator: %p\n", obj->datum.ptr);
109 	    break;
110 	case CSI_OBJECT_TYPE_REAL:
111 	    fprintf (stream, "real: %g\n", obj->datum.real);
112 	    break;
113 
114 	    /* compound */
115 	case CSI_OBJECT_TYPE_ARRAY:
116 	    fprintf (stream, "array\n");
117 	    break;
118 	case CSI_OBJECT_TYPE_DICTIONARY:
119 	    fprintf (stream, "dictionary\n");
120 	    break;
121 	case CSI_OBJECT_TYPE_FILE:
122 	    fprintf (stream, "file\n");
123 	    break;
124 	case CSI_OBJECT_TYPE_MATRIX:
125 	    fprintf (stream, "matrix: [%g %g %g %g %g %g]\n",
126 		    obj->datum.matrix->matrix.xx,
127 		    obj->datum.matrix->matrix.yx,
128 		    obj->datum.matrix->matrix.xy,
129 		    obj->datum.matrix->matrix.yy,
130 		    obj->datum.matrix->matrix.x0,
131 		    obj->datum.matrix->matrix.y0);
132 	    break;
133 	case CSI_OBJECT_TYPE_STRING:
134 	    fprintf (stream, "string: len=%ld, defate=%ld, method=%d\n",
135 		     obj->datum.string->len, obj->datum.string->deflate, obj->datum.string->method);
136 	    break;
137 
138 	    /* cairo */
139 	case CSI_OBJECT_TYPE_CONTEXT:
140 	    fprintf (stream, "context\n");
141 	    break;
142 	case CSI_OBJECT_TYPE_FONT:
143 	    fprintf (stream, "font\n");
144 	    break;
145 	case CSI_OBJECT_TYPE_PATTERN:
146 	    fprintf (stream, "pattern\n");
147 	    break;
148 	case CSI_OBJECT_TYPE_SCALED_FONT:
149 	    fprintf (stream, "scaled-font\n");
150 	    break;
151 	case CSI_OBJECT_TYPE_SURFACE:
152 	    fprintf (stream, "surface\n");
153 	    break;
154     }
155 }
156 
157 /* takes ownership of obj */
158 static inline csi_status_t
scan_push(csi_t * ctx,csi_object_t * obj)159 scan_push (csi_t *ctx, csi_object_t *obj)
160 {
161     return ctx->scanner.push (ctx, obj);
162 }
163 
164 static inline csi_status_t
scan_execute(csi_t * ctx,csi_object_t * obj)165 scan_execute (csi_t *ctx, csi_object_t *obj)
166 {
167     return ctx->scanner.execute (ctx, obj);
168 }
169 
170 static cairo_status_t
buffer_init(csi_t * ctx,csi_buffer_t * buffer)171 buffer_init (csi_t *ctx, csi_buffer_t *buffer)
172 {
173     cairo_status_t status = CSI_STATUS_SUCCESS;
174 
175     buffer->size = 16384;
176     buffer->base = _csi_alloc (ctx, buffer->size);
177     if (_csi_unlikely (buffer->base == NULL)) {
178 	status = _csi_error (CSI_STATUS_NO_MEMORY);
179 	buffer->size = 0;
180     }
181 
182     buffer->ptr = buffer->base;
183     buffer->end = buffer->base + buffer->size;
184 
185     return status;
186 }
187 
188 static void
buffer_fini(csi_t * ctx,csi_buffer_t * buffer)189 buffer_fini (csi_t *ctx, csi_buffer_t *buffer)
190 {
191     _csi_free (ctx, buffer->base);
192 }
193 
194 static void
_buffer_grow(csi_t * ctx,csi_scanner_t * scan)195 _buffer_grow (csi_t *ctx, csi_scanner_t *scan)
196 {
197     int newsize;
198     int offset;
199     char *base;
200 
201     if (_csi_unlikely (scan->buffer.size > INT_MAX / 2))
202 	longjmp (scan->jump_buffer,  _csi_error (CSI_STATUS_NO_MEMORY));
203 
204     offset = scan->buffer.ptr - scan->buffer.base;
205     newsize = scan->buffer.size * 2;
206     base = _csi_realloc (ctx, scan->buffer.base, newsize);
207     if (_csi_unlikely (base == NULL))
208 	longjmp (scan->jump_buffer,  _csi_error (CSI_STATUS_NO_MEMORY));
209 
210     scan->buffer.base = base;
211     scan->buffer.ptr  = base + offset;
212     scan->buffer.end  = base + newsize;
213     scan->buffer.size = newsize;
214 }
215 
216 static inline void
buffer_check(csi_t * ctx,csi_scanner_t * scan,int count)217 buffer_check (csi_t *ctx, csi_scanner_t *scan, int count)
218 {
219     if (_csi_unlikely (scan->buffer.ptr + count > scan->buffer.end))
220 	_buffer_grow (ctx, scan);
221 }
222 
223 static inline void
buffer_add(csi_buffer_t * buffer,int c)224 buffer_add (csi_buffer_t *buffer, int c)
225 {
226     *buffer->ptr++ = c;
227 }
228 
229 static inline void
buffer_reset(csi_buffer_t * buffer)230 buffer_reset (csi_buffer_t *buffer)
231 {
232     buffer->ptr = buffer->base;
233 }
234 
235 static void
token_start(csi_scanner_t * scan)236 token_start (csi_scanner_t *scan)
237 {
238     buffer_reset (&scan->buffer);
239 }
240 
241 static void
token_add(csi_t * ctx,csi_scanner_t * scan,int c)242 token_add (csi_t *ctx, csi_scanner_t *scan, int c)
243 {
244     buffer_check (ctx, scan, 1);
245     buffer_add (&scan->buffer, c);
246 }
247 
248 static void
token_add_unchecked(csi_scanner_t * scan,int c)249 token_add_unchecked (csi_scanner_t *scan, int c)
250 {
251     buffer_add (&scan->buffer, c);
252 }
253 
254 csi_boolean_t
_csi_parse_number(csi_object_t * obj,const char * s,int len)255 _csi_parse_number (csi_object_t *obj, const char *s, int len)
256 {
257     int radix = 0;
258     long long mantissa = 0;
259     int exponent = 0;
260     int sign = 1;
261     int decimal = -1;
262     int exponent_sign = 0;
263     const char * const end = s + len;
264 
265     switch (*s) {
266     case '0':
267     case '1':
268     case '2':
269     case '3':
270     case '4':
271     case '5':
272     case '6':
273     case '7':
274     case '8':
275     case '9':
276 	mantissa = *s - '0';
277     case '+':
278 	break;
279     case '-':
280 	sign = -1;
281 	break;
282     case '.':
283 	decimal = 0;
284 	break;
285     default:
286 	return FALSE;
287     }
288 
289     while (++s < end) {
290 	if (*s < '0') {
291 	    if (*s == '.') {
292 		if (_csi_unlikely (radix))
293 		    return FALSE;
294 		if (_csi_unlikely (decimal != -1))
295 		    return FALSE;
296 		if (_csi_unlikely (exponent_sign))
297 		    return FALSE;
298 
299 		decimal = 0;
300 	    } else if (*s == '!') {
301 		if (_csi_unlikely (radix))
302 		    return FALSE;
303 		if (_csi_unlikely (decimal != -1))
304 		    return FALSE;
305 		if (_csi_unlikely (exponent_sign))
306 		    return FALSE;
307 
308 		radix = mantissa;
309 		mantissa = 0;
310 
311 		if (_csi_unlikely (radix < 2 || radix > 36))
312 		    return FALSE;
313 	    } else
314 		return FALSE;
315 	} else if (*s <= '9') {
316 	    int v = *s - '0';
317 	    if (_csi_unlikely (radix && v >= radix))
318 		return FALSE;
319 
320 	    if (exponent_sign) {
321 		exponent = 10 * exponent + v;
322 	    } else {
323 		if (radix)
324 		    mantissa = radix * mantissa + v;
325 		else
326 		    mantissa = 10 * mantissa + v;
327 		if (decimal != -1)
328 		    decimal++;
329 	    }
330 	} else if (*s == 'E' || * s== 'e') {
331 	    if (radix == 0) {
332 		if (_csi_unlikely (s + 1 == end))
333 		    return FALSE;
334 
335 		exponent_sign = 1;
336 		if (s[1] == '-') {
337 		    exponent_sign = -1;
338 		    s++;
339 		} else if (s[1] == '+')
340 		    s++;
341 	    } else {
342 		int v = 0xe;
343 
344 		if (_csi_unlikely (v >= radix))
345 		    return FALSE;
346 
347 		mantissa = radix * mantissa + v;
348 	    }
349 	} else if (*s < 'A') {
350 	    return FALSE;
351 	} else if (*s <= 'Z') {
352 	    int v = *s - 'A' + 0xA;
353 
354 	    if (_csi_unlikely (v >= radix))
355 		return FALSE;
356 
357 	    mantissa = radix * mantissa + v;
358 	} else if (*s < 'a') {
359 	    return FALSE;
360 	} else if (*s <= 'z') {
361 	    int v = *s - 'a' + 0xa;
362 
363 	    if (_csi_unlikely (v >= radix))
364 		return FALSE;
365 
366 	    mantissa = radix * mantissa + v;
367 	} else
368 	    return FALSE;
369     }
370 
371     if (exponent_sign || decimal != -1) {
372 	if (mantissa == 0) {
373 	    obj->type = CSI_OBJECT_TYPE_REAL;
374 	    obj->datum.real = 0.;
375 	    return TRUE;
376 	} else {
377 	    int e;
378 	    double v;
379 
380 	    v = mantissa;
381 	    e = exponent * exponent_sign;
382 	    if (decimal != -1)
383 		e -= decimal;
384 	    switch (e) {
385 	    case -7: v *= 0.0000001; break;
386 	    case -6: v *= 0.000001; break;
387 	    case -5: v *= 0.00001; break;
388 	    case -4: v *= 0.0001; break;
389 	    case -3: v *= 0.001; break;
390 	    case -2: v *= 0.01; break;
391 	    case -1: v *= 0.1; break;
392 	    case  0: break;
393 	    case  1: v *= 10; break;
394 	    case  2: v *= 100; break;
395 	    case  3: v *= 1000; break;
396 	    case  4: v *= 10000; break;
397 	    case  5: v *= 100000; break;
398 	    case  6: v *= 1000000; break;
399 	    default:
400 		    v *= pow (10, e); /* XXX */
401 		    break;
402 	    }
403 
404 	    obj->type = CSI_OBJECT_TYPE_REAL;
405 	    obj->datum.real = sign * v;
406 	    return TRUE;
407 	}
408     } else {
409 	obj->type = CSI_OBJECT_TYPE_INTEGER;
410 	obj->datum.integer = sign * mantissa;
411 	return TRUE;
412     }
413 }
414 
415 static void
token_end(csi_t * ctx,csi_scanner_t * scan,csi_file_t * src)416 token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
417 {
418     cairo_status_t status;
419     char *s;
420     csi_object_t obj;
421     int len;
422 
423     /*
424      * Any token that consists entirely of regular characters and
425      * cannot be interpreted as a number is treated as a name object
426      * (more precisely, an executable name). All characters except
427      * delimiters and white-space characters can appear in names,
428      * including characters ordinarily considered to be punctuation.
429      */
430 
431     if (_csi_unlikely (scan->buffer.ptr == scan->buffer.base))
432 	return;
433 
434     s = scan->buffer.base;
435     len = scan->buffer.ptr - scan->buffer.base;
436 
437     if (_csi_likely (! scan->bind)) {
438 	if (s[0] == '{') { /* special case procedures */
439 	    if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
440 		status = _csi_stack_push (ctx,
441 					  &scan->procedure_stack,
442 					  &scan->build_procedure);
443 		if (_csi_unlikely (status))
444 		    longjmp (scan->jump_buffer, status);
445 	    }
446 
447 	    status = csi_array_new (ctx, 0, &scan->build_procedure);
448 	    if (_csi_unlikely (status))
449 		longjmp (scan->jump_buffer, status);
450 
451 	    scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE;
452 	    return;
453 	} else if (s[0] == '}') {
454 	    if (_csi_unlikely
455 		(scan->build_procedure.type == CSI_OBJECT_TYPE_NULL))
456 	    {
457 		longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
458 	    }
459 
460 	    if (scan->procedure_stack.len) {
461 		csi_object_t *next;
462 
463 		next = _csi_stack_peek (&scan->procedure_stack, 0);
464 		status = csi_array_append (ctx, next->datum.array,
465 					   &scan->build_procedure);
466 		scan->build_procedure = *next;
467 		scan->procedure_stack.len--;
468 	    } else {
469 		status = scan_push (ctx, &scan->build_procedure);
470 		scan->build_procedure.type = CSI_OBJECT_TYPE_NULL;
471 	    }
472 	    if (_csi_unlikely (status))
473 		longjmp (scan->jump_buffer, status);
474 
475 	    return;
476 	}
477     }
478 
479     if (s[0] == '/') {
480 	if (len >= 2 && s[1] == '/') { /* substituted name */
481 	    status = csi_name_new (ctx, &obj, s + 2, len - 2);
482 	    if (_csi_unlikely (status))
483 		longjmp (scan->jump_buffer, status);
484 
485 	    status = _csi_name_lookup (ctx, obj.datum.name, &obj);
486 	} else { /* literal name */
487 	    status = csi_name_new (ctx, &obj, s + 1, len - 1);
488 	}
489 	if (_csi_unlikely (status))
490 	    longjmp (scan->jump_buffer, status);
491     } else {
492 	if (! _csi_parse_number (&obj, s, len)) {
493 	    status = csi_name_new (ctx, &obj, s, len);
494 	    if (_csi_unlikely (status))
495 		longjmp (scan->jump_buffer, status);
496 
497 	    obj.type |= CSI_OBJECT_ATTR_EXECUTABLE;
498 	}
499     }
500 
501     /* consume whitespace after token, before calling the interpreter */
502     if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
503 	status = csi_array_append (ctx,
504 				   scan->build_procedure.datum.array,
505 				   &obj);
506     } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
507 	status = scan_execute (ctx, &obj);
508 	csi_object_free (ctx, &obj);
509     } else {
510 	status = scan_push (ctx, &obj);
511     }
512     if (_csi_unlikely (status))
513 	longjmp (scan->jump_buffer, status);
514 }
515 
516 static void
string_add(csi_t * ctx,csi_scanner_t * scan,int c)517 string_add (csi_t *ctx, csi_scanner_t *scan, int c)
518 {
519     buffer_check (ctx, scan, 1);
520     buffer_add (&scan->buffer, c);
521 }
522 
523 static void
string_end(csi_t * ctx,csi_scanner_t * scan)524 string_end (csi_t *ctx, csi_scanner_t *scan)
525 {
526     csi_object_t obj;
527     cairo_status_t status;
528 
529     status = csi_string_new (ctx,
530 			     &obj,
531 			     scan->buffer.base,
532 			     scan->buffer.ptr - scan->buffer.base);
533     if (_csi_unlikely (status))
534 	longjmp (scan->jump_buffer, status);
535 
536     if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
537 	status = csi_array_append (ctx,
538 				   scan->build_procedure.datum.array,
539 				   &obj);
540     else
541 	status = scan_push (ctx, &obj);
542     if (_csi_unlikely (status))
543 	longjmp (scan->jump_buffer, status);
544 }
545 
546 static int
hex_value(int c)547 hex_value (int c)
548 {
549     if (c < '0')
550 	return EOF;
551     if (c <= '9')
552 	return c - '0';
553     c |= 32;
554     if (c < 'a')
555 	return EOF;
556     if (c <= 'f')
557 	return c - 'a' + 0xa;
558     return EOF;
559 }
560 
561 static void
hex_add(csi_t * ctx,csi_scanner_t * scan,int c)562 hex_add (csi_t *ctx, csi_scanner_t *scan, int c)
563 {
564     if (scan->accumulator_count == 0) {
565 	scan->accumulator |= hex_value (c) << 4;
566 	scan->accumulator_count = 1;
567     } else {
568 	scan->accumulator |= hex_value (c) << 0;
569 	buffer_check (ctx, scan, 1);
570 	buffer_add (&scan->buffer, scan->accumulator);
571 
572 	scan->accumulator = 0;
573 	scan->accumulator_count = 0;
574     }
575 }
576 
577 static void
hex_end(csi_t * ctx,csi_scanner_t * scan)578 hex_end (csi_t *ctx, csi_scanner_t *scan)
579 {
580     csi_object_t obj;
581     cairo_status_t status;
582 
583     if (scan->accumulator_count)
584 	hex_add (ctx, scan, '0');
585 
586     status = csi_string_new (ctx,
587 			     &obj,
588 			     scan->buffer.base,
589 			     scan->buffer.ptr - scan->buffer.base);
590     if (_csi_unlikely (status))
591 	longjmp (scan->jump_buffer, status);
592 
593     if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
594 	status = csi_array_append (ctx,
595 				   scan->build_procedure.datum.array,
596 				   &obj);
597     else
598 	status = scan_push (ctx, &obj);
599     if (_csi_unlikely (status))
600 	longjmp (scan->jump_buffer, status);
601 }
602 
603 static void
base85_add(csi_t * ctx,csi_scanner_t * scan,int c)604 base85_add (csi_t *ctx, csi_scanner_t *scan, int c)
605 {
606     if (c == 'z') {
607 	if (_csi_unlikely (scan->accumulator_count != 0))
608 	    longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
609 
610 	buffer_check (ctx, scan, 4);
611 	buffer_add (&scan->buffer, 0);
612 	buffer_add (&scan->buffer, 0);
613 	buffer_add (&scan->buffer, 0);
614 	buffer_add (&scan->buffer, 0);
615     } else if (_csi_unlikely (c < '!' || c > 'u')) {
616 	longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
617     } else {
618 	scan->accumulator = scan->accumulator*85 + c - '!';
619 	if (++scan->accumulator_count == 5) {
620 	    buffer_check (ctx, scan, 4);
621 	    buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
622 	    buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
623 	    buffer_add (&scan->buffer, (scan->accumulator >>  8) & 0xff);
624 	    buffer_add (&scan->buffer, (scan->accumulator >>  0) & 0xff);
625 
626 	    scan->accumulator = 0;
627 	    scan->accumulator_count = 0;
628 	}
629     }
630 }
631 
632 static void
base85_end(csi_t * ctx,csi_scanner_t * scan,cairo_bool_t deflate)633 base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate)
634 {
635     csi_object_t obj;
636     cairo_status_t status;
637 
638     buffer_check (ctx, scan, 4);
639 
640     switch (scan->accumulator_count) {
641     case 0:
642 	break;
643     case 1:
644 	longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
645 	break;
646 
647     case 2:
648 	scan->accumulator = scan->accumulator * (85*85*85) + 85*85*85 -1;
649 	buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
650 	break;
651     case 3:
652 	scan->accumulator = scan->accumulator * (85*85) + 85*85 -1;
653 	buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
654 	buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
655 	break;
656     case 4:
657 	scan->accumulator = scan->accumulator * 85 + 84;
658 	buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff);
659 	buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff);
660 	buffer_add (&scan->buffer, (scan->accumulator >>  8) & 0xff);
661 	break;
662     }
663 
664     if (deflate) {
665         uLongf len = be32 (*(uint32_t *) scan->buffer.base);
666 	Bytef *source = (Bytef *) (scan->buffer.base + sizeof (uint32_t));
667 
668 	status = csi_string_deflate_new (ctx, &obj,
669 					 source,
670 					 (Bytef *) scan->buffer.ptr - source,
671 					 len);
672 	if (_csi_unlikely (status))
673 	    longjmp (scan->jump_buffer, status);
674     } else {
675 	status = csi_string_new (ctx,
676 				 &obj,
677 				 scan->buffer.base,
678 				 scan->buffer.ptr - scan->buffer.base);
679 	if (_csi_unlikely (status))
680 	    longjmp (scan->jump_buffer, status);
681     }
682 
683     if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
684 	status = csi_array_append (ctx,
685 				   scan->build_procedure.datum.array,
686 				   &obj);
687     else
688 	status = scan_push (ctx, &obj);
689     if (_csi_unlikely (status))
690 	longjmp (scan->jump_buffer, status);
691 }
692 
693 static void
base64_add(csi_t * ctx,csi_scanner_t * scan,int c)694 base64_add (csi_t *ctx, csi_scanner_t *scan, int c)
695 {
696     int val;
697 
698     /* Convert Base64 character to its 6 bit nibble */
699     val = scan->accumulator;
700     if (c =='/') {
701 	val = (val << 6) | 63;
702     } else if (c =='+') {
703 	val = (val << 6) | 62;
704     } else if (c >='A' && c <='Z') {
705 	val = (val << 6) | (c -'A');
706     } else if (c >='a' && c <='z') {
707 	val = (val << 6) | (c -'a' + 26);
708     } else if (c >='0' && c <='9') {
709 	val = (val << 6) | (c -'0' + 52);
710     }
711 
712     buffer_check (ctx, scan, 1);
713     switch (scan->accumulator_count++) {
714     case 0:
715 	break;
716 
717     case 1:
718 	buffer_add (&scan->buffer, (val >> 4) & 0xFF);
719 	val &= 0xF;
720 	break;
721 
722     case 2:
723 	buffer_add (&scan->buffer, (val >> 2) & 0xFF);
724 	val &= 0x3;
725 	break;
726 
727     case 3:
728 	buffer_add (&scan->buffer, (val >> 0) & 0xFF);
729 	scan->accumulator_count = 0;
730 	val = 0;
731 	break;
732     }
733 
734      if (c == '=') {
735 	scan->accumulator_count = 0;
736 	scan->accumulator = 0;
737      } else {
738 	 scan->accumulator = val;
739      }
740 }
741 
742 static void
base64_end(csi_t * ctx,csi_scanner_t * scan)743 base64_end (csi_t *ctx, csi_scanner_t *scan)
744 {
745     csi_object_t obj;
746     cairo_status_t status;
747 
748     switch (scan->accumulator_count) {
749     case 0:
750 	break;
751     case 2:
752 	base64_add (ctx, scan, (scan->accumulator << 2) & 0x3f);
753 	base64_add (ctx, scan, '=');
754 	break;
755     case 1:
756 	base64_add (ctx, scan, (scan->accumulator << 4) & 0x3f);
757 	base64_add (ctx, scan, '=');
758 	base64_add (ctx, scan, '=');
759 	break;
760     }
761 
762     status = csi_string_new (ctx,
763 			     &obj,
764 			     scan->buffer.base,
765 			     scan->buffer.ptr - scan->buffer.base);
766     if (_csi_unlikely (status))
767 	longjmp (scan->jump_buffer, status);
768 
769     if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
770 	status = csi_array_append (ctx,
771 				   scan->build_procedure.datum.array,
772 				   &obj);
773     else
774 	status = scan_push (ctx, &obj);
775     if (_csi_unlikely (status))
776 	longjmp (scan->jump_buffer, status);
777 }
778 
779 static void
scan_read(csi_scanner_t * scan,csi_file_t * src,void * ptr,int len)780 scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len)
781 {
782     uint8_t *data = ptr;
783     do {
784 	int ret = csi_file_read (src, data, len);
785 	if (_csi_unlikely (ret == 0))
786 	    longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_READ_ERROR));
787 	data += ret;
788 	len -= ret;
789     } while (_csi_unlikely (len));
790 }
791 
792 static void
string_read(csi_t * ctx,csi_scanner_t * scan,csi_file_t * src,int len,int compressed,csi_object_t * obj)793 string_read (csi_t *ctx,
794 	     csi_scanner_t *scan,
795 	     csi_file_t *src,
796 	     int len,
797 	     int compressed,
798 	     csi_object_t *obj)
799 {
800     csi_status_t status;
801 
802     status = csi_string_new (ctx, obj, NULL, len);
803     if (_csi_unlikely (status))
804 	longjmp (scan->jump_buffer, status);
805 
806     if (compressed) {
807 	uint32_t u32;
808 	scan_read (scan, src, &u32, 4);
809 	obj->datum.string->deflate = be32 (u32);
810 	obj->datum.string->method = compressed;
811     }
812 
813     if (_csi_likely (len))
814 	scan_read (scan, src, obj->datum.string->string, len);
815     obj->datum.string->string[len] = '\0';
816 }
817 
818 static void
_scan_file(csi_t * ctx,csi_file_t * src)819 _scan_file (csi_t *ctx, csi_file_t *src)
820 {
821     csi_scanner_t *scan = &ctx->scanner;
822     int c, next;
823     union {
824 	int8_t i8;
825 	uint8_t u8;
826 	int16_t i16;
827 	uint16_t u16;
828 	int32_t i32;
829 	uint32_t u32;
830 	float f;
831     } u;
832     int deflate = 0;
833     int string_p;
834 
835 scan_none:
836     while ((c = csi_file_getc (src)) != EOF) {
837 	csi_object_t obj = { CSI_OBJECT_TYPE_NULL };
838 
839 	switch (c) {
840 	case 0xa:
841 	    scan->line_number++;
842 	case 0x0:
843 	case 0x9:
844 	case 0xc:
845 	case 0xd:
846 	case 0x20: /* ignore whitespace */
847 	    break;
848 
849 	case '%':
850 	    goto scan_comment;
851 
852 	case '(':
853 	    goto scan_string;
854 
855 	case '[': /* needs special case */
856 	case ']':
857 	case '{':
858 	case '}':
859 	    token_start (scan);
860 	    token_add_unchecked (scan, c);
861 	    token_end (ctx, scan, src);
862 	    goto scan_none;
863 
864 	case '<':
865 	    next = csi_file_getc (src);
866 	    switch (next) {
867 	    case EOF:
868 		csi_file_putc (src, '<');
869 		return;
870 	    case '<':
871 		/* dictionary name */
872 		token_start (scan);
873 		token_add_unchecked (scan, '<');
874 		token_add_unchecked (scan, '<');
875 		token_end (ctx, scan, src);
876 		goto scan_none;
877 	    case '|':
878 		deflate = 1;
879 	    case '~':
880 		goto scan_base85;
881 	    case '{':
882 		goto scan_base64;
883 	    default:
884 		csi_file_putc (src, next);
885 		goto scan_hex;
886 	    }
887 	    break;
888 
889 	    /* binary token */
890 #define MSB_INT8 128
891 #define MSB_UINT8 129
892 #define MSB_INT16 130
893 #define MSB_UINT16 131
894 #define MSB_INT32 132
895 #define LSB_INT8 MSB_INT8
896 #define LSB_UINT8 MSB_UINT8
897 #define LSB_INT16 133
898 #define LSB_UINT16 134
899 #define LSB_INT32 135
900 #define MSB_FLOAT32 140
901 #define LSB_FLOAT32 141
902 	case MSB_INT8:
903 	    scan_read (scan, src, &u.i8, 1);
904 	    csi_integer_new (&obj, u.i8);
905 	    break;
906 	case MSB_UINT8:
907 	    scan_read (scan, src, &u.u8, 1);
908 	    csi_integer_new (&obj, u.u8);
909 	    break;
910 	case MSB_INT16:
911 	    scan_read (scan, src, &u.i16, 2);
912 	    csi_integer_new (&obj, be16 (u.i16));
913 	    break;
914 	case LSB_INT16:
915 	    scan_read (scan, src, &u.i16, 2);
916 	    csi_integer_new (&obj, le16 (u.i16));
917 	    break;
918 	case MSB_UINT16:
919 	    scan_read (scan, src, &u.u16, 2);
920 	    csi_integer_new (&obj, be16 (u.u16));
921 	    break;
922 	case LSB_UINT16:
923 	    scan_read (scan, src, &u.u16, 2);
924 	    csi_integer_new (&obj, le16 (u.u16));
925 	    break;
926 	case MSB_INT32:
927 	    scan_read (scan, src, &u.i32, 4);
928 	    csi_integer_new (&obj, be32 (u.i32));
929 	    break;
930 	case LSB_INT32:
931 	    scan_read (scan, src, &u.i32, 4);
932 	    csi_integer_new (&obj, le32 (u.i32));
933 	    break;
934 
935 	case 136: /* 16.16 msb */
936 	    scan_read (scan, src, &u.i32, 4);
937 	    csi_real_new (&obj, be32 (u.i32) / 65536.);
938 	    break;
939 	case 137: /* 16.16 lsb */
940 	    scan_read (scan, src, &u.i32, 4);
941 	    csi_real_new (&obj, le32 (u.i32) / 65536.);
942 	    break;
943 	case 138: /* 24.8 msb */
944 	    scan_read (scan, src, &u.i32, 4);
945 	    csi_real_new (&obj, be32 (u.i32) / 256.);
946 	    break;
947 	case 139: /* 24.8 lsb */
948 	    scan_read (scan, src, &u.i32, 4);
949 	    csi_real_new (&obj, le32 (u.i32) / 256.);
950 	    break;
951 	case MSB_FLOAT32:
952 	    scan_read (scan, src, &u.i32, 4);
953 	    u.i32 = be32 (u.i32);
954 	    csi_real_new (&obj, u.f);
955 	    break;
956 	case LSB_FLOAT32:
957 	    scan_read (scan, src, &u.i32, 4);
958 	    u.i32 = le32 (u.i32);
959 	    csi_real_new (&obj, u.f);
960 	    break;
961 
962 #define STRING_1 142
963 #define STRING_2_MSB 144
964 #define STRING_2_LSB 146
965 #define STRING_4_MSB 148
966 #define STRING_4_LSB 150
967 #define STRING_DEFLATE 1
968 	case STRING_1:
969 	case STRING_1 | STRING_DEFLATE:
970 	    scan_read (scan, src, &u.u8, 1);
971 	    string_read (ctx, scan, src, u.u8, c & STRING_DEFLATE, &obj);
972 	    break;
973 	case STRING_2_MSB:
974 	case STRING_2_MSB | STRING_DEFLATE:
975 	    scan_read (scan, src, &u.u16, 2);
976 	    string_read (ctx, scan, src, be16 (u.u16),  c & STRING_DEFLATE, &obj);
977 	    break;
978 	case STRING_2_LSB:
979 	case STRING_2_LSB | STRING_DEFLATE:
980 	    scan_read (scan, src, &u.u16, 2);
981 	    string_read (ctx, scan, src, le16 (u.u16), c & STRING_DEFLATE, &obj);
982 	    break;
983 	case STRING_4_MSB:
984 	case STRING_4_MSB | STRING_DEFLATE:
985 	    scan_read (scan, src, &u.u32, 4);
986 	    string_read (ctx, scan, src, be32 (u.u32), c & STRING_DEFLATE, &obj);
987 	    break;
988 	case STRING_4_LSB:
989 	case STRING_4_LSB | STRING_DEFLATE:
990 	    scan_read (scan, src, &u.u32, 4);
991 	    string_read (ctx, scan, src, le32 (u.u32), c & STRING_DEFLATE, &obj);
992 	    break;
993 
994 #define OPCODE 152
995 	case OPCODE:
996 	    scan_read (scan, src, &u.u8, 1);
997 	    csi_operator_new (&obj, ctx->opcode[u.u8]);
998 	    break;
999 
1000 	case OPCODE | 1:
1001 	    scan_read (scan, src, &u.u8, 1);
1002 	    csi_operator_new (&obj, ctx->opcode[u.u8]);
1003 	    obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE;
1004 	    break;
1005 
1006 #define STRING_LZO 154
1007 	case STRING_LZO:
1008 	    scan_read (scan, src, &u.u32, 4);
1009 	    string_read (ctx, scan, src, be32 (u.u32), LZO, &obj);
1010 	    break;
1011 
1012 	    /* unassigned */
1013 	case 155:
1014 	case 156:
1015 	case 157:
1016 	case 158:
1017 	case 159:
1018 	    longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1019 
1020 	case '#': /* PDF 1.2 escape code */
1021 	    {
1022 		int c_hi = csi_file_getc (src);
1023 		int c_lo = csi_file_getc (src);
1024 		c = (hex_value (c_hi) << 4) | hex_value (c_lo);
1025 	    }
1026 	    /* fall-through */
1027 	default:
1028 	    token_start (scan);
1029 	    token_add_unchecked (scan, c);
1030 	    goto scan_token;
1031 	}
1032 
1033 	if (obj.type != CSI_OBJECT_TYPE_NULL) {
1034 	    cairo_status_t status;
1035 
1036 	    if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
1037 		status = csi_array_append (ctx,
1038 					   scan->build_procedure.datum.array,
1039 					   &obj);
1040 	    } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
1041 		status = scan_execute (ctx, &obj);
1042 		csi_object_free (ctx, &obj);
1043 	    } else {
1044 		status = scan_push (ctx, &obj);
1045 	    }
1046 	    if (_csi_unlikely (status))
1047 		longjmp (scan->jump_buffer, status);
1048 	}
1049     }
1050     return;
1051 
1052 scan_token:
1053     while ((c = csi_file_getc (src)) != EOF) {
1054 	switch (c) {
1055 	case 0xa:
1056 	    scan->line_number++;
1057 	    /* fall through */
1058 	case 0x0:
1059 	case 0x9:
1060 	case 0xc:
1061 	case 0xd:
1062 	case 0x20:
1063 	    token_end (ctx, scan, src);
1064 	    goto scan_none;
1065 
1066 	    /* syntax delimiters */
1067 	case '%':
1068 	    token_end (ctx, scan, src);
1069 	    goto scan_comment;
1070 	    /* syntax error? */
1071 	case '(':
1072 	    token_end (ctx, scan, src);
1073 	    goto scan_string;
1074 	    /* XXX syntax error? */
1075 	case ')':
1076 	    token_end (ctx, scan, src);
1077 	    goto scan_none;
1078 	case '/':
1079 	    /* need to special case '^//?' */
1080 	    if (scan->buffer.ptr > scan->buffer.base+1 ||
1081 		scan->buffer.base[0] != '/')
1082 	    {
1083 		token_end (ctx, scan, src);
1084 		token_start (scan);
1085 	    }
1086 	    token_add_unchecked (scan, '/');
1087 	    goto scan_token;
1088 
1089 	case '{':
1090 	case '}':
1091 	case ']':
1092 	    token_end (ctx, scan, src);
1093 	    token_start (scan);
1094 	    token_add_unchecked (scan, c);
1095 	    token_end (ctx, scan, src);
1096 	    goto scan_none;
1097 
1098 	case '<':
1099 	    csi_file_putc (src, '<');
1100 	    token_end (ctx, scan, src);
1101 	    goto scan_none;
1102 
1103 	case '#': /* PDF 1.2 escape code */
1104 	    {
1105 		int c_hi = csi_file_getc (src);
1106 		int c_lo = csi_file_getc (src);
1107 		c = (hex_value (c_hi) << 4) | hex_value (c_lo);
1108 	    }
1109 	    /* fall-through */
1110 	default:
1111 	    token_add (ctx, scan, c);
1112 	    break;
1113 	}
1114     }
1115     token_end (ctx, scan, src);
1116     return;
1117 
1118 scan_comment:
1119     /* discard until newline */
1120     while ((c = csi_file_getc (src)) != EOF) {
1121 	switch (c) {
1122 	case 0xa:
1123 	    scan->line_number++;
1124 	case 0xc:
1125 	    goto scan_none;
1126 	}
1127     }
1128     return;
1129 
1130 scan_string:
1131     buffer_reset (&scan->buffer);
1132     string_p = 1;
1133     while ((c = csi_file_getc (src)) != EOF) {
1134 	switch (c) {
1135 	case '\\': /* escape */
1136 	    next = csi_file_getc (src);
1137 	    switch (next) {
1138 	    case EOF:
1139 		longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1140 
1141 	    case 'n':
1142 		string_add (ctx, scan, '\n');
1143 		break;
1144 	    case 'r':
1145 		string_add (ctx, scan, '\r');
1146 		break;
1147 	    case 't':
1148 		string_add (ctx, scan, '\t');
1149 		break;
1150 	    case 'b':
1151 		string_add (ctx, scan, '\b');
1152 		break;
1153 	    case 'f':
1154 		string_add (ctx, scan, '\f');
1155 		break;
1156 	    case '\\':
1157 		string_add (ctx, scan, '\\');
1158 		break;
1159 	    case '(':
1160 		string_add (ctx, scan, '(');
1161 		break;
1162 	    case ')':
1163 		string_add (ctx, scan, ')');
1164 		break;
1165 
1166 	    case '0': case '1': case '2': case '3':
1167 	    case '4': case '5': case '6': case '7':
1168 		{ /* octal code: \d{1,3} */
1169 		    int i;
1170 
1171 		    c = next - '0';
1172 
1173 		    for (i = 0; i < 2; i++) {
1174 			next = csi_file_getc (src);
1175 			switch (next) {
1176 			case EOF:
1177 			    return;
1178 
1179 			case '0': case '1': case '2': case '3':
1180 			case '4': case '5': case '6': case '7':
1181 			    c = 8*c + next-'0';
1182 			    break;
1183 
1184 			default:
1185 			    csi_file_putc (src, next);
1186 			    goto octal_code_done;
1187 			}
1188 		    }
1189   octal_code_done:
1190 		    string_add (ctx, scan, c);
1191 		}
1192 		break;
1193 
1194 	    case 0xa:
1195 		/* skip the newline */
1196 		next = csi_file_getc (src); /* might be compound LFCR */
1197 		switch (next) {
1198 		case EOF:
1199 		    return;
1200 		case 0xc:
1201 		    break;
1202 		default:
1203 		    csi_file_putc (src, next);
1204 		    break;
1205 		}
1206 		scan->line_number++;
1207 		break;
1208 	    case 0xc:
1209 		break;
1210 
1211 	    default:
1212 		/* ignore the '\' */
1213 		break;
1214 	    }
1215 	    break;
1216 
1217 	case '(':
1218 	    string_p++;
1219 	    string_add (ctx, scan, c);
1220 	    break;
1221 
1222 	case ')':
1223 	    if (--string_p == 0) {
1224 		string_end (ctx, scan);
1225 		goto scan_none;
1226 	    }
1227 	    /* fall through */
1228 	default:
1229 	    string_add (ctx, scan, c);
1230 	    break;
1231 	}
1232     }
1233     longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1234 
1235 scan_hex:
1236     buffer_reset (&scan->buffer);
1237     scan->accumulator_count = 0;
1238     scan->accumulator = 0;
1239     while ((c = csi_file_getc (src)) != EOF) {
1240 	switch (c) {
1241 	case 0xa:
1242 	    scan->line_number++;
1243 	case 0x0:
1244 	case 0x9:
1245 	case 0xc:
1246 	case 0xd:
1247 	case 0x20: /* ignore whitespace */
1248 	    break;
1249 
1250 	case '>':
1251 	    hex_end (ctx, scan); /* fixup odd digit with '0' */
1252 	    goto scan_none;
1253 
1254 	case '0':
1255 	case '1':
1256 	case '2':
1257 	case '3':
1258 	case '4':
1259 	case '5':
1260 	case '6':
1261 	case '7':
1262 	case '8':
1263 	case '9':
1264 	case 'a':
1265 	case 'b':
1266 	case 'c':
1267 	case 'd':
1268 	case 'e':
1269 	case 'f':
1270 	case 'A':
1271 	case 'B':
1272 	case 'C':
1273 	case 'D':
1274 	case 'E':
1275 	case 'F':
1276 	    hex_add (ctx, scan, c);
1277 	    break;
1278 
1279 	default:
1280 	    longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1281 	}
1282     }
1283     longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1284 
1285 scan_base85:
1286     buffer_reset (&scan->buffer);
1287     scan->accumulator = 0;
1288     scan->accumulator_count = 0;
1289     while ((c = csi_file_getc (src)) != EOF) {
1290 	switch (c) {
1291 	case '~':
1292 	    next = csi_file_getc (src);
1293 	    switch (next) {
1294 	    case EOF:
1295 		return;
1296 
1297 	    case '>':
1298 		base85_end (ctx, scan, deflate);
1299 		deflate = 0;
1300 		goto scan_none;
1301 	    }
1302 	    csi_file_putc (src, next);
1303 
1304 	    /* fall-through */
1305 	default:
1306 	    base85_add (ctx, scan, c);
1307 	    break;
1308 	}
1309     }
1310     longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1311 
1312 scan_base64:
1313     buffer_reset (&scan->buffer);
1314     scan->accumulator = 0;
1315     scan->accumulator_count = 0;
1316     while ((c = csi_file_getc (src)) != EOF) {
1317 	switch (c) {
1318 	case '}':
1319 	    next = csi_file_getc (src);
1320 	    switch (next) {
1321 	    case EOF:
1322 		return;
1323 
1324 	    case '>':
1325 		base64_end (ctx, scan);
1326 		goto scan_none;
1327 	    }
1328 	    longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1329 
1330 	default:
1331 	    base64_add (ctx, scan, c);
1332 	    break;
1333 	}
1334     }
1335     longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT));
1336 }
1337 
1338 static csi_status_t
_scan_push(csi_t * ctx,csi_object_t * obj)1339 _scan_push (csi_t *ctx, csi_object_t *obj)
1340 {
1341     if (DEBUG_SCAN) {
1342 	fprintf (stderr, "push ");
1343 	fprintf_obj (stderr, ctx, obj);
1344     }
1345     return _csi_push_ostack (ctx, obj);
1346 }
1347 
1348 static csi_status_t
_scan_execute(csi_t * ctx,csi_object_t * obj)1349 _scan_execute (csi_t *ctx, csi_object_t *obj)
1350 {
1351     if (DEBUG_SCAN) {
1352 	fprintf (stderr, "exec ");
1353 	fprintf_obj (stderr, ctx, obj);
1354     }
1355     return csi_object_execute (ctx, obj);
1356 }
1357 
1358 csi_status_t
_csi_scanner_init(csi_t * ctx,csi_scanner_t * scanner)1359 _csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner)
1360 {
1361     csi_status_t status;
1362 
1363     memset (scanner, 0, sizeof (csi_scanner_t));
1364 
1365     status = buffer_init (ctx, &scanner->buffer);
1366     if (status)
1367 	return status;
1368 
1369     status = _csi_stack_init (ctx, &scanner->procedure_stack, 4);
1370     if (status)
1371 	return status;
1372 
1373     scanner->bind = 0;
1374     scanner->push = _scan_push;
1375     scanner->execute = _scan_execute;
1376 
1377     return CSI_STATUS_SUCCESS;
1378 }
1379 
1380 void
_csi_scanner_fini(csi_t * ctx,csi_scanner_t * scanner)1381 _csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner)
1382 {
1383     buffer_fini (ctx, &scanner->buffer);
1384     _csi_stack_fini (ctx, &scanner->procedure_stack);
1385     if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL)
1386 	csi_object_free (ctx, &scanner->build_procedure);
1387 }
1388 
1389 csi_status_t
_csi_scan_file(csi_t * ctx,csi_file_t * src)1390 _csi_scan_file (csi_t *ctx, csi_file_t *src)
1391 {
1392     csi_status_t status;
1393     int old_line_number;
1394 
1395     /* This function needs to be reentrant to handle recursive scanners.
1396      * i.e. one script executes a second.
1397      */
1398 
1399     if (ctx->scanner.depth++ == 0) {
1400 	if ((status = setjmp (ctx->scanner.jump_buffer))) {
1401 	    ctx->scanner.depth = 0;
1402 	    return status;
1403 	}
1404     }
1405 
1406     old_line_number = ctx->scanner.line_number;
1407     ctx->scanner.line_number = 0;
1408 
1409     _scan_file (ctx, src);
1410 
1411     ctx->scanner.line_number = old_line_number;
1412 
1413     --ctx->scanner.depth;
1414     return CSI_STATUS_SUCCESS;
1415 }
1416 
1417 struct _translate_closure {
1418     csi_dictionary_t *opcodes;
1419     cairo_write_func_t write_func;
1420     void *closure;
1421 };
1422 
1423 static csi_status_t
_translate_name(csi_t * ctx,csi_name_t name,csi_boolean_t executable,struct _translate_closure * closure)1424 _translate_name (csi_t *ctx,
1425 	         csi_name_t name,
1426 		 csi_boolean_t executable,
1427 		 struct _translate_closure *closure)
1428 {
1429     if (executable) {
1430 	csi_dictionary_entry_t *entry;
1431 	uint16_t u16;
1432 
1433 	/* Bind executable names.
1434 	 * XXX This may break some scripts that overload system operators.
1435 	 */
1436 	entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
1437 		                        (csi_hash_entry_t *) &name);
1438 	if (entry == NULL)
1439 	    goto STRING;
1440 
1441 	u16 = entry->value.datum.integer;
1442 	u16 = be16 (u16);
1443 	closure->write_func (closure->closure, (unsigned char *) &u16, 2);
1444     } else {
1445 	closure->write_func (closure->closure, (unsigned char *) "/", 1);
1446 STRING:
1447 	closure->write_func (closure->closure,
1448 		             (unsigned char *) name,
1449 			     strlen ((char *) name));
1450 	closure->write_func (closure->closure, (unsigned char *) "\n", 1);
1451     }
1452 
1453     return CSI_STATUS_SUCCESS;
1454 }
1455 
1456 static csi_status_t
_translate_operator(csi_t * ctx,csi_operator_t op,csi_boolean_t executable,struct _translate_closure * closure)1457 _translate_operator (csi_t *ctx,
1458 	             csi_operator_t op,
1459 		     csi_boolean_t executable,
1460 		     struct _translate_closure *closure)
1461 {
1462     csi_dictionary_entry_t *entry;
1463     uint16_t u16;
1464 
1465     entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
1466 	                            (csi_hash_entry_t *) &op);
1467     if (entry == NULL)
1468 	return _csi_error (CSI_STATUS_INVALID_SCRIPT);
1469 
1470     u16 = entry->value.datum.integer;
1471     if (! executable)
1472 	u16 += 1 << 8;
1473     u16 = be16 (u16);
1474     closure->write_func (closure->closure, (unsigned char *) &u16, 2);
1475 
1476     return CSI_STATUS_SUCCESS;
1477 }
1478 
1479 static csi_status_t
_translate_integer(csi_t * ctx,csi_integer_t i,struct _translate_closure * closure)1480 _translate_integer (csi_t *ctx,
1481 	            csi_integer_t i,
1482 		    struct _translate_closure *closure)
1483 {
1484     uint8_t hdr;
1485     union {
1486 	int8_t i8;
1487 	uint8_t u8;
1488 	int16_t i16;
1489 	uint16_t u16;
1490 	int32_t i32;
1491 	uint32_t u32;
1492     } u;
1493     int len;
1494 
1495 #if WORDS_BIGENDIAN
1496     if (i < INT16_MIN) {
1497 	hdr = MSB_INT32;
1498 	len = 4;
1499 	u.i32 = i;
1500     } else if (i < INT8_MIN) {
1501 	hdr = MSB_INT16;
1502 	len = 2;
1503 	u.i16 = i;
1504     } else if (i < 0) {
1505 	hdr = MSB_INT8;
1506 	len = 1;
1507 	u.i8 = i;
1508     } else if (i <= UINT8_MAX) {
1509 	hdr = MSB_UINT8;
1510 	len = 1;
1511 	u.u8 = i;
1512     } else if (i <= UINT16_MAX) {
1513 	hdr = MSB_UINT16;
1514 	len = 2;
1515 	u.u16 = i;
1516     } else {
1517 	hdr = MSB_INT32;
1518 	len = 4;
1519 	u.u32 = i;
1520     }
1521 #else
1522     if (i < INT16_MIN) {
1523 	hdr = LSB_INT32;
1524 	len = 4;
1525 	u.i32 = i;
1526     } else if (i < INT8_MIN) {
1527 	hdr = LSB_INT16;
1528 	len = 2;
1529 	u.i16 = i;
1530     } else if (i < 0) {
1531 	hdr = LSB_INT8;
1532 	len = 1;
1533 	u.i8 = i;
1534     } else if (i <= UINT8_MAX) {
1535 	hdr = LSB_UINT8;
1536 	len = 1;
1537 	u.u8 = i;
1538     } else if (i <= UINT16_MAX) {
1539 	hdr = LSB_UINT16;
1540 	len = 2;
1541 	u.u16 = i;
1542     } else {
1543 	hdr = LSB_INT32;
1544 	len = 4;
1545 	u.u32 = i;
1546     }
1547 #endif
1548 
1549     closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
1550     closure->write_func (closure->closure, (unsigned char *) &u, len);
1551 
1552     return CSI_STATUS_SUCCESS;
1553 }
1554 
1555 static csi_status_t
_translate_real(csi_t * ctx,csi_real_t real,struct _translate_closure * closure)1556 _translate_real (csi_t *ctx,
1557 	         csi_real_t real,
1558 		 struct _translate_closure *closure)
1559 {
1560     uint8_t hdr;
1561 
1562     if (real >= INT32_MIN && real <= INT32_MAX && (int) real == real)
1563 	return _translate_integer (ctx, real, closure);
1564 
1565 #if WORDS_BIGENDIAN
1566     hdr = MSB_FLOAT32;
1567 #else
1568     hdr = LSB_FLOAT32;
1569 #endif
1570     closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
1571     closure->write_func (closure->closure, (unsigned char *) &real, 4);
1572 
1573     return CSI_STATUS_SUCCESS;
1574 }
1575 
1576 static csi_status_t
_translate_string(csi_t * ctx,csi_string_t * string,struct _translate_closure * closure)1577 _translate_string (csi_t *ctx,
1578 	           csi_string_t *string,
1579 		   struct _translate_closure *closure)
1580 {
1581     uint8_t hdr;
1582     union {
1583 	uint8_t u8;
1584 	uint16_t u16;
1585 	uint32_t u32;
1586     } u;
1587     void *buf;
1588     unsigned long hdr_len, buf_len, deflate;
1589     int method;
1590 
1591     buf = string->string;
1592     buf_len = string->len;
1593     deflate = string->deflate;
1594     method = string->method;
1595 
1596 #if HAVE_LZO
1597     if (method == NONE && buf_len > 16) {
1598 	unsigned long mem_len = 2*string->len > LZO2A_999_MEM_COMPRESS ? 2*string->len : LZO2A_999_MEM_COMPRESS;
1599 	void *mem = malloc (mem_len);
1600 	void *work = malloc(LZO2A_999_MEM_COMPRESS);
1601 
1602 	if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
1603 				(lzo_bytep) mem, &mem_len,
1604 				work) == 0 &&
1605 	    8+2*mem_len < buf_len)
1606 	{
1607 	    method = LZO;
1608 	    deflate = buf_len;
1609 	    buf_len = mem_len;
1610 	    buf = mem;
1611 	}
1612 	else
1613 	{
1614 	    free (mem);
1615 	}
1616 
1617 	free (work);
1618     }
1619 #if HAVE_ZLIB
1620     if (method == ZLIB) {
1621 	buf_len = string->deflate;
1622 	buf = malloc (string->deflate);
1623 	if (uncompress ((Bytef *) buf, &buf_len,
1624 			(Bytef *) string->string, string->len) == Z_OK)
1625 	{
1626 	    assert(string->len > 0);
1627 	    if (buf_len <= 8 + 2*((unsigned long)string->len)) {
1628 		method = NONE;
1629 		deflate = 0;
1630 	    } else {
1631 		unsigned long mem_len = 2*string->deflate;
1632 		void *mem = malloc (mem_len);
1633 		void *work = malloc(LZO2A_999_MEM_COMPRESS);
1634 
1635 		if (lzo2a_999_compress ((lzo_bytep) buf, buf_len,
1636 					(lzo_bytep) mem, &mem_len,
1637 					work) == 0)
1638 		{
1639 		    if (8 + mem_len > buf_len) {
1640 			method = NONE;
1641 			deflate = 0;
1642 		    } else {
1643 			free (buf);
1644 			method = LZO;
1645 			deflate = buf_len;
1646 			buf_len = mem_len;
1647 			buf = mem;
1648 			assert(deflate);
1649 		    }
1650 		}
1651 		else
1652 		{
1653 		    free (buf);
1654 		    buf = string->string;
1655 		    buf_len = string->len;
1656 		}
1657 
1658 		free (work);
1659 	    }
1660 	}
1661 	else
1662 	{
1663 	    free (buf);
1664 	    buf = string->string;
1665 	    buf_len = string->len;
1666 	}
1667     }
1668 #endif
1669 #endif
1670 
1671     if (method == LZO) {
1672 	hdr = STRING_LZO;
1673 	u.u32 = to_be32 (buf_len);
1674 	hdr_len = 4;
1675     } else {
1676 #if WORDS_BIGENDIAN
1677 	if (buf_len <= UINT8_MAX) {
1678 	    hdr = STRING_1;
1679 	    u.u8 = buf_len;
1680 	    hdr_len = 1;
1681 	} else if (buf_len <= UINT16_MAX) {
1682 	    hdr = STRING_2_MSB;
1683 	    u.u16 = buf_len;
1684 	    hdr_len = 2;
1685 	} else {
1686 	    hdr = STRING_4_MSB;
1687 	    u.u32 = buf_len;
1688 	    hdr_len = 4;
1689 	}
1690 #else
1691 	if (buf_len <= UINT8_MAX) {
1692 	    hdr = STRING_1;
1693 	    u.u8 = buf_len;
1694 	    hdr_len = 1;
1695 	} else if (buf_len <= UINT16_MAX) {
1696 	    hdr = STRING_2_LSB;
1697 	    u.u16 = buf_len;
1698 	    hdr_len = 2;
1699 	} else {
1700 	    hdr = STRING_4_LSB;
1701 	    u.u32 = buf_len;
1702 	    hdr_len = 4;
1703 	}
1704 #endif
1705 	if (deflate) {
1706 	    assert (method == ZLIB);
1707 	    hdr |= STRING_DEFLATE;
1708 	}
1709     }
1710 
1711     closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
1712     closure->write_func (closure->closure, (unsigned char *) &u, hdr_len);
1713     if (deflate) {
1714 	uint32_t u32 = to_be32 (deflate);
1715 	closure->write_func (closure->closure, (unsigned char *) &u32, 4);
1716     }
1717     closure->write_func (closure->closure, (unsigned char *) buf, buf_len);
1718 
1719     if (buf != string->string)
1720 	free (buf);
1721 
1722     return CSI_STATUS_SUCCESS;
1723 }
1724 
1725 static csi_status_t
_translate_push(csi_t * ctx,csi_object_t * obj)1726 _translate_push (csi_t *ctx, csi_object_t *obj)
1727 {
1728     struct _translate_closure *closure = ctx->scanner.closure;
1729 
1730     if (0) {
1731 	fprintf (stderr, "push ");
1732 	fprintf_obj (stderr, ctx, obj);
1733     }
1734 
1735     switch (csi_object_get_type (obj)) {
1736     case CSI_OBJECT_TYPE_NAME:
1737 	return _translate_name (ctx, obj->datum.name, FALSE, closure);
1738 
1739     case CSI_OBJECT_TYPE_OPERATOR:
1740 	return _translate_operator (ctx, obj->datum.op, FALSE, closure);
1741 
1742     case CSI_OBJECT_TYPE_INTEGER:
1743 	return _translate_integer (ctx, obj->datum.integer, closure);
1744 
1745     case CSI_OBJECT_TYPE_REAL:
1746 	return _translate_real (ctx, obj->datum.real, closure);
1747 
1748     case CSI_OBJECT_TYPE_STRING:
1749 	return _translate_string (ctx, obj->datum.string, closure);
1750 
1751     case CSI_OBJECT_TYPE_NULL:
1752     case CSI_OBJECT_TYPE_BOOLEAN:
1753     case CSI_OBJECT_TYPE_MARK:
1754     case CSI_OBJECT_TYPE_ARRAY:
1755     case CSI_OBJECT_TYPE_DICTIONARY:
1756     case CSI_OBJECT_TYPE_FILE:
1757     case CSI_OBJECT_TYPE_MATRIX:
1758     case CSI_OBJECT_TYPE_CONTEXT:
1759     case CSI_OBJECT_TYPE_FONT:
1760     case CSI_OBJECT_TYPE_PATTERN:
1761     case CSI_OBJECT_TYPE_SCALED_FONT:
1762     case CSI_OBJECT_TYPE_SURFACE:
1763 	longjmp (ctx->scanner.jump_buffer,  _csi_error (CSI_STATUS_INVALID_SCRIPT));
1764 	break;
1765     }
1766 
1767     csi_object_free (ctx, obj);
1768     return CSI_STATUS_SUCCESS;
1769 }
1770 
1771 static csi_status_t
_translate_execute(csi_t * ctx,csi_object_t * obj)1772 _translate_execute (csi_t *ctx, csi_object_t *obj)
1773 {
1774     struct _translate_closure *closure = ctx->scanner.closure;
1775 
1776     if (0) {
1777 	fprintf (stderr, "exec ");
1778 	fprintf_obj (stderr, ctx, obj);
1779     }
1780 
1781     switch (csi_object_get_type (obj)) {
1782     case CSI_OBJECT_TYPE_NAME:
1783 	return _translate_name (ctx, obj->datum.name, TRUE, closure);
1784 
1785     case CSI_OBJECT_TYPE_OPERATOR:
1786 	return _translate_operator (ctx, obj->datum.op, TRUE, closure);
1787 
1788     case CSI_OBJECT_TYPE_INTEGER:
1789 	return _translate_integer (ctx, obj->datum.integer, closure);
1790 
1791     case CSI_OBJECT_TYPE_REAL:
1792 	return _translate_real (ctx, obj->datum.real, closure);
1793 
1794     case CSI_OBJECT_TYPE_STRING:
1795 	return _translate_string (ctx, obj->datum.string, closure);
1796 
1797     case CSI_OBJECT_TYPE_NULL:
1798     case CSI_OBJECT_TYPE_BOOLEAN:
1799     case CSI_OBJECT_TYPE_MARK:
1800     case CSI_OBJECT_TYPE_ARRAY:
1801     case CSI_OBJECT_TYPE_DICTIONARY:
1802     case CSI_OBJECT_TYPE_FILE:
1803     case CSI_OBJECT_TYPE_MATRIX:
1804     case CSI_OBJECT_TYPE_CONTEXT:
1805     case CSI_OBJECT_TYPE_FONT:
1806     case CSI_OBJECT_TYPE_PATTERN:
1807     case CSI_OBJECT_TYPE_SCALED_FONT:
1808     case CSI_OBJECT_TYPE_SURFACE:
1809 	longjmp (ctx->scanner.jump_buffer,  _csi_error (CSI_STATUS_INVALID_SCRIPT));
1810 	break;
1811     }
1812 
1813     return CSI_STATUS_SUCCESS;
1814 }
1815 
1816 static csi_status_t
build_opcodes(csi_t * ctx,csi_dictionary_t ** out)1817 build_opcodes (csi_t *ctx, csi_dictionary_t **out)
1818 {
1819     csi_object_t obj;
1820     csi_dictionary_t *dict;
1821     const csi_operator_def_t *def;
1822     csi_status_t status;
1823     int opcode = OPCODE << 8;
1824 
1825     status = csi_dictionary_new (ctx, &obj);
1826     if (_csi_unlikely (status))
1827 	return status;
1828 
1829     dict = obj.datum.dictionary;
1830 
1831     csi_integer_new (&obj, opcode++);
1832     status = csi_dictionary_put (ctx, dict, 0, &obj);
1833     if (_csi_unlikely (status))
1834 	goto FAIL;
1835 
1836     for (def = _csi_operators (); def->name != NULL; def++) {
1837 	csi_object_t name;
1838 	csi_dictionary_entry_t *entry;
1839 	int code;
1840 
1841 	entry = _csi_hash_table_lookup (&dict->hash_table,
1842 		                        (csi_hash_entry_t *) &def->op);
1843 	if (entry == NULL) {
1844 	    code = opcode++;
1845 	    csi_integer_new (&obj, code);
1846 	    status = csi_dictionary_put (ctx, dict, (csi_name_t) def->op, &obj);
1847 	    if (_csi_unlikely (status))
1848 		goto FAIL;
1849 	} else {
1850 	    code = entry->value.datum.integer;
1851 	    csi_integer_new (&obj, code);
1852 	}
1853 	assert (ctx->opcode[code & 0xff] == def->op);
1854 
1855 	status = csi_name_new_static (ctx, &name, def->name);
1856 	if (_csi_unlikely (status))
1857 	    goto FAIL;
1858 
1859 	status = csi_dictionary_put (ctx, dict, name.datum.name, &obj);
1860 	if (_csi_unlikely (status))
1861 	    goto FAIL;
1862     }
1863 
1864     *out = dict;
1865     return CSI_STATUS_SUCCESS;
1866 
1867 FAIL:
1868     csi_dictionary_free (ctx, dict);
1869     return status;
1870 }
1871 
1872 csi_status_t
_csi_translate_file(csi_t * ctx,csi_file_t * file,cairo_write_func_t write_func,void * closure)1873 _csi_translate_file (csi_t *ctx,
1874 	             csi_file_t *file,
1875 		     cairo_write_func_t write_func,
1876 		     void *closure)
1877 {
1878     csi_status_t status;
1879     struct _translate_closure translator;
1880 
1881     if ((status = setjmp (ctx->scanner.jump_buffer)))
1882 	return status;
1883 
1884     status = build_opcodes (ctx, &translator.opcodes);
1885     if (_csi_unlikely (status))
1886 	return status;
1887 
1888     translator.write_func = write_func;
1889     translator.closure = closure;
1890     ctx->scanner.closure = &translator;
1891 
1892     ctx->scanner.bind = 1;
1893     ctx->scanner.push = _translate_push;
1894     ctx->scanner.execute = _translate_execute;
1895 
1896     _scan_file (ctx, file);
1897 
1898     ctx->scanner.bind = 0;
1899     ctx->scanner.push = _scan_push;
1900     ctx->scanner.execute = _scan_execute;
1901 
1902     csi_dictionary_free (ctx, translator.opcodes);
1903 
1904     return CSI_STATUS_SUCCESS;
1905 }
1906