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