summaryrefslogtreecommitdiff
path: root/pxl/pxparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'pxl/pxparse.c')
-rw-r--r--pxl/pxparse.c917
1 files changed, 917 insertions, 0 deletions
diff --git a/pxl/pxparse.c b/pxl/pxparse.c
new file mode 100644
index 000000000..6ffb10d39
--- /dev/null
+++ b/pxl/pxparse.c
@@ -0,0 +1,917 @@
+/* Portions Copyright (C) 2001 artofcode LLC.
+ Portions Copyright (C) 1996, 2001 Artifex Software Inc.
+ Portions Copyright (C) 1988, 2000 Aladdin Enterprises.
+ This software is based in part on the work of the Independent JPEG Group.
+ All Rights Reserved.
+
+ This software is distributed under license and may not be copied, modified
+ or distributed except as expressly authorized under the terms of that
+ license. Refer to licensing information at http://www.artifex.com/ or
+ contact Artifex Software, Inc., 101 Lucas Valley Road #110,
+ San Rafael, CA 94903, (415)492-9861, for further information. */
+/*$Id$ */
+
+/* pxparse.c */
+/* PCL XL parser */
+
+#include "memory_.h"
+#include "gdebug.h"
+#include "gserror.h"
+#include "gsio.h"
+#include "gstypes.h"
+#include "plparse.h"
+#include "pxattr.h"
+#include "pxenum.h"
+#include "pxerrors.h"
+#include "pxoper.h"
+#include "pxtag.h"
+#include "pxvalue.h"
+#include "pxparse.h" /* requires pxattr.h, pxvalue.h */
+#include "pxptable.h" /* requires pxenum.h, pxoper.h, pxvalue.h */
+#include "pxstate.h"
+#include "pxpthr.h"
+#include "gsstruct.h"
+
+/* GC structures and procedures */
+gs_private_st_composite(st_px_parser_state, px_parser_state_t,
+ "px_parser_state_t", parser_state_enum_ptrs, parser_state_reloc_ptrs);
+#define st ((px_parser_state_t *)vptr)
+static ENUM_PTRS_BEGIN(parser_state_enum_ptrs)
+ /* Mark from array pointers on the stack. */
+ if ( index < st->stack_count )
+ { px_value_t *pv = &st->stack[index];
+ ENUM_RETURN((!(~pv->type & (pxd_array | pxd_on_heap)) ?
+ pv->value.array.data : 0));
+ }
+ return 0;
+ENUM_PTRS_END
+static RELOC_PTRS_BEGIN(parser_state_reloc_ptrs) {
+ px_parser_state_t *st_new =
+ (*gc_proc(gcst, reloc_struct_ptr))((const void *)st, gcst);
+ long diff = (byte *)st_new - (byte *)st;
+
+ /* Relocate array pointers on the stack. */
+ { px_value_t *pv = &st->stack[0];
+ int i;
+
+ for ( i = 0; i < st->stack_count; ++pv, ++i )
+ if ( !(~pv->type & (pxd_array | pxd_on_heap)) )
+ RELOC_OBJ_VAR(pv->value.array.data);
+ }
+ /* Relocate the pointers from the args. */
+ st->args.parser = st_new;
+ { px_value_t **ppv = &st->args.pv[0];
+ int i;
+
+ for ( i = 0; i < max_px_args; ++ppv, ++i )
+ if ( *ppv )
+ *ppv = (px_value_t *)((byte *)*ppv + diff);
+ }
+} RELOC_PTRS_END
+#undef st
+
+/*
+ * We define the syntax of each possible tag by 4 parameters:
+ * - The minimum number of input bytes required to parse it;
+ * - A mask and match value for the state(s) in which it is legal;
+ * - A transition mask to be xor'ed with the state.
+ * See pxparse.h for the state mask values.
+ */
+typedef struct px_tag_syntax_s {
+ byte min_input;
+ byte state_value;
+ byte state_mask;
+ byte state_transition;
+} px_tag_syntax_t;
+
+/* Define the common syntaxes. */
+#define N (ptsData|ptsReading) /* normal state */
+#define I {1,0,0,0} /* illegal or unusual */
+#define P {1,ptsInPage,ptsInPage|N,0} /* ordinary operator */
+#define C {1,ptsInSession,ptsInSession|N,0} /* control operator */
+#define R(p,r,t) /* reading operator */\
+ {1,ptsInSession|p|r,ptsInSession|p|N,t}
+#define D(n) {n,0,ptsData,ptsData} /* data type */
+#define DI D(1) /* invalid data type */
+#define A(n) {n,ptsData,ptsData,ptsData} /* attribute */
+
+/* Define the syntax of all tags. */
+static const px_tag_syntax_t tag_syntax[256] = {
+/*0x*/
+ I,I,I,I,I,I,I,I, I,I,I,I,I,I,I,I,
+/*1x*/
+ I,I,I,I,I,I,I,I, I,I,I,{2,0,0,0},I,I,I,I,
+/*2x*/
+ I,I,I,I,I,I,I,I, I,I,I,I,I,I,I,I,
+/*3x*/
+ I,I,I,I,I,I,I,I, I,I,I,I,I,I,I,I,
+/*4x*/
+ {2,0,ptsInSession|N,0},
+ {1,0,ptsInSession|N,ptsInSession},
+ {1,ptsInSession,ptsInSession|ptsInPage|N,ptsInSession},
+ {1,ptsInSession,ptsInSession|ptsInPage|N,ptsInPage},
+ {1,ptsInPage,ptsInPage|N,ptsInPage},
+ P,{1,1,1,0},C,
+ C,C,P,P,P,P,P,R(0,0,ptsReadingFont),
+/*5x*/
+ R(0,ptsReadingFont,0),
+ R(0,ptsReadingFont,ptsReadingFont),
+ R(0,0,ptsReadingChar),
+ R(0,ptsReadingChar,0),
+ R(0,ptsReadingChar,ptsReadingChar),
+ C,P,P,
+ P,P,P,
+ {1,ptsInSession,ptsInSession|ptsExecStream|N,ptsReadingStream},
+ {1,ptsInSession|ptsReadingStream,ptsInSession|ptsExecStream|N,0},
+ {1,ptsInSession|ptsReadingStream,ptsInSession|ptsExecStream|N,ptsReadingStream},
+ {1,ptsInSession,ptsInSession|ptsReadingStream|N,0},
+ P,
+/*6x*/
+ P,P,P,P,P,P,P,P, P,P,P,P,P,P,P,P,
+/*7x*/
+ P,P,P,P,P,P,P,P, P,P,P,P,P,P,P,P,
+/*8x*/
+ P,P,P,P,P,P,P,P, P,P,P,P,P,P,P,P,
+/*9x*/
+ P,P,P,P,P,P,P,P, P,P,P,P,P,P,P,P,
+/*ax*/
+ P,P,P,P,P,P,P,P, P,P,P,P,P,P,P,P,
+/*bx*/
+ R(ptsInPage,0,ptsReadingImage),
+ R(ptsInPage,ptsReadingImage,0),
+ R(ptsInPage,ptsReadingImage,ptsReadingImage),
+ R(ptsInPage,0,ptsReadingRastPattern),
+ R(ptsInPage,ptsReadingRastPattern,0),
+ R(ptsInPage,ptsReadingRastPattern,ptsReadingRastPattern),
+ R(ptsInPage,0,ptsReadingScan),
+ P,
+ R(ptsInPage,ptsReadingScan,ptsReadingScan),
+ R(ptsInPage,ptsReadingScan,0),
+ P,P,P,P,P,P,
+/*cx*/
+ D(2),D(3),D(5),D(3),D(5),D(5),DI,DI,
+ D(3),D(3),D(3),D(3),D(3),D(3),DI,DI,
+/*dx*/
+ D(3),D(5),D(9),D(5),D(9),D(9),DI,DI,
+ DI,DI,DI,DI,DI,DI,DI,DI,
+/*ex*/
+ D(5),D(9),D(17),D(9),D(17),D(17),DI,DI,
+ DI,DI,DI,DI,DI,DI,DI,DI,
+/*fx*/
+ I,I,I,I,I,I,I,I,
+ A(2),A(3),{5,0,0,0},{2,0,0,0},I,I,I,I
+};
+#undef I
+#undef P
+#undef C
+#undef R
+#undef D
+#undef DI
+#undef A
+
+/* Allocate a parser state. */
+px_parser_state_t *
+px_process_alloc(gs_memory_t *memory)
+{ px_parser_state_t *st = gs_alloc_struct(memory, px_parser_state_t,
+ &st_px_parser_state,
+ "px_process_alloc");
+ if ( st == 0 )
+ return 0;
+ st->memory = memory;
+ px_process_init(st, true);
+ return st;
+}
+
+/* Release a parser state. */
+void
+px_process_release(px_parser_state_t *st)
+{ gs_free_object(st->memory, st, "px_process_alloc");
+}
+
+/* Initialize the parser state. */
+void
+px_process_init(px_parser_state_t *st, bool big_endian)
+{ st->big_endian = big_endian;
+ st->operator_count = 0;
+ st->parent_operator_count = 0;
+ st->last_operator = pxtNull;
+ st->saved_count = 0;
+ st->data_left = 0;
+ st->macro_state = ptsInitial;
+ st->stack_count = 0;
+ st->data_proc = 0;
+ { int i;
+ for ( i = 0; i < max_px_args; ++i )
+ st->args.pv[i] = 0;
+ }
+ st->args.parser = 0; /* for garbage collector */
+ memset(st->attribute_indices, 0, px_attribute_next);
+}
+
+/* Get numeric values from the input. */
+#define get_uint16(st, p) uint16at(p, st->big_endian)
+#define get_sint16(st, p) sint16at(p, st->big_endian)
+#define get_uint32(st, p) uint32at(p, st->big_endian)
+#define get_sint32(st, p) sint32at(p, st->big_endian)
+#define get_real32(st, p) real32at(p, st->big_endian)
+
+/* Move an array to the heap for persistence if needed. */
+/* See pxoper.h for details. */
+static int
+px_save_array(px_value_t *pv, px_state_t *pxs, client_name_t cname,
+ uint nbytes)
+{ if ( pv->type & pxd_on_heap )
+ { /* Turn off the "on heap" bit, to prevent freeing. */
+ pv->type &= ~pxd_on_heap;
+ }
+ else
+ { /* Allocate a heap copy. Only the first nbytes bytes */
+ /* of the data are valid. */
+ uint num_elements = pv->value.array.size;
+ uint elt_size = value_size(pv);
+
+ byte *copy = gs_alloc_byte_array(pxs->memory, num_elements,
+ elt_size, cname);
+ if ( copy == 0 )
+ return_error(errorInsufficientMemory);
+ memcpy(copy, pv->value.array.data, nbytes);
+ pv->value.array.data = copy;
+ }
+ return 0;
+}
+
+/* Clear the stack and the attribute indices, */
+/* and free heap-allocated arrays. */
+#define clear_stack()\
+ for ( ; sp > st->stack; --sp )\
+ { if ( sp->type & pxd_on_heap )\
+ gs_free_object(memory, (void *)sp->value.array.data,\
+ "px stack pop");\
+ st->attribute_indices[sp->attribute] = 0;\
+ }
+
+/* Define data tracing if debugging. */
+#ifdef DEBUG
+# define trace_data(format, cast, ptr, count)\
+ do\
+ { uint i_;\
+ for ( i_ = 0; i_ < count; ++i_ )\
+ dprintf1(format, (cast)((ptr)[i_]));\
+ dputc('\n');\
+ }\
+ while (0)
+static void
+trace_array_data(const char *label, const px_value_t *pav)
+{ px_data_type_t type = pav->type;
+ const byte *ptr = pav->value.array.data;
+ uint count = pav->value.array.size;
+ bool big_endian = (type & pxd_big_endian) != 0;
+ bool text = (type & pxd_ubyte) != 0;
+ uint i;
+
+ dputs(label);
+ dputs((type & pxd_ubyte ? " <" : " {"));
+ for ( i = 0; i < count; ++i )
+ { if ( !(i & 15) && i )
+ { const char *p;
+ dputs("\n ");
+ for ( p = label; *p; ++p )
+ dputc(' ');
+ }
+ if ( type & pxd_ubyte )
+ { dprintf1("%02x ", ptr[i]);
+ if ( ptr[i] < 32 || ptr[i] > 126 )
+ text = false;
+ }
+ else if ( type & pxd_uint16 )
+ dprintf1("%u ", uint16at(ptr + i * 2, big_endian));
+ else if ( type & pxd_sint16 )
+ dprintf1("%d ", sint16at(ptr + i * 2, big_endian));
+ else if ( type & pxd_uint32 )
+ dprintf1("%lu ", (ulong)uint32at(ptr + i * 4, big_endian));
+ else if ( type & pxd_sint32 )
+ dprintf1("%ld ", (long)sint32at(ptr + i * 4, big_endian));
+ else if ( type & pxd_real32 )
+ dprintf1("%g ", real32at(ptr + i * 4, big_endian));
+ else
+ dputs("? ");
+ }
+ dputs((type & pxd_ubyte ? ">\n" : "}\n"));
+ if ( text )
+ { dputs("%chars: \"");
+ debug_print_string(ptr, count);
+ dputs("\"\n");
+ }
+}
+# define trace_array(pav)\
+ if ( gs_debug_c('I') )\
+ trace_array_data("array:", pav)
+#else
+# define trace_data(format, cast, ptr, count) DO_NOTHING
+# define trace_array(pav) DO_NOTHING
+#endif
+
+/* Process a buffer of PCL XL commands. */
+int
+px_process(px_parser_state_t *st, px_state_t *pxs, stream_cursor_read *pr)
+{ const byte *orig_p = pr->ptr;
+ const byte *next_p = orig_p; /* start of data not copied to saved */
+ const byte *p;
+ const byte *rlimit;
+ px_value_t *sp = &st->stack[st->stack_count];
+#define stack_limit &st->stack[max_stack - 1]
+ gs_memory_t *memory = st->memory;
+ int code = 0;
+ uint left;
+ uint min_left;
+ px_tag_t tag;
+ const px_tag_syntax_t *syntax = 0;
+
+ st->args.parser = st;
+ st->parent_operator_count = 0; /* in case of error */
+ /* Check for leftover data from the previous call. */
+parse: if ( st->saved_count )
+ { /* Fill up the saved buffer so we can make progress. */
+ int move = min(sizeof(st->saved) - st->saved_count,
+ pr->limit - next_p);
+ memcpy(&st->saved[st->saved_count], next_p + 1, move);
+ next_p += move;
+ p = st->saved - 1;
+ rlimit = p + st->saved_count + move;
+ }
+ else
+ { /* No leftover data, just read from the input. */
+ p = next_p;
+ rlimit = pr->limit;
+ }
+top: if ( st->data_left )
+ { /* We're in the middle of reading an array or data block. */
+ if ( st->data_proc )
+ { /* This is a data block. */
+ uint avail = min(rlimit - p, st->data_left);
+ uint used;
+
+ st->args.source.available = avail;
+ st->args.source.data = p + 1;
+ code = (*st->data_proc)(&st->args, pxs);
+ used = st->args.source.data - (p + 1);
+#ifdef DEBUG
+ if ( gs_debug_c('I') )
+ { px_value_t data_array;
+ data_array.type = pxd_ubyte;
+ data_array.value.array.data = p + 1;
+ data_array.value.array.size = used;
+ trace_array_data("data:", &data_array);
+ }
+#endif
+ p = st->args.source.data - 1;
+ st->data_left -= used;
+ if ( code < 0 )
+ { st->args.source.position = 0;
+ goto x;
+ }
+ else if ( ( code == pxNeedData ) || ( code == pxPassThrough && st->data_left != 0 ) )
+ { code = 0; /* exit for more data */
+ goto x;
+ }
+ else
+ { st->args.source.position = 0;
+ st->data_proc = 0;
+ if ( st->data_left != 0 )
+ { code = gs_note_error(errorExtraData);
+ goto x;
+ }
+ clear_stack();
+ }
+ }
+ else
+ { /* This is an array. */
+ uint size = sp->value.array.size;
+ uint scale = value_size(sp);
+ uint nbytes = size * scale;
+ byte *dest =
+ (byte *)sp->value.array.data + nbytes - st->data_left;
+
+ left = rlimit - p;
+ if ( left < st->data_left )
+ { /* We still don't have enough data to fill the array. */
+ memcpy(dest, p + 1, left);
+ st->data_left -= left;
+ p = rlimit;
+ code = 0;
+ goto x;
+ }
+ /* Complete the array and continue parsing. */
+ memcpy(dest, p + 1, st->data_left);
+ trace_array(sp);
+ p += st->data_left;
+ }
+ st->data_left = 0;
+ }
+ else if ( st->data_proc )
+ { /* An operator is awaiting data. */
+ /* Skip white space until we find some. */
+ code = 0; /* in case we exit */
+ while ( (left = rlimit - p) != 0 )
+ { switch ( (tag = p[1]) )
+ {
+ case pxtNull:
+ case pxtHT: case pxtLF: case pxtVT: case pxtFF: case pxtCR:
+ ++p;
+ continue;
+ case pxt_dataLength:
+ if ( left < 5 )
+ goto x; /* can't look ahead */
+ st->data_left = get_uint32(st, p + 2);
+ if_debug2('i', "tag= 0x%2x data, length %u\n",
+ p[1], st->data_left);
+ p += 5;
+ goto top;
+ case pxt_dataLengthByte:
+ if ( left < 2 )
+ goto x; /* can't look ahead */
+ st->data_left = p[2];
+ if_debug2('i', "tag= 0x%2x data, length %u\n",
+ p[1], st->data_left);
+ p += 2;
+ goto top;
+ default:
+ { code = gs_note_error(errorMissingData);
+ goto x;
+ }
+ }
+ }
+ }
+ st->args.source.position = 0;
+ st->args.source.available = 0;
+ while ( (left = rlimit - p) != 0 &&
+ left >= (min_left = (syntax = &tag_syntax[tag = p[1]])->min_input)
+ )
+ { int count;
+#ifdef DEBUG
+ if ( gs_debug_c('i') )
+ { dprintf1("tag= 0x%02x ", tag);
+ if ( tag == pxt_attr_ubyte || tag == pxt_attr_uint16 )
+ { px_attribute_t attr =
+ (tag == pxt_attr_ubyte ? p[2] : get_uint16(st, p + 2));
+ const char *aname = px_attribute_names[attr];
+ if ( aname )
+ dprintf1(" @%s\n", aname);
+ else
+ dprintf1(" attribute %u ???\n", attr);
+ }
+ else
+ { const char *format;
+ const char *tname;
+ bool operator = false;
+ if ( tag < 0x40 )
+ format = "%s\n", tname = px_tag_0_names[tag];
+ else if ( tag < 0xc0 )
+ format = "%s", tname = px_operator_names[tag - 0x40],
+ operator = true;
+ else
+ { tname = px_tag_c0_names[tag - 0xc0];
+ if ( tag < 0xf0 )
+ format = " %s"; /* data values follow */
+ else
+ format = "%s\n";
+ }
+ if ( tname ) {
+ dprintf1(format, tname);
+ if (operator)
+ dprintf1(" (%ld)\n", st->operator_count+1);
+ }
+ else
+ dputs("???\n");
+ }
+ }
+#endif
+ if ( (st->macro_state & syntax->state_mask) != syntax->state_value )
+ { /*
+ * We should probably distinguish here between
+ * out-of-context operators and illegal tags, but it's too
+ * much trouble.
+ */
+ code = gs_note_error(errorIllegalOperatorSequence);
+ if ( tag >= 0x40 && tag < 0xc0 )
+ st->last_operator = tag;
+ goto x;
+ }
+ st->macro_state ^= syntax->state_transition;
+ switch ( tag >> 3 )
+ {
+ case 0:
+ switch ( tag )
+ {
+ case pxtNull: ++p; continue;
+ default: break;
+ }
+ break;
+ case 1:
+ switch ( tag )
+ {
+ case pxtHT: case pxtLF: case pxtVT: case pxtFF: case pxtCR:
+ ++p;
+ continue;
+ default:
+ break;
+ }
+ break;
+ case 3:
+ if ( tag == pxt1b ) /* ESC */
+ { /* Check for UEL */
+ if ( memcmp(p + 1, "\033%-12345X", min(left, 9)) )
+ break; /* not UEL, error */
+ if ( left < 9 )
+ goto x; /* need more data */
+ p += 9;
+ code = e_ExitLanguage;
+ goto x;
+ }
+ break;
+ case 4:
+ switch ( tag )
+ {
+ case pxtSpace:
+ /* break; will error, compatible with lj */
+ /* ++p;continue; silently ignores the space */
+ ++p;
+ continue;
+ default: break;
+ }
+ break;
+ case 8: case 9:
+ case 10: case 11: case 12: case 13: case 14:
+ case 15: case 16: case 17: case 18: case 19:
+ case 20: case 21: case 22: case 23:
+ /* Operators */
+ /* Make sure that we have all the required attributes, */
+ /* and no attributes that are neither required nor */
+ /* optional. (It's up to the operator to make any */
+ /* more precise checks than this. */
+ st->operator_count++;
+ /* if this is a passthrough operator we have to tell
+ the passthrough module if this operator was
+ preceded by another passthrough operator or a
+ different xl operator */
+ if (tag == pxtPassThrough) {
+ pxpcl_passthroughcontiguous(st->last_operator == tag);
+ } else if ( st->last_operator == pxtPassThrough ) {
+ pxpcl_endpassthroughcontiguous(pxs);
+ }
+
+ st->last_operator = tag;
+ { const px_operator_definition_t *pod =
+ &px_operator_definitions[tag - 0x40];
+ int left = sp - st->stack;
+ const byte /*px_attribute_t*/ *pal = pod->attrs;
+ px_value_t **ppv = st->args.pv;
+ bool required = true;
+
+ code = 0;
+ /*
+ * Scan the attributes. Illegal attributes take priority
+ * over missing attributes, which in turn take priority
+ * over illegal data types.
+ */
+ for ( ; ; ++pal, ++ppv )
+ { px_attribute_t attr = *pal;
+ uint index;
+
+ if ( !attr )
+ { /*
+ * We've reached the end of either the required or
+ * the optional attribute list.
+ */
+ if ( !required )
+ break;
+ required = false;
+ --ppv; /* cancel incrementing */
+ continue;
+ }
+ if ( (index = st->attribute_indices[attr]) == 0 )
+ { if ( required )
+ code = gs_note_error(errorMissingAttribute);
+ else
+ *ppv = 0;
+ }
+ else
+ { /* Check the attribute data type and value. */
+ px_value_t *pv = *ppv = &st->stack[index];
+ const px_attr_value_type_t *pavt =
+ &px_attr_value_types[attr];
+ int acode;
+
+ if ( (~pavt->mask & pv->type &
+ (pxd_structure | pxd_representation)) ||
+ (pavt->mask == (pxd_scalar | pxd_ubyte) &&
+ (pv->value.i < 0 || pv->value.i > pavt->limit))
+ )
+ { if ( code >= 0 )
+ code = gs_note_error(errorIllegalAttributeDataType);
+ }
+ if ( pavt->proc != 0 && (acode = (*pavt->proc)(pv)) < 0 )
+ { if ( code >= 0 )
+ code = acode;
+ }
+ --left;
+ }
+ }
+
+ /* Make sure there are no attributes left over. */
+ if ( left )
+ code = gs_note_error(errorIllegalAttribute);
+ if ( code >= 0 ) {
+ st->args.source.phase = 0;
+ code = (*pod->proc)(&st->args, pxs);
+ }
+ if ( code < 0 )
+ goto x;
+ /* Check whether the operator wanted source data. */
+ if ( code == pxNeedData )
+ { if ( !pxs->data_source_open )
+ { code = gs_note_error(errorDataSourceNotOpen);
+ goto x;
+ }
+ st->data_proc = pod->proc;
+ ++p;
+ goto top;
+ }
+ }
+ clear_stack();
+ ++p;
+ continue;
+ case 24: sp[1].type = pxd_scalar; count = 1; goto data;
+ case 26: sp[1].type = pxd_xy; count = 2; goto data;
+ case 28: sp[1].type = pxd_box; count = 4; goto data;
+ /* Scalar, point, and box data */
+data: { int i;
+ if ( sp == stack_limit )
+ { code = gs_note_error(errorInternalOverflow);
+ goto x;
+ }
+ ++sp;
+ sp->attribute = 0;
+ p += 2;
+#ifdef DEBUG
+# define trace_scalar(format, cast, alt)\
+ if ( gs_debug_c('i') )\
+ trace_data(format, cast, sp->value.alt, count)
+#else
+# define trace_scalar(format, cast, alt) DO_NOTHING
+#endif
+ switch ( tag & 7 )
+ {
+ case pxt_ubyte & 7:
+ sp->type |= pxd_ubyte;
+ for ( i = 0; i < count; ++p, ++i )
+ sp->value.ia[i] = *p;
+dux: trace_scalar(" %lu", ulong, ia);
+ --p;
+ continue;
+ case pxt_uint16 & 7:
+ sp->type |= pxd_uint16;
+ for ( i = 0; i < count; p += 2, ++i )
+ sp->value.ia[i] = get_uint16(st, p);
+ goto dux;
+ case pxt_uint32 & 7:
+ sp->type |= pxd_uint32;
+ for ( i = 0; i < count; p += 4, ++i )
+ sp->value.ia[i] = get_uint32(st, p);
+ goto dux;
+ case pxt_sint16 & 7:
+ sp->type |= pxd_sint16;
+ for ( i = 0; i < count; p += 2, ++i )
+ sp->value.ia[i] = get_sint16(st, p);
+dsx: trace_scalar(" %ld", long, ia);
+ --p;
+ continue;
+ case pxt_sint32 & 7:
+ sp->type |= pxd_sint32;
+ for ( i = 0; i < count; p += 4, ++i )
+ sp->value.ia[i] = get_sint32(st, p);
+ goto dsx;
+ case pxt_real32 & 7:
+ sp->type |= pxd_real32;
+ for ( i = 0; i < count; p += 4, ++i )
+ sp->value.ra[i] = get_real32(st, p);
+ trace_scalar(" %g", double, ra);
+ --p;
+ continue;
+ default:
+ break;
+ }
+ }
+ break;
+ case 25:
+ /* Array data */
+ { const byte *dp;
+ uint nbytes;
+ if ( sp == stack_limit )
+ { code = gs_note_error(errorInternalOverflow);
+ goto x;
+ }
+ switch ( p[2] )
+ {
+ case pxt_ubyte:
+ sp[1].value.array.size = p[3];
+ dp = p + 4;
+ break;
+ case pxt_uint16:
+ if ( left < 4 )
+ { if_debug0('i', "...\n");
+ /* Undo the state transition. */
+ st->macro_state ^= syntax->state_transition;
+ goto x;
+ }
+ sp[1].value.array.size = get_uint16(st, p+3);
+ dp = p + 5;
+ break;
+ default:
+ st->last_operator = tag; /* for error message */
+ code = gs_note_error(errorIllegalTag);
+ goto x;
+ }
+ nbytes = sp[1].value.array.size;
+ if_debug1('i', "[%u]\n", sp[1].value.array.size);
+ switch ( tag )
+ {
+ case pxt_ubyte_array:
+ sp[1].type = pxd_array | pxd_ubyte;
+array: ++sp;
+ if ( st->big_endian )
+ sp->type |= pxd_big_endian;
+ sp->value.array.data = dp;
+ sp->attribute = 0;
+ /* Check whether we have enough data for the entire */
+ /* array. */
+ if ( rlimit + 1 - dp < nbytes )
+ { /* Exit now, continue reading when we return. */
+ uint avail = rlimit + 1 - dp;
+
+ code = px_save_array(sp, pxs, "partial array",
+ avail);
+ if ( code < 0 )
+ goto x;
+ sp->type |= pxd_on_heap;
+ st->data_left = nbytes - avail;
+ st->data_proc = 0;
+ p = rlimit;
+ goto x;
+ }
+ p = dp + nbytes - 1;
+ trace_array(sp);
+ continue;
+ case pxt_uint16_array:
+ sp[1].type = pxd_array | pxd_uint16;
+a16: nbytes <<= 1;
+ goto array;
+ case pxt_uint32_array:
+ sp[1].type = pxd_array | pxd_uint32;
+a32: nbytes <<= 2;
+ goto array;
+ case pxt_sint16_array:
+ sp[1].type = pxd_array | pxd_sint16;
+ goto a16;
+ case pxt_sint32_array:
+ sp[1].type = pxd_array | pxd_sint32;
+ goto a32;
+ case pxt_real32_array:
+ sp[1].type = pxd_array | pxd_real32;
+ goto a32;
+ default:
+ break;
+ }
+ break;
+ }
+ break;
+ case 31:
+ { px_attribute_t attr;
+ const byte *pnext;
+
+ switch ( tag )
+ {
+ case pxt_attr_ubyte:
+ attr = p[2];
+ pnext = p + 2;
+ goto a;
+ case pxt_attr_uint16:
+ attr = get_uint16(st, p+2);
+ pnext = p + 3;
+a: if ( attr >= px_attribute_next )
+ break;
+ /*
+ * We could check the attribute value type here, but
+ * in order to match the behavior of the H-P printers,
+ * we don't do it until we see the operator.
+ *
+ * It is legal to specify the same attribute more than
+ * once; the last value has priority. If this happens,
+ * since the order of attributes doesn't matter, we can
+ * just replace the former value on the stack.
+ */
+ sp->attribute = attr;
+ if ( st->attribute_indices[attr] != 0 )
+ { px_value_t *old_sp =
+ &st->stack[st->attribute_indices[attr]];
+ /* If the old value is on the heap, free it. */
+ if ( old_sp->type & pxd_on_heap )
+ gs_free_object(memory, (void *)old_sp->value.array.data,
+ "old value for duplicate attribute");
+ *old_sp = *sp--;
+ }
+ else
+ st->attribute_indices[attr] = sp - st->stack;
+ p = pnext;
+ continue;
+ case pxt_dataLength:
+ /*
+ * Unexpected data length operators are normally not
+ * allowed, but there might be a zero-length data
+ * block immediately following a zero-size image,
+ * which doesn't ask for any data.
+ */
+ if ( uint32at(p + 2, true /*arbitrary*/) == 0 )
+ { p += 5;
+ continue;
+ }
+ break;
+ case pxt_dataLengthByte:
+ /* See the comment under pxt_dataLength above. */
+ if ( p[2] == 0 )
+ { p += 2;
+ continue;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ /* Unknown tag value. Report an error. */
+ st->last_operator = tag; /* for error message */
+ code = gs_note_error(errorIllegalTag);
+ break;
+ }
+x: /* Save any leftover input. */
+ left = rlimit - p;
+ if ( rlimit != pr->limit )
+ { /* We were reading saved input. */
+ if ( left <= next_p - orig_p )
+ { /* We finished reading the previously saved input. */
+ /* Continue reading current input, unless we got an error. */
+ p = next_p -= left;
+ rlimit = pr->limit;
+ st->saved_count = 0;
+ if ( code >= 0 )
+ goto parse;
+ }
+ else
+ { /* There's still some previously saved input left over. */
+ memmove(st->saved, p + 1, st->saved_count = left);
+ p = next_p;
+ rlimit = pr->limit;
+ left = rlimit - p;
+ }
+ }
+ /* Except in case of error, save any remaining input. */
+ if ( code >= 0 )
+ { if ( left + st->saved_count > sizeof(st->saved) )
+ { /* Fatal error -- shouldn't happen! */
+ code = gs_note_error(errorInternalOverflow);
+ st->saved_count = 0;
+ }
+ else
+ { memcpy(&st->saved[st->saved_count], p + 1, left);
+ st->saved_count += left;
+ p = rlimit;
+ }
+ }
+ pr->ptr = p;
+ st->stack_count = sp - st->stack;
+ /* Move to the heap any arrays whose data was being referenced */
+ /* directly in the input buffer. */
+ for ( ; sp > st->stack; --sp )
+ if ( (sp->type & (pxd_array | pxd_on_heap)) == pxd_array )
+ { int code = px_save_array(sp, pxs, "px stack array to heap",
+ sp->value.array.size * value_size(sp));
+ if ( code < 0 )
+ break;
+ sp->type |= pxd_on_heap;
+ }
+ if ( code < 0 && syntax != 0 )
+ { /* Undo the state transition. */
+ st->macro_state ^= syntax->state_transition;
+ }
+ return code;
+}
+
+uint
+px_parser_data_left(px_parser_state_t *pxp)
+{
+ return pxp->data_left;
+}
+