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