/src/ghostpdl/pcl/pxl/pxparse.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2023 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* pxparse.c */ |
18 | | /* PCL XL parser */ |
19 | | |
20 | | #include "memory_.h" |
21 | | #include "gdebug.h" |
22 | | #include "gserrors.h" |
23 | | #include "gsio.h" |
24 | | #include "gstypes.h" |
25 | | #include "plparse.h" |
26 | | #include "pxattr.h" |
27 | | #include "pxenum.h" |
28 | | #include "pxerrors.h" |
29 | | #include "pxoper.h" |
30 | | #include "pxtag.h" |
31 | | #include "pxvalue.h" |
32 | | #include "pxparse.h" /* requires pxattr.h, pxvalue.h */ |
33 | | #include "pxptable.h" /* requires pxenum.h, pxoper.h, pxvalue.h */ |
34 | | #include "pxstate.h" |
35 | | #include "pxpthr.h" |
36 | | #include "gsstruct.h" |
37 | | #include "pxgstate.h" /* Prototype for px_high_level_pattern */ |
38 | | |
39 | | /* |
40 | | * We define the syntax of each possible tag by 4 parameters: |
41 | | * - The minimum number of input bytes required to parse it; |
42 | | * - A mask and match value for the state(s) in which it is legal; |
43 | | * - A transition mask to be xor'ed with the state. |
44 | | * See pxparse.h for the state mask values. |
45 | | */ |
46 | | typedef struct px_tag_syntax_s |
47 | | { |
48 | | byte min_input; |
49 | | byte state_value; |
50 | | byte state_mask; |
51 | | byte state_transition; |
52 | | } px_tag_syntax_t; |
53 | | |
54 | | /* Define the common syntaxes. */ |
55 | | #define N (ptsData|ptsReading) /* normal state */ |
56 | | #define I {1,0,0,0} /* illegal or unusual */ |
57 | | #define P {1,ptsInPage,ptsInPage|N,0} /* ordinary operator */ |
58 | | #define C {1,ptsInSession,ptsInSession|N,0} /* control operator */ |
59 | | #define R(p,r,t) /* reading operator */\ |
60 | | {1,ptsInSession|p|r,ptsInSession|p|N,t} |
61 | | #define D(n) {n,0,ptsData,ptsData} /* data type */ |
62 | | #define DI D(1) /* invalid data type */ |
63 | | #define A(n) {n,ptsData,ptsData,ptsData} /* attribute */ |
64 | | |
65 | | /* Define the syntax of all tags. */ |
66 | | static const px_tag_syntax_t tag_syntax[256] = { |
67 | | /*0x*/ |
68 | | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, |
69 | | /*1x*/ |
70 | | I, I, I, I, I, I, I, I, I, I, I, {2, 0, 0, 0}, I, I, I, I, |
71 | | /*2x*/ |
72 | | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, |
73 | | /*3x*/ |
74 | | I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, |
75 | | /*4x*/ |
76 | | {2, 0, ptsInSession | N, 0}, |
77 | | {1, 0, ptsInSession | N, ptsInSession}, |
78 | | {1, ptsInSession, ptsInSession | ptsInPage | N, ptsInSession}, |
79 | | {1, ptsInSession, ptsInSession | ptsInPage | N, ptsInPage}, |
80 | | {1, ptsInPage, ptsInPage | N, ptsInPage}, |
81 | | P, {1, 1, 1, 0}, C, |
82 | | C, C, P, P, P, P, P, R(0, 0, ptsReadingFont), |
83 | | /*5x*/ |
84 | | R(0, ptsReadingFont, 0), |
85 | | R(0, ptsReadingFont, ptsReadingFont), |
86 | | R(0, 0, ptsReadingChar), |
87 | | R(0, ptsReadingChar, 0), |
88 | | R(0, ptsReadingChar, ptsReadingChar), |
89 | | C, P, P, |
90 | | P, P, P, |
91 | | {1, ptsInSession, ptsInSession | ptsExecStream | N, ptsReadingStream}, |
92 | | {1, ptsInSession | ptsReadingStream, ptsInSession | ptsExecStream | N, 0}, |
93 | | {1, ptsInSession | ptsReadingStream, ptsInSession | ptsExecStream | N, |
94 | | ptsReadingStream}, |
95 | | {1, ptsInSession, ptsInSession | ptsReadingStream | N, 0}, |
96 | | P, |
97 | | /*6x*/ |
98 | | P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, |
99 | | /*7x*/ |
100 | | P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, |
101 | | /*8x*/ |
102 | | P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, |
103 | | /*9x*/ |
104 | | P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, |
105 | | /*ax*/ |
106 | | P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, P, |
107 | | /*bx*/ |
108 | | R(ptsInPage, 0, ptsReadingImage), |
109 | | R(ptsInPage, ptsReadingImage, 0), |
110 | | R(ptsInPage, ptsReadingImage, ptsReadingImage), |
111 | | R(ptsInPage, 0, ptsReadingRastPattern), |
112 | | R(ptsInPage, ptsReadingRastPattern, 0), |
113 | | R(ptsInPage, ptsReadingRastPattern, ptsReadingRastPattern), |
114 | | R(ptsInPage, 0, ptsReadingScan), |
115 | | P, |
116 | | R(ptsInPage, ptsReadingScan, ptsReadingScan), |
117 | | R(ptsInPage, ptsReadingScan, 0), |
118 | | P, P, P, P, P, P, |
119 | | /*cx*/ |
120 | | D(2), D(3), D(5), D(3), D(5), D(5), DI, DI, |
121 | | D(3), D(3), D(3), D(3), D(3), D(3), DI, DI, |
122 | | /*dx*/ |
123 | | D(3), D(5), D(9), D(5), D(9), D(9), DI, DI, |
124 | | DI, DI, DI, DI, DI, DI, DI, DI, |
125 | | /*ex*/ |
126 | | D(5), D(9), D(17), D(9), D(17), D(17), DI, DI, |
127 | | DI, DI, DI, DI, DI, DI, DI, DI, |
128 | | /*fx*/ |
129 | | I, I, I, I, I, I, I, I, |
130 | | A(2), A(3), {5, 0, 0, 0}, {2, 0, 0, 0}, I, I, I, I |
131 | | }; |
132 | | #undef I |
133 | | #undef P |
134 | | #undef C |
135 | | #undef R |
136 | | #undef D |
137 | | #undef DI |
138 | | #undef A |
139 | | |
140 | | /* Allocate a parser state. */ |
141 | | px_parser_state_t * |
142 | | px_process_alloc(gs_memory_t * memory) |
143 | 8.09k | { |
144 | 8.09k | px_parser_state_t *st = (px_parser_state_t *) gs_alloc_bytes(memory, |
145 | 8.09k | sizeof |
146 | 8.09k | (px_parser_state_t), |
147 | 8.09k | "px_process_alloc"); |
148 | | |
149 | 8.09k | if (st == 0) |
150 | 0 | return 0; |
151 | 8.09k | st->memory = memory; |
152 | 8.09k | px_process_init(st, true); |
153 | 8.09k | return st; |
154 | 8.09k | } |
155 | | |
156 | | /* Release a parser state. */ |
157 | | void |
158 | | px_process_release(px_parser_state_t * st) |
159 | 8.09k | { |
160 | 8.09k | gs_free_object(st->memory, st, "px_process_alloc"); |
161 | 8.09k | } |
162 | | |
163 | | /* Initialize the parser state. */ |
164 | | void |
165 | | px_process_init(px_parser_state_t * st, bool big_endian) |
166 | 22.0k | { |
167 | 22.0k | st->big_endian = big_endian; |
168 | 22.0k | st->operator_count = 0; |
169 | 22.0k | st->parent_operator_count = 0; |
170 | 22.0k | st->last_operator = pxtNull; |
171 | 22.0k | st->saved_count = 0; |
172 | 22.0k | st->data_left = 0; |
173 | 22.0k | st->macro_state = ptsInitial; |
174 | 22.0k | st->stack_count = 0; |
175 | 22.0k | st->data_proc = 0; |
176 | 22.0k | { |
177 | 22.0k | int i; |
178 | | |
179 | 463k | for (i = 0; i < max_px_args; ++i) |
180 | 441k | st->args.pv[i] = 0; |
181 | 22.0k | } |
182 | 22.0k | st->args.parser = 0; /* for garbage collector */ |
183 | 22.0k | memset(st->attribute_indices, 0, px_attribute_next); |
184 | 22.0k | } |
185 | | |
186 | | /* Get numeric values from the input. */ |
187 | 36.3k | #define get_uint16(st, p) uint16at(p, st->big_endian) |
188 | 73.0k | #define get_sint16(st, p) sint16at(p, st->big_endian) |
189 | 3.15k | #define get_uint32(st, p) uint32at(p, st->big_endian) |
190 | 22 | #define get_sint32(st, p) sint32at(p, st->big_endian) |
191 | 1.97k | #define get_real32(st, p) real32at(p, st->big_endian) |
192 | | |
193 | | /* Move an array to the heap for persistence if needed. */ |
194 | | /* See pxoper.h for details. */ |
195 | | static int |
196 | | px_save_array(px_value_t * pv, px_state_t * pxs, client_name_t cname, |
197 | | uint nbytes) |
198 | 512 | { |
199 | 512 | if (pv->type & pxd_on_heap) { /* Turn off the "on heap" bit, to prevent freeing. */ |
200 | 0 | pv->type &= ~pxd_on_heap; |
201 | 512 | } else { /* Allocate a heap copy. Only the first nbytes bytes */ |
202 | | /* of the data are valid. */ |
203 | 512 | uint num_elements = pv->value.array.size; |
204 | 512 | uint elt_size = value_size(pv); |
205 | 512 | byte *copy = gs_alloc_byte_array(pxs->memory, num_elements, |
206 | 512 | elt_size, cname); |
207 | | |
208 | 512 | if (copy == 0) |
209 | 0 | return_error(errorInsufficientMemory); |
210 | 512 | memcpy(copy, pv->value.array.data, nbytes); |
211 | 512 | pv->value.array.data = copy; |
212 | 512 | } |
213 | 512 | return 0; |
214 | 512 | } |
215 | | |
216 | | /* Clear the stack and the attribute indices, */ |
217 | | /* and free heap-allocated arrays. */ |
218 | | #define clear_stack()\ |
219 | 195k | for ( ; sp > st->stack; --sp )\ |
220 | 99.3k | { if ( sp->type & pxd_on_heap )\ |
221 | 99.3k | gs_free_object(memory, (void *)sp->value.array.data,\ |
222 | 99.3k | "px stack pop");\ |
223 | 99.3k | st->attribute_indices[sp->attribute] = 0;\ |
224 | 99.3k | } |
225 | | |
226 | | /* Define data tracing if debugging. */ |
227 | | #ifdef DEBUG |
228 | | # define trace_data(mem, format, cast, ptr, count)\ |
229 | | do\ |
230 | | { uint i_;\ |
231 | | for ( i_ = 0; i_ < count; ++i_ )\ |
232 | | dmprintf1(mem, format, (cast)((ptr)[i_]));\ |
233 | | dmputc(mem, '\n');\ |
234 | | }\ |
235 | | while (0) |
236 | | static void |
237 | | trace_array_data(const gs_memory_t * mem, const char *label, |
238 | | const px_value_t * pav) |
239 | | { |
240 | | px_data_type_t type = pav->type; |
241 | | const byte *ptr = pav->value.array.data; |
242 | | uint count = pav->value.array.size; |
243 | | bool big_endian = (type & pxd_big_endian) != 0; |
244 | | bool text = (type & pxd_ubyte) != 0; |
245 | | uint i; |
246 | | |
247 | | dmputs(mem, label); |
248 | | dmputs(mem, (type & pxd_ubyte ? " <" : " {")); |
249 | | for (i = 0; i < count; ++i) { |
250 | | if (!(i & 15) && i) { |
251 | | const char *p; |
252 | | |
253 | | dmputs(mem, "\n "); |
254 | | for (p = label; *p; ++p) |
255 | | dmputc(mem, ' '); |
256 | | } |
257 | | if (type & pxd_ubyte) { |
258 | | dmprintf1(mem, "%02x ", ptr[i]); |
259 | | if (ptr[i] < 32 || ptr[i] > 126) |
260 | | text = false; |
261 | | } else if (type & pxd_uint16) |
262 | | dmprintf1(mem, "%u ", uint16at(ptr + i * 2, big_endian)); |
263 | | else if (type & pxd_sint16) |
264 | | dmprintf1(mem, "%d ", sint16at(ptr + i * 2, big_endian)); |
265 | | else if (type & pxd_uint32) |
266 | | dmprintf1(mem, "%lu ", (ulong) uint32at(ptr + i * 4, big_endian)); |
267 | | else if (type & pxd_sint32) |
268 | | dmprintf1(mem, "%ld ", (long)sint32at(ptr + i * 4, big_endian)); |
269 | | else if (type & pxd_real32) |
270 | | dmprintf1(mem, "%g ", real32at(ptr + i * 4, big_endian)); |
271 | | else |
272 | | dmputs(mem, "? "); |
273 | | } |
274 | | dmputs(mem, (type & pxd_ubyte ? ">\n" : "}\n")); |
275 | | if (text) { |
276 | | dmputs(mem, "%chars: \""); |
277 | | debug_print_string(mem, ptr, count); |
278 | | dmputs(mem, "\"\n"); |
279 | | } |
280 | | } |
281 | | # define trace_array(mem,pav)\ |
282 | | if ( gs_debug_c('I') )\ |
283 | | trace_array_data(mem,"array:", pav) |
284 | | #else |
285 | | # define trace_data(mem, format, cast, ptr, count) DO_NOTHING |
286 | 11.1k | # define trace_array(mem,pav) DO_NOTHING |
287 | | #endif |
288 | | |
289 | | /* Process a buffer of PCL XL commands. */ |
290 | | int |
291 | | px_process(px_parser_state_t * st, /* lgtm [cpp/use-of-goto] */ |
292 | | px_state_t * pxs, stream_cursor_read * pr) |
293 | 5.09k | { |
294 | 5.09k | const byte *orig_p = pr->ptr; |
295 | 5.09k | const byte *next_p = orig_p; /* start of data not copied to saved */ |
296 | 5.09k | const byte *p; |
297 | 5.09k | const byte *rlimit; |
298 | 5.09k | px_value_t *sp = &st->stack[st->stack_count]; |
299 | | |
300 | 101k | #define stack_limit &st->stack[max_stack - 1] |
301 | 5.09k | gs_memory_t *memory = st->memory; |
302 | 5.09k | int code = 0; |
303 | 5.09k | uint left; |
304 | 5.09k | uint min_left; |
305 | 5.09k | px_tag_t tag; |
306 | 5.09k | const px_tag_syntax_t *syntax = 0; |
307 | | |
308 | 5.09k | st->args.parser = st; |
309 | 5.09k | st->parent_operator_count = 0; /* in case of error */ |
310 | | /* Check for leftover data from the previous call. */ |
311 | 5.25k | parse:if (st->saved_count) { /* Fill up the saved buffer so we can make progress. */ |
312 | 232 | int move = min(sizeof(st->saved) - st->saved_count, |
313 | 232 | pr->limit - next_p); |
314 | | |
315 | 232 | memcpy(&st->saved[st->saved_count], next_p + 1, move); |
316 | 232 | next_p += move; |
317 | 232 | p = st->saved - 1; |
318 | 232 | rlimit = p + st->saved_count + move; |
319 | 5.02k | } else { /* No leftover data, just read from the input. */ |
320 | 5.02k | p = next_p; |
321 | 5.02k | rlimit = pr->limit; |
322 | 5.02k | } |
323 | 32.3k | top:if (st->data_left) { /* We're in the middle of reading an array or data block. */ |
324 | 14.0k | if (st->data_proc) { /* This is a data block. */ |
325 | 13.8k | uint avail = min(rlimit - p, st->data_left); |
326 | 13.8k | uint used; |
327 | | |
328 | 13.8k | st->args.source.available = avail; |
329 | 13.8k | st->args.source.data = p + 1; |
330 | 13.8k | code = (*st->data_proc) (&st->args, pxs); |
331 | | /* If we get a 'remap_color' error, it means we are dealing with a |
332 | | * pattern, and the device supports high level patterns. So we must |
333 | | * use our high level pattern implementation. |
334 | | */ |
335 | 13.8k | if (code == gs_error_Remap_Color) { |
336 | 0 | code = px_high_level_pattern(pxs->pgs); |
337 | 0 | code = (*st->data_proc) (&st->args, pxs); |
338 | 0 | } |
339 | 13.8k | used = st->args.source.data - (p + 1); |
340 | | #ifdef DEBUG |
341 | | if (gs_debug_c('I')) { |
342 | | px_value_t data_array; |
343 | | |
344 | | data_array.type = pxd_ubyte; |
345 | | data_array.value.array.data = p + 1; |
346 | | data_array.value.array.size = used; |
347 | | trace_array_data(pxs->memory, "data:", &data_array); |
348 | | } |
349 | | #endif |
350 | 13.8k | p = st->args.source.data - 1; |
351 | 13.8k | st->data_left -= used; |
352 | 13.8k | if (code < 0) { |
353 | 26 | st->args.source.position = 0; |
354 | 26 | goto x; |
355 | 13.8k | } else if ((code == pxNeedData) |
356 | 13.4k | || (code == pxPassThrough && st->data_left != 0)) { |
357 | 426 | code = 0; /* exit for more data */ |
358 | 426 | goto x; |
359 | 13.4k | } else { |
360 | 13.4k | st->args.source.position = 0; |
361 | 13.4k | st->data_proc = 0; |
362 | 13.4k | if (st->data_left != 0) { |
363 | 70 | code = gs_note_error(errorExtraData); |
364 | 70 | goto x; |
365 | 70 | } |
366 | 13.3k | clear_stack(); |
367 | 13.3k | } |
368 | 13.8k | } else { /* This is an array. */ |
369 | 183 | uint size = sp->value.array.size; |
370 | 183 | uint scale = value_size(sp); |
371 | 183 | uint nbytes = size * scale; |
372 | 183 | byte *dest = |
373 | 183 | (byte *) sp->value.array.data + nbytes - st->data_left; |
374 | | |
375 | 183 | left = rlimit - p; |
376 | 183 | if (left < st->data_left) { /* We still don't have enough data to fill the array. */ |
377 | 35 | memcpy(dest, p + 1, left); |
378 | 35 | st->data_left -= left; |
379 | 35 | p = rlimit; |
380 | 35 | code = 0; |
381 | 35 | goto x; |
382 | 35 | } |
383 | | /* Complete the array and continue parsing. */ |
384 | 148 | memcpy(dest, p + 1, st->data_left); |
385 | 148 | trace_array(memory, sp); |
386 | 148 | p += st->data_left; |
387 | 148 | } |
388 | 13.4k | st->data_left = 0; |
389 | 18.3k | } else if (st->data_proc) { /* An operator is awaiting data. */ |
390 | | /* Skip white space until we find some. */ |
391 | 13.6k | code = 0; /* in case we exit */ |
392 | | /* special case - VendorUnique has a length attribute which |
393 | | we've already parsed and error checked */ |
394 | 13.6k | if (st->data_proc == pxVendorUnique) { |
395 | 0 | st->data_left = |
396 | 0 | st->stack[st->attribute_indices[pxaVUDataLength]].value.i; |
397 | 0 | goto top; |
398 | 13.6k | } else { |
399 | 13.8k | while ((left = rlimit - p) != 0) { |
400 | 13.8k | switch ((tag = p[1])) { |
401 | 251 | case pxtNull: |
402 | 251 | case pxtHT: |
403 | 251 | case pxtLF: |
404 | 252 | case pxtVT: |
405 | 252 | case pxtFF: |
406 | 253 | case pxtCR: |
407 | 253 | ++p; |
408 | 253 | continue; |
409 | 1.11k | case pxt_dataLength: |
410 | 1.11k | if (left < 5) |
411 | 0 | goto x; /* can't look ahead */ |
412 | 1.11k | st->data_left = get_uint32(st, p + 2); |
413 | 1.11k | if_debug2m('i', memory, "tag= 0x%2x data, length %u\n", |
414 | 1.11k | p[1], st->data_left); |
415 | 1.11k | p += 5; |
416 | 1.11k | goto top; |
417 | 12.4k | case pxt_dataLengthByte: |
418 | 12.4k | if (left < 2) |
419 | 21 | goto x; /* can't look ahead */ |
420 | 12.4k | st->data_left = p[2]; |
421 | 12.4k | if_debug2m('i', memory, "tag= 0x%2x data, length %u\n", |
422 | 12.4k | p[1], st->data_left); |
423 | 12.4k | p += 2; |
424 | 12.4k | goto top; |
425 | 45 | default: |
426 | 45 | { |
427 | 45 | code = gs_note_error(errorMissingData); |
428 | 45 | goto x; |
429 | 12.4k | } |
430 | 13.8k | } |
431 | 13.8k | } |
432 | 13.6k | } |
433 | 13.6k | } |
434 | 18.2k | st->args.source.position = 0; |
435 | 18.2k | st->args.source.available = 0; |
436 | 320k | while ((left = rlimit - p) != 0 && |
437 | 320k | left >= (min_left = (syntax = &tag_syntax[tag = p[1]])->min_input) |
438 | 320k | ) { |
439 | 320k | int count; |
440 | | |
441 | | #ifdef DEBUG |
442 | | if (gs_debug_c('i')) { |
443 | | dmprintf1(memory, "tag= 0x%02x ", tag); |
444 | | if (tag == pxt_attr_ubyte || tag == pxt_attr_uint16) { |
445 | | px_attribute_t attr = |
446 | | (tag == pxt_attr_ubyte ? p[2] : get_uint16(st, p + 2)); |
447 | | const char *aname = px_attribute_names[attr]; |
448 | | |
449 | | if (aname) |
450 | | dmprintf1(memory, " @%s\n", aname); |
451 | | else |
452 | | dmprintf1(memory, " attribute %u ???\n", attr); |
453 | | } else { |
454 | | const char *format; |
455 | | const char *tname; |
456 | | bool operator = false; |
457 | | |
458 | | if (tag < 0x40) |
459 | | format = "%s\n", tname = px_tag_0_names[tag]; |
460 | | else if (tag < 0xc0) |
461 | | format = "%s", tname = px_operator_names[tag - 0x40], |
462 | | operator = true; |
463 | | else { |
464 | | tname = px_tag_c0_names[tag - 0xc0]; |
465 | | if (tag < 0xf0) |
466 | | format = " %s"; /* data values follow */ |
467 | | else |
468 | | format = "%s\n"; |
469 | | } |
470 | | if (tname) { |
471 | | dmprintf1(memory, format, tname); |
472 | | if (operator) |
473 | | dmprintf1(memory, " (%ld)\n", st->operator_count + 1); |
474 | | } else |
475 | | dmputs(memory, "???\n"); |
476 | | } |
477 | | } |
478 | | #endif |
479 | 320k | if ((st->macro_state & syntax->state_mask) != syntax->state_value) { |
480 | | /* |
481 | | * We should probably distinguish here between |
482 | | * out-of-context operators and illegal tags, but it's too |
483 | | * much trouble. |
484 | | */ |
485 | 748 | code = gs_note_error(errorIllegalOperatorSequence); |
486 | 748 | if (tag >= 0x40 && tag < 0xc0) |
487 | 577 | st->last_operator = tag; |
488 | 748 | goto x; |
489 | 748 | } |
490 | 319k | st->macro_state ^= syntax->state_transition; |
491 | 319k | switch (tag >> 3) { |
492 | 17.9k | case 0: |
493 | 17.9k | switch (tag) { |
494 | 17.8k | case pxtNull: |
495 | 17.8k | ++p; |
496 | 17.8k | continue; |
497 | 161 | default: |
498 | 161 | break; |
499 | 17.9k | } |
500 | 161 | break; |
501 | 283 | case 1: |
502 | 283 | switch (tag) { |
503 | 50 | case pxtHT: |
504 | 227 | case pxtLF: |
505 | 235 | case pxtVT: |
506 | 248 | case pxtFF: |
507 | 258 | case pxtCR: |
508 | 258 | ++p; |
509 | 258 | continue; |
510 | 25 | default: |
511 | 25 | break; |
512 | 283 | } |
513 | 25 | break; |
514 | 2.32k | case 3: |
515 | 2.32k | if (tag == pxt1b) { /* ESC *//* Check for UEL */ |
516 | 2.30k | if (memcmp(p + 1, "\033%-12345X", min(left, 9))) |
517 | 349 | break; /* not UEL, error */ |
518 | 1.95k | if (left < 9) |
519 | 2 | goto x; /* need more data */ |
520 | 1.94k | p += 9; |
521 | 1.94k | code = e_ExitLanguage; |
522 | 1.94k | goto x; |
523 | 1.95k | } |
524 | 20 | break; |
525 | 127 | case 4: |
526 | 127 | switch (tag) { |
527 | 87 | case pxtSpace: |
528 | | /* break; will error, compatible with lj */ |
529 | | /* ++p;continue; silently ignores the space */ |
530 | 87 | ++p; |
531 | 87 | continue; |
532 | 40 | default: |
533 | 40 | break; |
534 | 127 | } |
535 | 40 | break; |
536 | 3.72k | case 8: |
537 | 5.92k | case 9: |
538 | 8.25k | case 10: |
539 | 8.59k | case 11: |
540 | 19.7k | case 12: |
541 | 38.2k | case 13: |
542 | 40.8k | case 14: |
543 | 48.8k | case 15: |
544 | 73.8k | case 16: |
545 | 73.8k | case 17: |
546 | 81.6k | case 18: |
547 | 91.9k | case 19: |
548 | 92.8k | case 20: |
549 | 96.0k | case 21: |
550 | 96.5k | case 22: |
551 | 96.6k | case 23: |
552 | | /* Operators */ |
553 | | /* Make sure that we have all the required attributes, */ |
554 | | /* and no attributes that are neither required nor */ |
555 | | /* optional. (It's up to the operator to make any */ |
556 | | /* more precise checks than this. */ |
557 | 96.6k | st->operator_count++; |
558 | | /* if this is a passthrough operator we have to tell |
559 | | the passthrough module if this operator was |
560 | | preceded by another passthrough operator or a |
561 | | different xl operator */ |
562 | 96.6k | if (tag == pxtPassThrough) { |
563 | 38 | pxpcl_passthroughcontiguous(pxs, st->last_operator == tag); |
564 | 96.5k | } else if (st->last_operator == pxtPassThrough) { |
565 | 0 | pxpcl_endpassthroughcontiguous(pxs); |
566 | 0 | } |
567 | | |
568 | 96.6k | st->last_operator = tag; |
569 | 96.6k | { |
570 | 96.6k | const px_operator_definition_t *pod = |
571 | 96.6k | &px_operator_definitions[tag - 0x40]; |
572 | 96.6k | int left = sp - st->stack; |
573 | 96.6k | const byte /*px_attribute_t */ * pal = pod->attrs; |
574 | 96.6k | px_value_t **ppv = st->args.pv; |
575 | 96.6k | bool required = true; |
576 | 96.6k | code = 0; |
577 | | /* |
578 | | * Scan the attributes. Illegal attributes take priority |
579 | | * over missing attributes, which in turn take priority |
580 | | * over illegal data types. |
581 | | */ |
582 | 470k | for (;; ++pal, ++ppv) { |
583 | 470k | px_attribute_t attr = *pal; |
584 | 470k | uint index; |
585 | | |
586 | 470k | if (!attr) { /* |
587 | | * We've reached the end of either the required or |
588 | | * the optional attribute list. |
589 | | */ |
590 | 193k | if (!required) |
591 | 96.6k | break; |
592 | 96.6k | required = false; |
593 | 96.6k | --ppv; /* cancel incrementing */ |
594 | 96.6k | continue; |
595 | 193k | } |
596 | 276k | if ((index = st->attribute_indices[attr]) == 0) { |
597 | 176k | if (required) |
598 | 147 | code = gs_note_error(errorMissingAttribute); |
599 | 176k | else |
600 | 176k | *ppv = 0; |
601 | 176k | } else { /* Check the attribute data type and value. */ |
602 | 99.9k | px_value_t *pv = *ppv = &st->stack[index]; |
603 | 99.9k | const px_attr_value_type_t *pavt = |
604 | 99.9k | &px_attr_value_types[attr]; |
605 | 99.9k | int acode; |
606 | | |
607 | 99.9k | if ((~pavt->mask & pv->type & |
608 | 99.9k | (pxd_structure | pxd_representation)) || |
609 | 99.9k | (pavt->mask == (pxd_scalar | pxd_ubyte) && |
610 | 39.7k | (pv->value.i < 0 |
611 | 39.7k | || pv->value.i > pavt->limit)) |
612 | 99.9k | ) { |
613 | 34 | if (code >= 0) |
614 | 34 | code = |
615 | 34 | gs_note_error |
616 | 34 | (errorIllegalAttributeDataType); |
617 | 34 | } |
618 | 99.9k | if (pavt->proc != 0 |
619 | 12.9k | && (acode = (*pavt->proc) (pv)) < 0) { |
620 | 14 | if (code >= 0) |
621 | 10 | code = acode; |
622 | 14 | } |
623 | 99.9k | --left; |
624 | 99.9k | } |
625 | 276k | } |
626 | | |
627 | | /* Make sure there are no attributes left over. */ |
628 | 96.6k | if (left) |
629 | 146 | code = gs_note_error(errorIllegalAttribute); |
630 | 96.6k | if (code >= 0) { |
631 | 96.3k | st->args.source.phase = 0; |
632 | 96.3k | code = (*pod->proc) (&st->args, pxs); |
633 | | /* If we get a 'remap_color' error, it means we are dealing with a |
634 | | * pattern, and the device supports high level patterns. So we must |
635 | | * use our high level pattern implementation. |
636 | | */ |
637 | 96.3k | if (code == gs_error_Remap_Color) { |
638 | 0 | code = px_high_level_pattern(pxs->pgs); |
639 | 0 | if (code < 0) |
640 | 0 | goto x; |
641 | 0 | code = (*pod->proc) (&st->args, pxs); |
642 | 0 | } |
643 | 96.3k | } |
644 | 96.6k | if (code < 0) |
645 | 428 | goto x; |
646 | | /* Check whether the operator wanted source data. */ |
647 | 96.2k | if (code == pxNeedData) { |
648 | 13.5k | if (!pxs->data_source_open) { |
649 | 0 | code = gs_note_error(errorDataSourceNotOpen); |
650 | 0 | goto x; |
651 | 0 | } |
652 | 13.5k | st->data_proc = pod->proc; |
653 | 13.5k | ++p; |
654 | 13.5k | goto top; |
655 | 13.5k | } |
656 | 96.2k | } |
657 | 82.6k | clear_stack(); |
658 | 82.6k | ++p; |
659 | 82.6k | continue; |
660 | 66.0k | case 24: |
661 | 66.0k | sp[1].type = pxd_scalar; |
662 | 66.0k | count = 1; |
663 | 66.0k | goto data; |
664 | 22.2k | case 26: |
665 | 22.2k | sp[1].type = pxd_xy; |
666 | 22.2k | count = 2; |
667 | 22.2k | goto data; |
668 | 1.86k | case 28: |
669 | 1.86k | sp[1].type = pxd_box; |
670 | 1.86k | count = 4; |
671 | 1.86k | goto data; |
672 | | /* Scalar, point, and box data */ |
673 | 90.1k | data:{ |
674 | 90.1k | int i; |
675 | | |
676 | 90.1k | if (sp == stack_limit) { |
677 | 0 | code = gs_note_error(errorInternalOverflow); |
678 | 0 | goto x; |
679 | 0 | } |
680 | 90.1k | ++sp; |
681 | 90.1k | sp->attribute = 0; |
682 | 90.1k | p += 2; |
683 | | #ifdef DEBUG |
684 | | # define trace_scalar(mem, format, cast, alt)\ |
685 | | if ( gs_debug_c('i') )\ |
686 | | trace_data(mem, format, cast, sp->value.alt, count) |
687 | | #else |
688 | 90.1k | # define trace_scalar(mem, format, cast, alt) DO_NOTHING |
689 | 90.1k | #endif |
690 | 90.1k | switch (tag & 7) { |
691 | 52.1k | case pxt_ubyte & 7: |
692 | 52.1k | sp->type |= pxd_ubyte; |
693 | 104k | for (i = 0; i < count; ++p, ++i) |
694 | 52.1k | sp->value.ia[i] = *p; |
695 | 64.3k | dux:trace_scalar(pxs->memory, " %lu", ulong, |
696 | 64.3k | ia); |
697 | 64.3k | --p; |
698 | 64.3k | continue; |
699 | 11.1k | case pxt_uint16 & 7: |
700 | 11.1k | sp->type |= pxd_uint16; |
701 | 26.6k | for (i = 0; i < count; p += 2, ++i) |
702 | 15.4k | sp->value.ia[i] = get_uint16(st, p); |
703 | 11.1k | goto dux; |
704 | 1.01k | case pxt_uint32 & 7: |
705 | 1.01k | sp->type |= pxd_uint32; |
706 | 2.04k | for (i = 0; i < count; p += 4, ++i) |
707 | 1.03k | sp->value.ia[i] = get_uint32(st, p); |
708 | 1.01k | goto dux; |
709 | 24.9k | case pxt_sint16 & 7: |
710 | 24.9k | sp->type |= pxd_sint16; |
711 | 73.0k | for (i = 0; i < count; p += 2, ++i) |
712 | 48.1k | sp->value.ia[i] = get_sint16(st, p); |
713 | 24.9k | dsx:trace_scalar(pxs->memory, " %ld", long, |
714 | 24.9k | ia); |
715 | 24.9k | --p; |
716 | 24.9k | continue; |
717 | 7 | case pxt_sint32 & 7: |
718 | 7 | sp->type |= pxd_sint32; |
719 | 22 | for (i = 0; i < count; p += 4, ++i) |
720 | 15 | sp->value.ia[i] = get_sint32(st, p); |
721 | 7 | goto dsx; |
722 | 871 | case pxt_real32 & 7: |
723 | 871 | sp->type |= pxd_real32; |
724 | 1.97k | for (i = 0; i < count; p += 4, ++i) |
725 | 1.10k | sp->value.ra[i] = get_real32(st, p); |
726 | 871 | trace_scalar(pxs->memory, " %g", double, ra); |
727 | | |
728 | 871 | --p; |
729 | 871 | continue; |
730 | 5 | default: |
731 | 5 | break; |
732 | 90.1k | } |
733 | 90.1k | } |
734 | 5 | break; |
735 | 11.2k | case 25: |
736 | | /* Array data */ |
737 | 11.2k | { |
738 | 11.2k | const byte *dp; |
739 | 11.2k | uint nbytes; |
740 | | |
741 | 11.2k | if (sp == stack_limit) { |
742 | 0 | code = gs_note_error(errorInternalOverflow); |
743 | 0 | goto x; |
744 | 0 | } |
745 | 11.2k | switch (p[2]) { |
746 | 1.51k | case pxt_ubyte: |
747 | 1.51k | sp[1].value.array.size = p[3]; |
748 | 1.51k | dp = p + 4; |
749 | 1.51k | break; |
750 | 9.68k | case pxt_uint16: |
751 | 9.68k | if (left < 4) { |
752 | 7 | if_debug0m('i', memory, "...\n"); |
753 | | /* Undo the state transition. */ |
754 | 7 | st->macro_state ^= syntax->state_transition; |
755 | 7 | goto x; |
756 | 7 | } |
757 | 9.67k | sp[1].value.array.size = get_uint16(st, p + 3); |
758 | 9.67k | dp = p + 5; |
759 | 9.67k | break; |
760 | 24 | default: |
761 | 24 | st->last_operator = tag; /* for error message */ |
762 | 24 | code = gs_note_error(errorIllegalTag); |
763 | 24 | goto x; |
764 | 11.2k | } |
765 | 11.1k | nbytes = sp[1].value.array.size; |
766 | 11.1k | if_debug1m('i', memory, "[%u]\n", sp[1].value.array.size); |
767 | 11.1k | switch (tag) { |
768 | 11.1k | case pxt_ubyte_array: |
769 | 11.1k | sp[1].type = pxd_array | pxd_ubyte; |
770 | 11.1k | array:++sp; |
771 | 11.1k | if (st->big_endian) |
772 | 0 | sp->type |= pxd_big_endian; |
773 | 11.1k | sp->value.array.data = dp; |
774 | 11.1k | sp->attribute = 0; |
775 | | /* Check whether we have enough data for the entire */ |
776 | | /* array. */ |
777 | 11.1k | if (rlimit + 1 - dp < nbytes) { /* Exit now, continue reading when we return. */ |
778 | 191 | uint avail = rlimit + 1 - dp; |
779 | | |
780 | 191 | code = px_save_array(sp, pxs, "partial array", |
781 | 191 | avail); |
782 | 191 | if (code < 0) |
783 | 0 | goto x; |
784 | 191 | sp->type |= pxd_on_heap; |
785 | 191 | st->data_left = nbytes - avail; |
786 | 191 | st->data_proc = 0; |
787 | 191 | p = rlimit; |
788 | 191 | goto x; |
789 | 191 | } |
790 | 10.9k | p = dp + nbytes - 1; |
791 | 10.9k | trace_array(memory, sp); |
792 | 10.9k | continue; |
793 | 0 | case pxt_uint16_array: |
794 | 0 | sp[1].type = pxd_array | pxd_uint16; |
795 | 0 | a16:nbytes <<= 1; |
796 | 0 | goto array; |
797 | 0 | case pxt_uint32_array: |
798 | 0 | sp[1].type = pxd_array | pxd_uint32; |
799 | 0 | a32:nbytes <<= 2; |
800 | 0 | goto array; |
801 | 0 | case pxt_sint16_array: |
802 | 0 | sp[1].type = pxd_array | pxd_sint16; |
803 | 0 | goto a16; |
804 | 0 | case pxt_sint32_array: |
805 | 0 | sp[1].type = pxd_array | pxd_sint32; |
806 | 0 | goto a32; |
807 | 0 | case pxt_real32_array: |
808 | 0 | sp[1].type = pxd_array | pxd_real32; |
809 | 0 | goto a32; |
810 | 2 | default: |
811 | 2 | break; |
812 | 11.1k | } |
813 | 2 | break; |
814 | 11.1k | } |
815 | 2 | break; |
816 | 100k | case 31: |
817 | 100k | { |
818 | 100k | px_attribute_t attr; |
819 | 100k | const byte *pnext; |
820 | | |
821 | 100k | switch (tag) { |
822 | 100k | case pxt_attr_ubyte: |
823 | 100k | attr = p[2]; |
824 | 100k | pnext = p + 2; |
825 | 100k | goto a; |
826 | 2 | case pxt_attr_uint16: |
827 | 2 | attr = get_uint16(st, p + 2); |
828 | 2 | pnext = p + 3; |
829 | 100k | a:if (attr >= |
830 | 100k | px_attribute_next) |
831 | 86 | break; |
832 | | /* |
833 | | * We could check the attribute value type here, but |
834 | | * in order to match the behavior of the H-P printers, |
835 | | * we don't do it until we see the operator. |
836 | | * |
837 | | * It is legal to specify the same attribute more than |
838 | | * once; the last value has priority. If this happens, |
839 | | * since the order of attributes doesn't matter, we can |
840 | | * just replace the former value on the stack. |
841 | | */ |
842 | 100k | sp->attribute = attr; |
843 | 100k | if (st->attribute_indices[attr] != 0) { |
844 | 2 | px_value_t *old_sp = |
845 | 2 | &st->stack[st->attribute_indices[attr]]; |
846 | | /* If the old value is on the heap, free it. */ |
847 | 2 | if (old_sp->type & pxd_on_heap) |
848 | 0 | gs_free_object(memory, |
849 | 2 | (void *)old_sp->value. |
850 | 2 | array.data, |
851 | 2 | "old value for duplicate attribute"); |
852 | 2 | *old_sp = *sp--; |
853 | 2 | } else |
854 | 100k | st->attribute_indices[attr] = sp - st->stack; |
855 | 100k | p = pnext; |
856 | 100k | continue; |
857 | 11 | case pxt_dataLength: |
858 | | /* |
859 | | * Unexpected data length operators are normally not |
860 | | * allowed, but there might be a zero-length data |
861 | | * block immediately following a zero-size image, |
862 | | * which doesn't ask for any data. |
863 | | */ |
864 | 11 | if (uint32at(p + 2, true /*arbitrary */ ) == 0) { |
865 | 0 | p += 5; |
866 | 0 | continue; |
867 | 0 | } |
868 | 11 | break; |
869 | 91 | case pxt_dataLengthByte: |
870 | | /* See the comment under pxt_dataLength above. */ |
871 | 91 | if (p[2] == 0) { |
872 | 77 | p += 2; |
873 | 77 | continue; |
874 | 77 | } |
875 | 14 | break; |
876 | 72 | default: |
877 | 72 | break; |
878 | 100k | } |
879 | 100k | } |
880 | 183 | break; |
881 | 262 | default: |
882 | 262 | break; |
883 | 319k | } |
884 | | /* Unknown tag value. Report an error. */ |
885 | 1.04k | st->last_operator = tag; /* for error message */ |
886 | 1.04k | code = gs_note_error(errorIllegalTag); |
887 | 1.04k | break; |
888 | 319k | } |
889 | 5.25k | x: /* Save any leftover input. */ |
890 | 5.25k | left = rlimit - p; |
891 | 5.25k | if (rlimit != pr->limit) { /* We were reading saved input. */ |
892 | 232 | if (left <= next_p - orig_p) { /* We finished reading the previously saved input. */ |
893 | | /* Continue reading current input, unless we got an error. */ |
894 | 228 | p = next_p -= left; |
895 | 228 | rlimit = pr->limit; |
896 | 228 | st->saved_count = 0; |
897 | 228 | if (code >= 0) |
898 | 153 | goto parse; |
899 | 228 | } else { /* There's still some previously saved input left over. */ |
900 | 4 | memmove(st->saved, p + 1, st->saved_count = left); |
901 | 4 | p = next_p; |
902 | 4 | rlimit = pr->limit; |
903 | 4 | left = rlimit - p; |
904 | 4 | } |
905 | 232 | } |
906 | | /* Except in case of error, save any remaining input. */ |
907 | 5.09k | if (code >= 0) { |
908 | 762 | if (left + st->saved_count > sizeof(st->saved)) { /* Fatal error -- shouldn't happen! */ |
909 | 7 | code = gs_note_error(errorInternalOverflow); |
910 | 7 | st->saved_count = 0; |
911 | 755 | } else { |
912 | 755 | memcpy(&st->saved[st->saved_count], p + 1, left); |
913 | 755 | st->saved_count += left; |
914 | 755 | p = rlimit; |
915 | 755 | } |
916 | 762 | } |
917 | 5.09k | pr->ptr = p; |
918 | 5.09k | st->stack_count = sp - st->stack; |
919 | | /* Move to the heap any arrays whose data was being referenced */ |
920 | | /* directly in the input buffer. */ |
921 | 7.90k | for (; sp > st->stack; --sp) |
922 | 2.80k | if ((sp->type & (pxd_array | pxd_on_heap)) == pxd_array) { |
923 | 321 | int code = px_save_array(sp, pxs, "px stack array to heap", |
924 | 321 | sp->value.array.size * value_size(sp)); |
925 | | |
926 | 321 | if (code < 0) |
927 | 0 | break; |
928 | 321 | sp->type |= pxd_on_heap; |
929 | 321 | } |
930 | 5.09k | if (code < 0 && syntax != 0) { /* Undo the state transition. */ |
931 | 4.33k | st->macro_state ^= syntax->state_transition; |
932 | 4.33k | } |
933 | 5.09k | return code; |
934 | 5.25k | } |
935 | | |
936 | | uint |
937 | | px_parser_data_left(px_parser_state_t * pxp) |
938 | 0 | { |
939 | 0 | return pxp->data_left; |
940 | 0 | } |