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