[cairo-commit] util/cairo-script
Chris Wilson
ickle at kemper.freedesktop.org
Sat Jul 4 07:29:30 PDT 2009
util/cairo-script/Makefile.am | 5
util/cairo-script/cairo-script-file.c | 44 +
util/cairo-script/cairo-script-interpreter.c | 85 +-
util/cairo-script/cairo-script-interpreter.h | 9
util/cairo-script/cairo-script-objects.c | 8
util/cairo-script/cairo-script-operators.c | 2
util/cairo-script/cairo-script-private.h | 27
util/cairo-script/cairo-script-scanner.c | 1059 +++++++++++++++++++--------
8 files changed, 906 insertions(+), 333 deletions(-)
New commits:
commit 23648e2fdfefba4df08bc854d725758209998e1f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jul 3 00:40:32 2009 +0100
[script] Prototypical binary translator
Hook into the scanner to write out binary version of the tokenized
objects -- note we bind executable names (i.e. check to see if is an
operator and substitute the name with an operator -- this breaks
overloading of operators by scripts).
By converting scripts to a binary form, they are more compact and
execute faster:
firefox-world-map.trace 526850146 bytes
bound.trace 275187755 bytes
[ # ] backend test min(s) median(s) stddev. count
[ 0] null bound 34.481 34.741 0.68% 3/3
[ 1] null firefox-world-map 89.635 89.716 0.19% 3/3
[ 0] drm bound 79.304 79.350 0.61% 3/3
[ 1] drm firefox-world-map 135.380 135.475 0.58% 3/3
[ 0] image bound 95.819 96.258 2.85% 3/3
[ 1] image firefox-world-map 156.889 156.935 1.36% 3/3
[ 0] xlib bound 539.130 550.220 1.40% 3/3
[ 1] xlib firefox-world-map 596.244 613.487 1.74% 3/3
This trace has a lot of complex paths and the use of binary floating point
reduces the file size by about 50%, with a commensurate reduction in scan
time and significant reduction in operator lookup overhead. Note that this
test is still IO/CPU bound on my i915 with its pitifully slow flash...
diff --git a/util/cairo-script/Makefile.am b/util/cairo-script/Makefile.am
index 644185b..c742cda 100644
--- a/util/cairo-script/Makefile.am
+++ b/util/cairo-script/Makefile.am
@@ -1,7 +1,7 @@
SUBDIRS = examples
lib_LTLIBRARIES = libcairo-script-interpreter.la
-EXTRA_PROGRAMS = csi-replay csi-exec
+EXTRA_PROGRAMS = csi-replay csi-exec csi-bind
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src
@@ -27,5 +27,8 @@ csi_replay_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.l
csi_exec_SOURCES = csi-exec.c
csi_exec_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+csi_bind_SOURCES = csi-bind.c
+csi_bind_LDADD = libcairo-script-interpreter.la $(top_builddir)/src/libcairo.la $(CAIRO_LIBS)
+
EXTRA_DIST = \
COPYING
diff --git a/util/cairo-script/cairo-script-file.c b/util/cairo-script/cairo-script-file.c
index a330d0b..18b5b86 100644
--- a/util/cairo-script/cairo-script-file.c
+++ b/util/cairo-script/cairo-script-file.c
@@ -40,6 +40,8 @@
#define CHUNK_SIZE 32768
+#define OWN_STREAM 0x1
+
csi_status_t
csi_file_new (csi_t *ctx,
csi_object_t *obj,
@@ -56,6 +58,7 @@ csi_file_new (csi_t *ctx,
file->data = NULL;
file->type = STDIO;
+ file->flags = OWN_STREAM;
file->src = fopen (path, mode);
if (file->src == NULL) {
_csi_slab_free (ctx, file, sizeof (csi_file_t));
@@ -76,6 +79,42 @@ csi_file_new (csi_t *ctx,
}
csi_status_t
+csi_file_new_for_stream (csi_t *ctx,
+ csi_object_t *obj,
+ FILE *stream)
+{
+ csi_file_t *file;
+
+ file = _csi_slab_alloc (ctx, sizeof (csi_file_t));
+ if (file == NULL)
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+
+ file->base.type = CSI_OBJECT_TYPE_FILE;
+ file->base.ref = 1;
+
+ file->data = NULL;
+ file->type = STDIO;
+ file->flags = 0;
+ file->src = stream;
+ if (file->src == NULL) {
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+ return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND);
+ }
+
+ file->data = _csi_alloc (ctx, CHUNK_SIZE);
+ if (file->data == NULL) {
+ _csi_slab_free (ctx, file, sizeof (csi_file_t));
+ return _csi_error (CAIRO_STATUS_NO_MEMORY);
+ }
+ file->bp = file->data;
+ file->rem = 0;
+
+ obj->type = CSI_OBJECT_TYPE_FILE;
+ obj->datum.file = file;
+ return CAIRO_STATUS_SUCCESS;
+}
+
+csi_status_t
csi_file_new_for_bytes (csi_t *ctx,
csi_object_t *obj,
const char *bytes,
@@ -727,7 +766,7 @@ csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard)
csi_status_t
_csi_file_execute (csi_t *ctx, csi_file_t *obj)
{
- return _csi_scan_file (ctx, &ctx->scanner, obj);
+ return _csi_scan_file (ctx, obj);
}
int
@@ -917,7 +956,8 @@ csi_file_close (csi_t *ctx, csi_file_t *file)
switch (file->type) {
case STDIO:
- fclose (file->src);
+ if (file->flags & OWN_STREAM)
+ fclose (file->src);
break;
case BYTES:
if (file->src != file->data) {
diff --git a/util/cairo-script/cairo-script-interpreter.c b/util/cairo-script/cairo-script-interpreter.c
index 16283e2..44c33f3 100644
--- a/util/cairo-script/cairo-script-interpreter.c
+++ b/util/cairo-script/cairo-script-interpreter.c
@@ -40,6 +40,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <assert.h>
#ifndef MAX
#define MAX(a,b) (((a)>=(b))?(a):(b))
@@ -261,10 +262,11 @@ _init_dictionaries (csi_t *ctx)
csi_status_t status;
csi_stack_t *stack;
csi_object_t obj;
- csi_dictionary_t *dict;
+ csi_dictionary_t *dict, *opcodes;
const csi_operator_def_t *odef;
const csi_integer_constant_def_t *idef;
const csi_real_constant_def_t *rdef;
+ unsigned n;
stack = &ctx->dstack;
@@ -283,12 +285,37 @@ _init_dictionaries (csi_t *ctx)
dict = obj.datum.dictionary;
+ status = csi_dictionary_new (ctx, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ opcodes = obj.datum.dictionary;
+
+ n = 0;
+ csi_integer_new (&obj, n);
+ status = csi_dictionary_put (ctx, opcodes, 0, &obj);
+ if (_csi_unlikely (status))
+ return status;
+ ctx->opcode[n++] = NULL;
+
/* fill systemdict with operators */
for (odef = _csi_operators (); odef->name != NULL; odef++) {
status = _add_operator (ctx, dict, odef);
if (_csi_unlikely (status))
return status;
+
+ if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) {
+ csi_integer_new (&obj, n);
+ status = csi_dictionary_put (ctx,
+ opcodes, (csi_name_t) odef->op, &obj);
+ if (_csi_unlikely (status))
+ return status;
+
+ assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0]));
+ ctx->opcode[n++] = odef->op;
+ }
}
+ csi_dictionary_free (ctx, opcodes);
/* add constants */
for (idef = _csi_integer_constants (); idef->name != NULL; idef++) {
@@ -365,6 +392,8 @@ _csi_init (csi_t *ctx)
{
csi_status_t status;
+ memset (ctx, 0, sizeof (*ctx));
+
ctx->status = CSI_STATUS_SUCCESS;
ctx->ref_count = 1;
@@ -391,7 +420,7 @@ FAIL:
}
static void
-_csi_fini (csi_t *ctx)
+_csi_finish (csi_t *ctx)
{
_csi_stack_fini (ctx, &ctx->ostack);
_csi_stack_fini (ctx, &ctx->dstack);
@@ -494,7 +523,7 @@ cairo_script_interpreter_create (void)
{
csi_t *ctx;
- ctx = calloc (1, sizeof (csi_t));
+ ctx = malloc (sizeof (csi_t));
if (ctx == NULL)
return (csi_t *) &_csi_nil;
@@ -580,7 +609,7 @@ cairo_script_interpreter_finish (csi_t *ctx)
status = ctx->status;
if (! ctx->finished) {
- _csi_fini (ctx);
+ _csi_finish (ctx);
ctx->finished = 1;
} else if (status == CAIRO_STATUS_SUCCESS) {
status = ctx->status = CSI_STATUS_INTERPRETER_FINISHED;
@@ -589,17 +618,11 @@ cairo_script_interpreter_finish (csi_t *ctx)
return status;
}
-cairo_status_t
-cairo_script_interpreter_destroy (csi_t *ctx)
+static void
+_csi_fini (csi_t *ctx)
{
- csi_status_t status;
-
- status = ctx->status;
- if (--ctx->ref_count)
- return status;
-
if (! ctx->finished)
- _csi_fini (ctx);
+ _csi_finish (ctx);
if (ctx->free_array != NULL)
csi_array_free (ctx, ctx->free_array);
@@ -610,8 +633,44 @@ cairo_script_interpreter_destroy (csi_t *ctx)
_csi_slab_fini (ctx);
_csi_perm_fini (ctx);
+}
+
+cairo_status_t
+cairo_script_interpreter_destroy (csi_t *ctx)
+{
+ csi_status_t status;
+
+ status = ctx->status;
+ if (--ctx->ref_count)
+ return status;
+
+ _csi_fini (ctx);
free (ctx);
return status;
}
slim_hidden_def (cairo_script_interpreter_destroy);
+
+cairo_status_t
+cairo_script_interpreter_translate_stream (FILE *stream,
+ cairo_write_func_t write_func,
+ void *closure)
+{
+ csi_t ctx;
+ csi_object_t src;
+ csi_status_t status;
+
+ _csi_init (&ctx);
+
+ status = csi_file_new_for_stream (&ctx, &src, stream);
+ if (status)
+ goto BAIL;
+
+ status = _csi_translate_file (&ctx, src.datum.file, write_func, closure);
+
+BAIL:
+ csi_object_free (&ctx, &src);
+ _csi_fini (&ctx);
+
+ return status;
+}
diff --git a/util/cairo-script/cairo-script-interpreter.h b/util/cairo-script/cairo-script-interpreter.h
index a500467..b7950aa 100644
--- a/util/cairo-script/cairo-script-interpreter.h
+++ b/util/cairo-script/cairo-script-interpreter.h
@@ -37,6 +37,7 @@
#define CAIRO_SCRIPT_INTERPRETER_H
#include <cairo.h>
+#include <stdio.h>
CAIRO_BEGIN_DECLS
@@ -45,7 +46,8 @@ typedef struct _cairo_script_interpreter cairo_script_interpreter_t;
/* XXX expose csi_dictionary_t and pass to hooks */
typedef void
(*csi_destroy_func_t) (void *closure,
- void *ptr);
+ void *ptr);
+
typedef cairo_surface_t *
(*csi_surface_create_func_t) (void *closure,
cairo_content_t content,
@@ -100,6 +102,11 @@ cairo_script_interpreter_finish (cairo_script_interpreter_t *ctx);
cairo_public cairo_status_t
cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx);
+cairo_public cairo_status_t
+cairo_script_interpreter_translate_stream (FILE *stream,
+ cairo_write_func_t write_func,
+ void *closure);
+
CAIRO_END_DECLS
#endif /*CAIRO_SCRIPT_INTERPRETER_H*/
diff --git a/util/cairo-script/cairo-script-objects.c b/util/cairo-script/cairo-script-objects.c
index c48f720..784376b 100644
--- a/util/cairo-script/cairo-script-objects.c
+++ b/util/cairo-script/cairo-script-objects.c
@@ -502,8 +502,10 @@ csi_string_new (csi_t *ctx,
ctx->free_string = NULL;
}
- memcpy (string->string, str, len);
- string->string[len] = '\0';
+ if (str != NULL) {
+ memcpy (string->string, str, len);
+ string->string[len] = '\0';
+ }
string->len = len;
string->base.type = CSI_OBJECT_TYPE_STRING;
@@ -555,7 +557,7 @@ _csi_string_execute (csi_t *ctx, csi_string_t *string)
if (_csi_unlikely (status))
return status;
- status = _csi_scan_file (ctx, &ctx->scanner, obj.datum.file);
+ status = _csi_scan_file (ctx, obj.datum.file);
csi_object_free (ctx, &obj);
return status;
diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 407afae..da68b1b 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -5440,7 +5440,7 @@ _defs[] = {
{ "arc", _arc },
{ "arc-negative", _arc_negative },
{ "arc-", _arc_negative },
- //{ "arc-to", NULL },
+ { "arc-to", NULL },
{ "array", _array },
{ "astore", NULL },
{ "atan", NULL },
diff --git a/util/cairo-script/cairo-script-private.h b/util/cairo-script/cairo-script-private.h
index c5c3b59..504218d 100644
--- a/util/cairo-script/cairo-script-private.h
+++ b/util/cairo-script/cairo-script-private.h
@@ -404,6 +404,7 @@ struct _csi_file {
PROCEDURE,
FILTER
} type;
+ unsigned int flags;
void *src;
void *data;
uint8_t *bp;
@@ -426,14 +427,9 @@ struct _csi_scanner {
jmp_buf jmpbuf;
int depth;
- enum {
- NONE,
- TOKEN,
- COMMENT,
- STRING,
- HEX,
- BASE85
- } state;
+ csi_status_t (*push) (csi_t *ctx, csi_object_t *obj);
+ csi_status_t (*execute) (csi_t *ctx, csi_object_t *obj);
+ void *closure;
csi_buffer_t buffer;
csi_stack_t procedure_stack;
@@ -478,6 +474,8 @@ struct _cairo_script_interpreter {
csi_dictionary_t *free_dictionary;
csi_string_t *free_string;
+ csi_operator_t opcode[256];
+
/* caches of live data */
csi_list_t *_images;
csi_list_t *_faces;
@@ -506,6 +504,11 @@ csi_file_new (csi_t *ctx,
const char *path, const char *mode);
csi_private csi_status_t
+csi_file_new_for_stream (csi_t *ctx,
+ csi_object_t *obj,
+ FILE *stream);
+
+csi_private csi_status_t
csi_file_new_for_bytes (csi_t *ctx,
csi_object_t *obj,
const char *bytes,
@@ -803,7 +806,13 @@ csi_private csi_status_t
_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner);
csi_private csi_status_t
-_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src);
+_csi_scan_file (csi_t *ctx, csi_file_t *src);
+
+csi_private csi_status_t
+_csi_translate_file (csi_t *ctx,
+ csi_file_t *file,
+ cairo_write_func_t write_func,
+ void *closure);
csi_private void
_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner);
diff --git a/util/cairo-script/cairo-script-scanner.c b/util/cairo-script/cairo-script-scanner.c
index 9cc2ce9..dd89826 100644
--- a/util/cairo-script/cairo-script-scanner.c
+++ b/util/cairo-script/cairo-script-scanner.c
@@ -38,6 +38,7 @@
#include <math.h> /* pow */
#include <stdio.h> /* EOF */
#include <string.h> /* memset */
+#include <assert.h>
/*
* whitespace:
@@ -56,6 +57,90 @@
* % = 25 - comment
*/
+static void
+fprintf_obj (FILE *stream, csi_t *ctx, const csi_object_t *obj)
+{
+ switch (csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_NULL:
+ fprintf (stream, "NULL\n");
+ break;
+
+ /* atomics */
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ fprintf (stream, "boolean: %s\n",
+ obj->datum.boolean ? "true" : "false");
+ break;
+ case CSI_OBJECT_TYPE_INTEGER:
+ fprintf (stream, "integer: %ld\n", obj->datum.integer);
+ break;
+ case CSI_OBJECT_TYPE_MARK:
+ fprintf (stream, "mark\n");
+ break;
+ case CSI_OBJECT_TYPE_NAME:
+ fprintf (stream, "name: %s\n", (char *) obj->datum.name);
+ break;
+ case CSI_OBJECT_TYPE_OPERATOR:
+ fprintf (stream, "operator: %p\n", obj->datum.ptr);
+ break;
+ case CSI_OBJECT_TYPE_REAL:
+ fprintf (stream, "real: %g\n", obj->datum.real);
+ break;
+
+ /* compound */
+ case CSI_OBJECT_TYPE_ARRAY:
+ fprintf (stream, "array\n");
+ break;
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ fprintf (stream, "dictionary\n");
+ break;
+ case CSI_OBJECT_TYPE_FILE:
+ fprintf (stream, "file\n");
+ break;
+ case CSI_OBJECT_TYPE_MATRIX:
+ fprintf (stream, "matrix: [%g %g %g %g %g %g]\n",
+ obj->datum.matrix->matrix.xx,
+ obj->datum.matrix->matrix.yx,
+ obj->datum.matrix->matrix.xy,
+ obj->datum.matrix->matrix.yy,
+ obj->datum.matrix->matrix.x0,
+ obj->datum.matrix->matrix.y0);
+ break;
+ case CSI_OBJECT_TYPE_STRING:
+ fprintf (stream, "string: len=%ld\n", obj->datum.string->len);
+ break;
+
+ /* cairo */
+ case CSI_OBJECT_TYPE_CONTEXT:
+ fprintf (stream, "context\n");
+ break;
+ case CSI_OBJECT_TYPE_FONT:
+ fprintf (stream, "font\n");
+ break;
+ case CSI_OBJECT_TYPE_PATTERN:
+ fprintf (stream, "pattern\n");
+ break;
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ fprintf (stream, "scaled-font\n");
+ break;
+ case CSI_OBJECT_TYPE_SURFACE:
+ fprintf (stream, "surface\n");
+ break;
+ }
+}
+
+/* takes ownership of obj */
+static inline csi_status_t
+scan_push (csi_t *ctx, csi_object_t *obj)
+{
+ return ctx->scanner.push (ctx, obj);
+}
+
+static inline csi_status_t
+scan_execute (csi_t *ctx, csi_object_t *obj)
+{
+ return ctx->scanner.execute (ctx, obj);
+}
+
static cairo_status_t
buffer_init (csi_t *ctx, csi_buffer_t *buffer)
{
@@ -80,7 +165,7 @@ buffer_fini (csi_t *ctx, csi_buffer_t *buffer)
_csi_free (ctx, buffer->base);
}
-static inline void
+static void
_buffer_grow (csi_t *ctx, csi_scanner_t *scan)
{
int newsize;
@@ -121,16 +206,9 @@ buffer_reset (csi_buffer_t *buffer)
buffer->ptr = buffer->base;
}
-static inline void
-reset (csi_scanner_t *scan)
-{
- scan->state = NONE;
-}
-
static void
token_start (csi_scanner_t *scan)
{
- scan->state = TOKEN;
buffer_reset (&scan->buffer);
}
@@ -344,7 +422,6 @@ token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
longjmp (scan->jmpbuf, status);
scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE;
- reset (scan);
return;
} else if (s[0] == '}') {
if (_csi_unlikely
@@ -362,13 +439,12 @@ token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
scan->build_procedure = *next;
scan->procedure_stack.len--;
} else {
- status = _csi_push_ostack (ctx, &scan->build_procedure);
+ status = scan_push (ctx, &scan->build_procedure);
scan->build_procedure.type = CSI_OBJECT_TYPE_NULL;
}
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
- reset (scan);
return;
}
@@ -395,43 +471,21 @@ token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
}
/* consume whitespace after token, before calling the interpreter */
- reset (scan);
-
if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
status = csi_array_append (ctx,
scan->build_procedure.datum.array,
&obj);
} else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
- status = csi_object_execute (ctx, &obj);
+ status = scan_execute (ctx, &obj);
+ csi_object_free (ctx, &obj);
} else {
- status = _csi_push_ostack (ctx, &obj);
+ status = scan_push (ctx, &obj);
}
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
}
static void
-comment_start (csi_scanner_t *scan)
-{
- /* XXX check for '!' interpreter mode?, '%' dsc setup? */
- scan->state = COMMENT;
-}
-
-static void
-comment_end (csi_scanner_t *scan)
-{
- reset (scan);
-}
-
-static void
-string_start (csi_scanner_t *scan)
-{
- scan->state = STRING;
- scan->string_p = 1;
- buffer_reset (&scan->buffer);
-}
-
-static void
string_inc_p (csi_scanner_t *scan)
{
scan->string_p++;
@@ -468,21 +522,9 @@ string_end (csi_t *ctx, csi_scanner_t *scan)
scan->build_procedure.datum.array,
&obj);
else
- status = _csi_push_ostack (ctx, &obj);
+ status = scan_push (ctx, &obj);
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
-
- reset (scan);
-}
-
-static void
-hex_start (csi_scanner_t *scan)
-{
- scan->state = HEX;
- scan->accumulator_count = 0;
- scan->accumulator = 0;
-
- buffer_reset (&scan->buffer);
}
static int
@@ -537,21 +579,9 @@ hex_end (csi_t *ctx, csi_scanner_t *scan)
scan->build_procedure.datum.array,
&obj);
else
- status = _csi_push_ostack (ctx, &obj);
+ status = scan_push (ctx, &obj);
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
-
- reset (scan);
-}
-
-static void
-base85_start (csi_scanner_t *scan)
-{
- scan->state = BASE85;
- scan->accumulator = 0;
- scan->accumulator_count = 0;
-
- buffer_reset (&scan->buffer);
}
static void
@@ -627,24 +657,63 @@ base85_end (csi_t *ctx, csi_scanner_t *scan)
scan->build_procedure.datum.array,
&obj);
else
- status = _csi_push_ostack (ctx, &obj);
+ status = scan_push (ctx, &obj);
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
+}
- reset (scan);
+static void
+scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len)
+{
+ uint8_t *data = ptr;
+ while (len) {
+ int ret = csi_file_read (src, data, len);
+ if (_csi_unlikely (ret == 0))
+ longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_READ_ERROR));
+ data += ret;
+ len -= ret;
+ }
}
-static int
-scan_none (csi_t *ctx,
- csi_scanner_t *scan,
- csi_file_t *src)
+static void
+string_read (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src, int len, csi_object_t *obj)
{
+ csi_status_t status;
+
+ status = csi_string_new (ctx, obj, NULL, len);
+ if (_csi_unlikely (status))
+ longjmp (scan->jmpbuf, status);
+
+ scan_read (scan, src, obj->datum.string->string, len);
+}
+
+#if WORDS_BIGENDIAN
+#define le16(x) bswap_16 (x)
+#define le32(x) bswap_32 (x)
+#define be16(x) x
+#define be32(x) x
+#else
+#define le16(x) x
+#define le32(x) x
+#define be16(x) bswap_16 (x)
+#define be32(x) bswap_32 (x)
+#endif
+static void
+_scan_file (csi_t *ctx, csi_file_t *src)
+{
+ csi_scanner_t *scan = &ctx->scanner;
int c, next;
union {
- int i;
+ int8_t i8;
+ uint8_t u8;
+ int16_t i16;
+ uint16_t u16;
+ int32_t i32;
+ uint32_t u32;
float f;
} u;
+scan_none:
while ((c = csi_file_getc (src)) != EOF) {
csi_object_t obj = { CSI_OBJECT_TYPE_NULL };
@@ -659,12 +728,10 @@ scan_none (csi_t *ctx,
break;
case '%':
- comment_start (scan);
- return 1;
+ goto scan_comment;
case '(':
- string_start (scan);
- return 1;
+ goto scan_string;
case '[': /* needs special case */
case ']':
@@ -673,88 +740,141 @@ scan_none (csi_t *ctx,
token_start (scan);
token_add_unchecked (scan, c);
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
case '<':
next = csi_file_getc (src);
switch (next) {
case EOF:
csi_file_putc (src, '<');
- return 0;
+ return;
case '<':
/* dictionary name */
token_start (scan);
token_add_unchecked (scan, '<');
token_add_unchecked (scan, '<');
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
case '~':
- base85_start (scan);
- return 1;
+ goto scan_base85;
default:
csi_file_putc (src, next);
- hex_start (scan);
- return 1;
+ goto scan_hex;
}
break;
/* binary token */
- case 128:
- case 129:
- case 130:
- case 131:
- /* binary object sequence */
+#define MSB_INT8 128
+#define MSB_UINT8 129
+#define MSB_INT16 130
+#define MSB_UINT16 131
+#define MSB_INT32 132
+#define LSB_INT8 MSB_INT8
+#define LSB_UINT8 MSB_UINT8
+#define LSB_INT16 133
+#define LSB_UINT16 134
+#define LSB_INT32 135
+#define MSB_FLOAT32 140
+#define LSB_FLOAT32 141
+ case MSB_INT8:
+ scan_read (scan, src, &u.i8, 1);
+ csi_integer_new (&obj, u.i8);
break;
- case 132: /* 32-bit integer, MSB */
+ case MSB_UINT8:
+ scan_read (scan, src, &u.u8, 1);
+ csi_integer_new (&obj, u.u8);
break;
- case 133: /* 32-bit integer, LSB */
+ case MSB_INT16:
+ scan_read (scan, src, &u.i16, 2);
+ csi_integer_new (&obj, be16 (u.i16));
break;
- case 134: /* 16-bit integer, MSB */
+ case LSB_INT16:
+ scan_read (scan, src, &u.i16, 2);
+ csi_integer_new (&obj, le16 (u.i16));
break;
- case 135: /* 16-bit integer, LSB */
+ case MSB_UINT16:
+ scan_read (scan, src, &u.u16, 2);
+ csi_integer_new (&obj, be16 (u.u16));
break;
- case 136: /* 8-bit integer */
+ case LSB_UINT16:
+ scan_read (scan, src, &u.u16, 2);
+ csi_integer_new (&obj, le16 (u.u16));
break;
- case 137: /* 16/32-bit fixed point */
+ case MSB_INT32:
+ scan_read (scan, src, &u.i32, 4);
+ csi_integer_new (&obj, be32 (u.i32));
break;
- case 138: /* 32-bit real, MSB */
- csi_file_read (src, &u.i, 4);
-#if ! WORDS_BIGENDIAN
- u.i = bswap_32 (u.i);
-#endif
- csi_real_new (&obj, u.f);
+ case LSB_INT32:
+ scan_read (scan, src, &u.i32, 4);
+ csi_integer_new (&obj, le32 (u.i32));
break;
- case 139: /* 32-bit real, LSB */
- csi_file_read (src, &u.f, 4);
-#if WORDS_BIGENDIAN
- u.i = bswap_32 (u.i);
-#endif
- csi_real_new (&obj, u.f);
+
+ case 136: /* 16.16 msb */
+ scan_read (scan, src, &u.i32, 4);
+ csi_real_new (&obj, be32 (u.i32) / 65536.);
break;
- case 140: /* 32-bit real, native */
- csi_file_read (src, &u.f, 4);
- csi_real_new (&obj, u.f);
+ case 137: /* 16.16 lsb */
+ scan_read (scan, src, &u.i32, 4);
+ csi_real_new (&obj, le32 (u.i32) / 65536.);
+ break;
+ case 138: /* 24.8 msb */
+ scan_read (scan, src, &u.i32, 4);
+ csi_real_new (&obj, be32 (u.i32) / 256.);
break;
- case 141: /* boolean */
+ case 139: /* 24.8 lsb */
+ scan_read (scan, src, &u.i32, 4);
+ csi_real_new (&obj, le32 (u.i32) / 256.);
break;
- case 142: /* string of length 1n */
+ case MSB_FLOAT32:
+ scan_read (scan, src, &u.i32, 4);
+ u.i32 = be32 (u.i32);
+ csi_real_new (&obj, u.f);
+ break;
+ case LSB_FLOAT32:
+ scan_read (scan, src, &u.i32, 4);
+ u.i32 = le32 (u.i32);
+ csi_real_new (&obj, u.f);
break;
- case 143: /* string of length 2n (MSB) */
+
+#define STRING_1 142
+#define STRING_2_MSB 143
+#define STRING_2_LSB 144
+#define STRING_4_MSB 145
+#define STRING_4_LSB 146
+ case STRING_1:
+ scan_read (scan, src, &u.u8, 1);
+ string_read (ctx, scan, src, u.u8, &obj);
break;
- case 144: /* string of length 2n (LSB) */
+ case STRING_2_MSB:
+ scan_read (scan, src, &u.u16, 2);
+ string_read (ctx, scan, src, be16 (u.u16), &obj);
break;
- case 145: /* literal system name */
+ case STRING_2_LSB:
+ scan_read (scan, src, &u.u16, 2);
+ string_read (ctx, scan, src, le16 (u.u16), &obj);
break;
- case 146: /* executable system name */
+ case STRING_4_MSB:
+ scan_read (scan, src, &u.u32, 4);
+ string_read (ctx, scan, src, be32 (u.u32), &obj);
break;
- case 147: /* reserved */
+ case STRING_4_LSB:
+ scan_read (scan, src, &u.u32, 4);
+ string_read (ctx, scan, src, le32 (u.u32), &obj);
break;
- case 148: /* reserved */
+
+ case 147:
+ scan_read (scan, src, &u.u8, 1);
+ csi_operator_new (&obj, ctx->opcode[u.u8]);
break;
- case 149: /* homogeneous array */
+
+ case 148:
+ scan_read (scan, src, &u.u8, 1);
+ csi_operator_new (&obj, ctx->opcode[u.u8]);
+ obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE;
break;
/* unassigned */
+ case 149:
case 150:
case 151:
case 152:
@@ -766,7 +886,6 @@ scan_none (csi_t *ctx,
case 158:
case 159:
longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
case '#': /* PDF 1.2 escape code */
{
@@ -778,31 +897,29 @@ scan_none (csi_t *ctx,
default:
token_start (scan);
token_add_unchecked (scan, c);
- return 1;
+ goto scan_token;
}
if (obj.type != CSI_OBJECT_TYPE_NULL) {
cairo_status_t status;
- if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) {
status = csi_array_append (ctx,
scan->build_procedure.datum.array,
&obj);
- else
- status = csi_object_execute (ctx, &obj);
+ } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) {
+ status = scan_execute (ctx, &obj);
+ csi_object_free (ctx, &obj);
+ } else {
+ status = scan_push (ctx, &obj);
+ }
if (_csi_unlikely (status))
longjmp (scan->jmpbuf, status);
}
}
+ return;
- return 0;
-}
-
-static int
-scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
-{
- int c;
-
+scan_token:
while ((c = csi_file_getc (src)) != EOF) {
switch (c) {
case 0xa:
@@ -813,22 +930,20 @@ scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
case 0xd:
case 0x20:
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
/* syntax delimiters */
case '%':
token_end (ctx, scan, src);
- comment_start (scan);
- return 1;
+ goto scan_comment;
/* syntax error? */
case '(':
token_end (ctx, scan, src);
- string_start (scan);
- return 1;
+ goto scan_string;
/* XXX syntax error? */
case ')':
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
case '/':
/* need to special case '^//?' */
if (scan->buffer.ptr > scan->buffer.base+1 ||
@@ -838,7 +953,7 @@ scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
token_start (scan);
}
token_add_unchecked (scan, '/');
- return 1;
+ goto scan_token;
case '{':
case '}':
@@ -847,12 +962,12 @@ scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
token_start (scan);
token_add_unchecked (scan, c);
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
case '<':
csi_file_putc (src, '<');
token_end (ctx, scan, src);
- return 1;
+ goto scan_none;
case '#': /* PDF 1.2 escape code */
{
@@ -867,100 +982,23 @@ scan_token (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
}
}
token_end (ctx, scan, src);
+ return;
- return 0;
-}
-
-static int
-scan_hex (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
-{
- int c;
-
+scan_comment:
+ /* discard until newline */
while ((c = csi_file_getc (src)) != EOF) {
switch (c) {
case 0xa:
scan->line_number++;
- case 0x0:
- case 0x9:
case 0xc:
- case 0xd:
- case 0x20: /* ignore whitespace */
- break;
-
- case '>':
- hex_end (ctx, scan); /* fixup odd digit with '0' */
- return 1;
-
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- hex_add (ctx, scan, c);
- break;
-
- default:
- longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
+ goto scan_none;
}
}
+ return;
- longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
-}
-
-static int
-scan_base85 (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
-{
- int c, next;
-
- while ((c = csi_file_getc (src)) != EOF) {
- switch (c) {
- case '~':
- next = csi_file_getc (src);
- switch (next) {
- case EOF:
- return 0;
-
- case '>':
- base85_end (ctx, scan);
- return 1;
- }
- csi_file_putc (src, next);
-
- /* fall-through */
- default:
- base85_add (ctx, scan, c);
- break;
- }
- }
-
- longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
-}
-
-static int
-scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
-{
- int c, next;
-
+scan_string:
+ buffer_reset (&scan->buffer);
+ scan->string_p = 1;
while ((c = csi_file_getc (src)) != EOF) {
switch (c) {
case '\\': /* escape */
@@ -968,7 +1006,6 @@ scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
switch (next) {
case EOF:
longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
case 'n':
string_add (ctx, scan, '\n');
@@ -1006,7 +1043,7 @@ scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
next = csi_file_getc (src);
switch (next) {
case EOF:
- return 0;
+ return;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
@@ -1028,7 +1065,7 @@ scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
next = csi_file_getc (src); /* might be compound LFCR */
switch (next) {
case EOF:
- return 0;
+ return;
case 0xc:
break;
default:
@@ -1054,139 +1091,555 @@ scan_string (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
case ')':
if (string_dec_p (scan)) {
string_end (ctx, scan);
- return 1;
- } else
- string_add (ctx, scan, c);
- break;
-
+ goto scan_none;
+ }
+ /* fall through */
default:
string_add (ctx, scan, c);
break;
}
}
-
longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
-}
-
-static int
-scan_comment (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
-{
- int c;
- /* discard until newline */
+scan_hex:
+ buffer_reset (&scan->buffer);
+ scan->accumulator_count = 0;
+ scan->accumulator = 0;
while ((c = csi_file_getc (src)) != EOF) {
switch (c) {
case 0xa:
scan->line_number++;
+ case 0x0:
+ case 0x9:
case 0xc:
- comment_end (scan);
- return 1;
+ case 0xd:
+ case 0x20: /* ignore whitespace */
+ break;
+
+ case '>':
+ hex_end (ctx, scan); /* fixup odd digit with '0' */
+ goto scan_none;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ hex_add (ctx, scan, c);
+ break;
+
+ default:
+ longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
}
}
+ longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
- return 0;
+scan_base85:
+ buffer_reset (&scan->buffer);
+ scan->accumulator = 0;
+ scan->accumulator_count = 0;
+ while ((c = csi_file_getc (src)) != EOF) {
+ switch (c) {
+ case '~':
+ next = csi_file_getc (src);
+ switch (next) {
+ case EOF:
+ return;
+
+ case '>':
+ base85_end (ctx, scan);
+ goto scan_none;
+ }
+ csi_file_putc (src, next);
+
+ /* fall-through */
+ default:
+ base85_add (ctx, scan, c);
+ break;
+ }
+ }
+ longjmp (scan->jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
+}
+
+static csi_status_t
+_scan_push (csi_t *ctx, csi_object_t *obj)
+{
+ if (0) {
+ fprintf (stderr, "push ");
+ fprintf_obj (stderr, ctx, obj);
+ }
+ return _csi_push_ostack (ctx, obj);
+}
+
+static csi_status_t
+_scan_execute (csi_t *ctx, csi_object_t *obj)
+{
+ if (0) {
+ fprintf (stderr, "exec ");
+ fprintf_obj (stderr, ctx, obj);
+ }
+ return csi_object_execute (ctx, obj);
+}
+
+csi_status_t
+_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner)
+{
+ csi_status_t status;
+
+ memset (scanner, 0, sizeof (csi_scanner_t));
+
+ status = buffer_init (ctx, &scanner->buffer);
+ if (status)
+ return status;
+
+ status = _csi_stack_init (ctx, &scanner->procedure_stack, 4);
+ if (status)
+ return status;
+
+ scanner->push = _scan_push;
+ scanner->execute = _scan_execute;
+
+ return CSI_STATUS_SUCCESS;
+}
+
+void
+_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner)
+{
+ buffer_fini (ctx, &scanner->buffer);
+ _csi_stack_fini (ctx, &scanner->procedure_stack);
+ if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL)
+ csi_object_free (ctx, &scanner->build_procedure);
}
csi_status_t
-_csi_scan_file (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src)
+_csi_scan_file (csi_t *ctx, csi_file_t *src)
{
- static int (* const func[]) (csi_t *, csi_scanner_t *, csi_file_t *) = {
- scan_none,
- scan_token,
- scan_comment,
- scan_string,
- scan_hex,
- scan_base85,
- };
csi_status_t status;
/* This function needs to be reentrant to handle recursive scanners.
* i.e. one script executes a second.
*/
- if (scan->depth++ == 0) {
- if ((status = setjmp (scan->jmpbuf))) {
- scan->depth = 0;
+ if (ctx->scanner.depth++ == 0) {
+ if ((status = setjmp (ctx->scanner.jmpbuf))) {
+ ctx->scanner.depth = 0;
return status;
}
+
+ ctx->scanner.line_number = 0; /* XXX broken by recursive scanning */
}
- scan->line_number = 0; /* XXX broken by recursive scanning */
- while (func[scan->state] (ctx, scan, src))
- ;
+ _scan_file (ctx, src);
- --scan->depth;
+ --ctx->scanner.depth;
return CSI_STATUS_SUCCESS;
}
-#if 0
-cairo_status_t
-_csi_tokenize_string (csi_t *ctx,
- const char *code, int len,
- csi_object_t **array_out)
+struct _translate_closure {
+ csi_dictionary_t *opcodes;
+ cairo_write_func_t write_func;
+ void *closure;
+};
+
+static csi_status_t
+_translate_name (csi_t *ctx,
+ csi_name_t name,
+ csi_boolean_t executable,
+ struct _translate_closure *closure)
{
- csi_scanner_t scan;
- csi_object_t *src;
- cairo_status_t status;
+ if (executable) {
+ csi_dictionary_entry_t *entry;
+ uint16_t u16;
+
+ /* Bind executable names.
+ * XXX This may break some scripts that overload system operators.
+ */
+ entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
+ (csi_hash_entry_t *) &name);
+ if (entry == NULL)
+ goto STRING;
+
+ u16 = entry->value.datum.integer;
+ u16 = be16 (u16);
+ closure->write_func (closure->closure, (unsigned char *) &u16, 2);
+ } else {
+ closure->write_func (closure->closure, (unsigned char *) "/", 1);
+STRING:
+ closure->write_func (closure->closure,
+ (unsigned char *) name,
+ strlen ((char *) name));
+ closure->write_func (closure->closure, (unsigned char *) "\n", 1);
+ }
- status = _csi_scanner_init (&scan, ctx);
- if (status)
- return status;
+ return CSI_STATUS_SUCCESS;
+}
- scan.build_procedure = csi_array_new (ctx, 0);
- if (scan.build_procedure == NULL)
- goto CLEANUP_SCAN;
- csi_object_set_literal (scan.build_procedure, FALSE);
+static csi_status_t
+_translate_operator (csi_t *ctx,
+ csi_operator_t op,
+ csi_boolean_t executable,
+ struct _translate_closure *closure)
+{
+ csi_dictionary_entry_t *entry;
+ uint16_t u16;
- src = csi_file_new_for_string (ctx, (const uint8_t *) code, len);
- if (src == NULL) {
- status = _csi_error (CSI_STATUS_NO_MEMORY);
- goto CLEANUP_SCAN;
+ entry = _csi_hash_table_lookup (&closure->opcodes->hash_table,
+ (csi_hash_entry_t *) &op);
+ if (entry == NULL)
+ return _csi_error (CSI_STATUS_INVALID_SCRIPT);
+
+ u16 = entry->value.datum.integer;
+ if (! executable)
+ u16 += 1 << 8;
+ u16 = be16 (u16);
+ closure->write_func (closure->closure, (unsigned char *) &u16, 2);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_translate_integer (csi_t *ctx,
+ csi_integer_t i,
+ struct _translate_closure *closure)
+{
+ uint8_t hdr;
+ union {
+ int8_t i8;
+ uint8_t u8;
+ int16_t i16;
+ uint16_t u16;
+ int32_t i32;
+ uint32_t u32;
+ } u;
+ int len;
+
+#if WORDS_BIGENDIAN
+ if (i < INT16_MIN) {
+ hdr = MSB_INT32;
+ len = 4;
+ u.i32 = i;
+ } else if (i < INT8_MIN) {
+ hdr = MSB_INT16;
+ len = 2;
+ u.i16 = i;
+ } else if (i < 0) {
+ hdr = MSB_INT8;
+ len = 1;
+ u.i8 = i;
+ } else if (i <= UINT8_MAX) {
+ hdr = MSB_UINT8;
+ len = 1;
+ u.u8 = i;
+ } else if (i <= UINT16_MAX) {
+ hdr = MSB_UINT16;
+ len = 2;
+ u.u16 = i;
+ } else {
+ hdr = MSB_INT32;
+ len = 4;
+ u.u32 = i;
+ }
+#else
+ if (i < INT16_MIN) {
+ hdr = LSB_INT32;
+ len = 4;
+ u.i32 = i;
+ } else if (i < INT8_MIN) {
+ hdr = LSB_INT16;
+ len = 2;
+ u.i16 = i;
+ } else if (i < 0) {
+ hdr = LSB_INT8;
+ len = 1;
+ u.i8 = i;
+ } else if (i <= UINT8_MAX) {
+ hdr = LSB_UINT8;
+ len = 1;
+ u.u8 = i;
+ } else if (i <= UINT16_MAX) {
+ hdr = LSB_UINT16;
+ len = 2;
+ u.u16 = i;
+ } else {
+ hdr = LSB_INT32;
+ len = 4;
+ u.u32 = i;
}
+#endif
- status = _csi_scan_object (&scan, src);
- if (status)
- goto CLEANUP_SRC;
+ closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
+ closure->write_func (closure->closure, (unsigned char *) &u, len);
- *array_out = scan.build_procedure;
- scan.build_procedure = NULL;
+ return CSI_STATUS_SUCCESS;
+}
-CLEANUP_SRC:
- csi_object_free (src);
+static csi_status_t
+_translate_real (csi_t *ctx,
+ csi_real_t real,
+ struct _translate_closure *closure)
+{
+ uint8_t hdr;
-CLEANUP_SCAN:
- _csi_scanner_fini (&scan);
+ if (real >= INT32_MIN && real <= INT32_MAX && (int) real == real)
+ return _translate_integer (ctx, real, closure);
- return status;
+#if WORDS_BIGENDIAN
+ hdr = MSB_FLOAT32;
+#else
+ hdr = LSB_FLOAT32;
+#endif
+ closure->write_func (closure->closure, (unsigned char *) &hdr, 1);
+ closure->write_func (closure->closure, (unsigned char *) &real, 4);
+
+ return CSI_STATUS_SUCCESS;
}
+
+static csi_status_t
+_translate_string (csi_t *ctx,
+ csi_string_t *string,
+ struct _translate_closure *closure)
+{
+ uint8_t hdr;
+ union {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ } u;
+ int len;
+
+#if WORDS_BIGENDIAN
+ if (string->len <= UINT8_MAX) {
+ hdr = STRING_1;
+ u.u8 = string->len;
+ len = 1;
+ } else if (string->len <= UINT16_MAX) {
+ hdr = STRING_2_MSB;
+ u.u16 = string->len;
+ len = 2;
+ } else {
+ hdr = STRING_4_MSB;
+ u.u32 = string->len;
+ len = 4;
+ }
+#else
+ if (string->len <= UINT8_MAX) {
+ hdr = STRING_1;
+ u.u8 = string->len;
+ len = 1;
+ } else if (string->len <= UINT16_MAX) {
+ hdr = STRING_2_LSB;
+ u.u16 = string->len;
+ len = 2;
+ } else {
+ hdr = STRING_4_LSB;
+ u.u32 = string->len;
+ len = 4;
+ }
#endif
-csi_status_t
-_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner)
+ closure->write_func (closure->closure,
+ (unsigned char *) &hdr, 1);
+ closure->write_func (closure->closure,
+ (unsigned char *) &u, len);
+ closure->write_func (closure->closure,
+ (unsigned char *) string->string, string->len);
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_translate_push (csi_t *ctx, csi_object_t *obj)
{
- csi_status_t status;
+ struct _translate_closure *closure = ctx->scanner.closure;
- memset (scanner, 0, sizeof (csi_scanner_t));
+ if (0) {
+ fprintf (stderr, "push ");
+ fprintf_obj (stderr, ctx, obj);
+ }
- status = buffer_init (ctx, &scanner->buffer);
- if (status)
- return status;
+ switch (csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_NAME:
+ return _translate_name (ctx, obj->datum.name, FALSE, closure);
+
+ case CSI_OBJECT_TYPE_OPERATOR:
+ return _translate_operator (ctx, obj->datum.op, FALSE, closure);
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ return _translate_integer (ctx, obj->datum.integer, closure);
+
+ case CSI_OBJECT_TYPE_REAL:
+ return _translate_real (ctx, obj->datum.real, closure);
+
+ case CSI_OBJECT_TYPE_STRING:
+ return _translate_string (ctx, obj->datum.string, closure);
+
+ case CSI_OBJECT_TYPE_NULL:
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ case CSI_OBJECT_TYPE_MARK:
+ case CSI_OBJECT_TYPE_ARRAY:
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ case CSI_OBJECT_TYPE_FILE:
+ case CSI_OBJECT_TYPE_MATRIX:
+ case CSI_OBJECT_TYPE_CONTEXT:
+ case CSI_OBJECT_TYPE_FONT:
+ case CSI_OBJECT_TYPE_PATTERN:
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ case CSI_OBJECT_TYPE_SURFACE:
+ longjmp (ctx->scanner.jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
+ break;
+ }
- status = _csi_stack_init (ctx, &scanner->procedure_stack, 4);
- if (status)
+ csi_object_free (ctx, obj);
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+_translate_execute (csi_t *ctx, csi_object_t *obj)
+{
+ struct _translate_closure *closure = ctx->scanner.closure;
+
+ if (0) {
+ fprintf (stderr, "exec ");
+ fprintf_obj (stderr, ctx, obj);
+ }
+
+ switch (csi_object_get_type (obj)) {
+ case CSI_OBJECT_TYPE_NAME:
+ return _translate_name (ctx, obj->datum.name, TRUE, closure);
+
+ case CSI_OBJECT_TYPE_OPERATOR:
+ return _translate_operator (ctx, obj->datum.op, TRUE, closure);
+
+ case CSI_OBJECT_TYPE_INTEGER:
+ return _translate_integer (ctx, obj->datum.integer, closure);
+
+ case CSI_OBJECT_TYPE_REAL:
+ return _translate_real (ctx, obj->datum.real, closure);
+
+ case CSI_OBJECT_TYPE_STRING:
+ return _translate_string (ctx, obj->datum.string, closure);
+
+ case CSI_OBJECT_TYPE_NULL:
+ case CSI_OBJECT_TYPE_BOOLEAN:
+ case CSI_OBJECT_TYPE_MARK:
+ case CSI_OBJECT_TYPE_ARRAY:
+ case CSI_OBJECT_TYPE_DICTIONARY:
+ case CSI_OBJECT_TYPE_FILE:
+ case CSI_OBJECT_TYPE_MATRIX:
+ case CSI_OBJECT_TYPE_CONTEXT:
+ case CSI_OBJECT_TYPE_FONT:
+ case CSI_OBJECT_TYPE_PATTERN:
+ case CSI_OBJECT_TYPE_SCALED_FONT:
+ case CSI_OBJECT_TYPE_SURFACE:
+ longjmp (ctx->scanner.jmpbuf, _csi_error (CSI_STATUS_INVALID_SCRIPT));
+ break;
+ }
+
+ return CSI_STATUS_SUCCESS;
+}
+
+static csi_status_t
+build_opcodes (csi_t *ctx, csi_dictionary_t **out)
+{
+ csi_object_t obj;
+ csi_dictionary_t *dict;
+ const csi_operator_def_t *def;
+ csi_status_t status;
+ int opcode = 147 << 8;
+
+ status = csi_dictionary_new (ctx, &obj);
+ if (_csi_unlikely (status))
return status;
- reset (scanner);
+ dict = obj.datum.dictionary;
+
+ csi_integer_new (&obj, opcode++);
+ status = csi_dictionary_put (ctx, dict, 0, &obj);
+ if (_csi_unlikely (status))
+ goto FAIL;
+
+ for (def = _csi_operators (); def->name != NULL; def++) {
+ csi_object_t name;
+ csi_dictionary_entry_t *entry;
+ int code;
+
+ entry = _csi_hash_table_lookup (&dict->hash_table,
+ (csi_hash_entry_t *) &def->op);
+ if (entry == NULL) {
+ code = opcode++;
+ csi_integer_new (&obj, code);
+ status = csi_dictionary_put (ctx, dict, (csi_name_t) def->op, &obj);
+ if (_csi_unlikely (status))
+ goto FAIL;
+ } else {
+ code = entry->value.datum.integer;
+ csi_integer_new (&obj, code);
+ }
+ assert (ctx->opcode[code & 0xff] == def->op);
+
+ status = csi_name_new_static (ctx, &name, def->name);
+ if (_csi_unlikely (status))
+ goto FAIL;
+
+ status = csi_dictionary_put (ctx, dict, name.datum.name, &obj);
+ if (_csi_unlikely (status))
+ goto FAIL;
+ }
+ *out = dict;
return CSI_STATUS_SUCCESS;
+
+FAIL:
+ csi_dictionary_free (ctx, dict);
+ return status;
}
-void
-_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner)
+csi_status_t
+_csi_translate_file (csi_t *ctx,
+ csi_file_t *file,
+ cairo_write_func_t write_func,
+ void *closure)
{
- buffer_fini (ctx, &scanner->buffer);
- _csi_stack_fini (ctx, &scanner->procedure_stack);
- if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL)
- csi_object_free (ctx, &scanner->build_procedure);
+ csi_status_t status;
+ struct _translate_closure translator;
+
+ if ((status = setjmp (ctx->scanner.jmpbuf)))
+ return status;
+
+ status = build_opcodes (ctx, &translator.opcodes);
+ if (_csi_unlikely (status))
+ return status;
+
+ translator.write_func = write_func;
+ translator.closure = closure;
+ ctx->scanner.closure = &translator;
+
+ ctx->scanner.push = _translate_push;
+ ctx->scanner.execute = _translate_execute;
+
+ _scan_file (ctx, file);
+
+ ctx->scanner.push = _scan_push;
+ ctx->scanner.execute = _scan_execute;
+
+ csi_dictionary_free (ctx, translator.opcodes);
+
+ return CSI_STATUS_SUCCESS;
}
More information about the cairo-commit
mailing list