/src/ghostpdl/pcl/pcl/pcparse.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 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 | | /* pcparse.c */ |
18 | | /* PCL5 parser */ |
19 | | #include "stdio_.h" |
20 | | #include "gdebug.h" |
21 | | #include "gstypes.h" |
22 | | #include "scommon.h" |
23 | | #include "pcparse.h" |
24 | | #include "pcstate.h" /* for display_functions */ |
25 | | #include "pcursor.h" |
26 | | #include "rtmisc.h" |
27 | | #include "rtgmode.h" |
28 | | #include "rtraster.h" |
29 | | |
30 | | /* We don't know whether an Enable Display Functions takes effect while */ |
31 | | /* defining a macro. To play it safe, we're providing both options. */ |
32 | | /* If the following #define is uncommented, E.D.F. *does* take effect */ |
33 | | /* while scanning a macro definition. */ |
34 | | /*#define DISPLAY_FUNCTIONS_IN_MACRO*/ |
35 | | |
36 | | /* ---------------- Command definition ---------------- */ |
37 | | |
38 | | /* Register a command. Return true if this is a redefinition. */ |
39 | | static bool |
40 | | pcl_register_command(byte * pindex, const pcl_command_definition_t * pcmd, |
41 | | pcl_parser_state_t * pcl_parser_state) |
42 | 3.28M | { |
43 | 3.28M | int index = pcl_parser_state->definitions->pcl_command_next_index; |
44 | | |
45 | 3.28M | byte prev = *pindex; |
46 | | |
47 | 3.28M | if (prev != 0 && prev <= index |
48 | 16.1k | && pcl_parser_state->definitions->pcl_command_list[prev] == pcmd) |
49 | 0 | index = prev; |
50 | 3.28M | else if (index != 0 |
51 | 3.26M | && pcl_parser_state->definitions->pcl_command_list[index] == |
52 | 3.26M | pcmd); |
53 | 3.28M | else |
54 | 3.28M | pcl_parser_state->definitions-> |
55 | 3.28M | pcl_command_list |
56 | 3.28M | [pcl_parser_state->definitions->pcl_command_next_index = |
57 | 3.28M | ++index] = (pcl_command_definition_t *) pcmd; |
58 | 3.28M | *pindex = index; |
59 | 3.28M | return (prev != 0 && prev != index); |
60 | 3.28M | } |
61 | | |
62 | | /* Define a command or list of commands. */ |
63 | | void |
64 | | pcl_define_control_command(int /*char */ chr, |
65 | | const pcl_command_definition_t * pcmd, |
66 | | pcl_parser_state_t * pcl_parser_state) |
67 | 144k | { |
68 | | #ifdef DEBUG |
69 | | if (chr < 0 |
70 | | || chr >= |
71 | | countof(pcl_parser_state->definitions->pcl_control_command_indices)) |
72 | | if_debug1('I', "Invalid control character %d\n", chr); |
73 | | else if ( |
74 | | #endif |
75 | 144k | pcl_register_command(&pcl_parser_state-> |
76 | 144k | definitions->pcl_control_command_indices |
77 | 144k | [chr], pcmd, pcl_parser_state) |
78 | | #ifdef DEBUG |
79 | | ) |
80 | | if_debug1('I', "Redefining control character %d\n", chr); |
81 | | #endif |
82 | 144k | ; |
83 | 144k | } |
84 | | void |
85 | | pcl_define_escape_command(int /*char */ chr, |
86 | | const pcl_command_definition_t * pcmd, |
87 | | pcl_parser_state_t * pcl_parser_state) |
88 | 96.6k | { |
89 | | #ifdef DEBUG |
90 | | if (chr < min_escape_2char || chr > max_escape_2char) |
91 | | if_debug1('I', "Invalid escape character %c\n", chr); |
92 | | else if ( |
93 | | #endif |
94 | 96.6k | pcl_register_command(&pcl_parser_state-> |
95 | 96.6k | definitions->pcl_escape_command_indices |
96 | 96.6k | [chr - min_escape_2char], pcmd, |
97 | 96.6k | pcl_parser_state) |
98 | | #ifdef DEBUG |
99 | | ) |
100 | | if_debug1('I', "Redefining ESC %c\n", chr) |
101 | | #endif |
102 | 96.6k | ; |
103 | 96.6k | } |
104 | | |
105 | | /* |
106 | | * Convert escape classes to second level dispatch indices. |
107 | | */ |
108 | | static const byte pcl_escape_class_indices[max_escape_class - |
109 | | min_escape_class + 1] = { |
110 | | 0, 0, 0, 0, 1 /*% */ , 2 /*& */ , 0, 3 /*( */ , 4 /*) */ , 5 /***/ , 0, 0, |
111 | | 0, 0, 0 |
112 | | }; |
113 | | |
114 | | void |
115 | | pcl_define_class_command(int /*char */ class, int /*char */ group, |
116 | | int /*char */ command, |
117 | | const pcl_command_definition_t * pcmd, |
118 | | pcl_parser_state_t * pcl_parser_state) |
119 | 3.04M | { |
120 | | #ifdef DEBUG |
121 | | if (class < min_escape_class || class > max_escape_class || |
122 | | pcl_escape_class_indices[class - min_escape_class] == 0 || |
123 | | (group != 0 && (group < min_escape_group || group > max_escape_group)) |
124 | | || command < min_escape_command || command > max_escape_command) |
125 | | if_debug3('I', "Invalid command %c %c %c\n", class, group, command); |
126 | | else if ( |
127 | | #endif |
128 | 3.04M | pcl_register_command(&pcl_parser_state-> |
129 | 3.04M | definitions->pcl_grouped_command_indices |
130 | 3.04M | [pcl_escape_class_indices |
131 | 3.04M | [class - min_escape_class] - 1] |
132 | 3.04M | [group == |
133 | 3.04M | 0 ? 0 : group - min_escape_group + 1] |
134 | 3.04M | [command - min_escape_command], pcmd, |
135 | 3.04M | pcl_parser_state) |
136 | | #ifdef DEBUG |
137 | | ) |
138 | | if_debug3('I', "Redefining ESC %c %c %c\n", class, |
139 | | (group == 0 ? ' ' : group), command) |
140 | | #endif |
141 | 3.04M | ; |
142 | 3.04M | } |
143 | | void |
144 | | pcl_define_class_commands(int /*char */ class, |
145 | | const pcl_grouped_command_definition_t * pgroup, |
146 | | pcl_parser_state_t * pcl_parser_state) |
147 | 515k | { |
148 | 515k | const pcl_grouped_command_definition_t *pgc = pgroup; |
149 | | |
150 | 2.44M | for (; pgc->command != 0; ++pgc) |
151 | 1.93M | pcl_define_class_command(class, pgc->group, pgc->command, |
152 | 1.93M | &pgc->defn, pcl_parser_state); |
153 | 515k | } |
154 | | |
155 | | /* |
156 | | * Look up an escape command. The arguments are as follows: |
157 | | * ESC x 0, 0, 'x' |
158 | | * ESC ? <arg> c '?', 0, 'c' |
159 | | * ESC ? b <arg> c '?', 'b', 'c' |
160 | | * The caller is responsible for providing valid arguments. |
161 | | */ |
162 | | static const pcl_command_definition_t * |
163 | | pcl_get_command_definition(pcl_parser_state_t * pcl_parser_state, |
164 | | int /*char */ class, |
165 | | int /*char */ group, |
166 | | int /*char */ command) |
167 | 461k | { |
168 | 461k | const pcl_command_definition_t *cdefn = 0; |
169 | | |
170 | 461k | if (class == 0) { |
171 | 202k | if (command >= min_escape_2char && command <= max_escape_2char) |
172 | 26.6k | cdefn = pcl_parser_state->definitions->pcl_command_list |
173 | 26.6k | [pcl_parser_state-> |
174 | 26.6k | definitions->pcl_escape_command_indices[command - |
175 | 26.6k | min_escape_2char]]; |
176 | 259k | } else { |
177 | 259k | int class_index = pcl_escape_class_indices[class - min_escape_class]; |
178 | | |
179 | 259k | if (class_index) |
180 | 257k | cdefn = pcl_parser_state->definitions->pcl_command_list |
181 | 257k | [pcl_parser_state-> |
182 | 257k | definitions->pcl_grouped_command_indices[class_index - 1] |
183 | 257k | [group ? group - min_escape_group + 1 : 0] |
184 | 257k | [command - min_escape_command] |
185 | 257k | ]; |
186 | 259k | } |
187 | | #ifdef DEBUG |
188 | | if (cdefn == 0) { |
189 | | if (class == 0) |
190 | | if_debug1('I', "ESC %c undefined\n", command); |
191 | | else if (group == 0) |
192 | | if_debug2('I', "ESC %c %c undefined\n", class, command); |
193 | | else |
194 | | if_debug3('I', "ESC %c %c %c undefined\n", class, group, command); |
195 | | } |
196 | | #endif |
197 | 461k | return cdefn; |
198 | 461k | } |
199 | | |
200 | | /* ---------------- Parsing ---------------- */ |
201 | | |
202 | | /* Initialize the parser state. */ |
203 | | int |
204 | | pcl_process_init(pcl_parser_state_t * pst, pcl_state_t * pcs) |
205 | 19.5k | { |
206 | 19.5k | pcl_args_t args; |
207 | 19.5k | int code = 0; |
208 | 19.5k | pst->scan_type = scanning_none; |
209 | 19.5k | pst->args.data = 0; |
210 | 19.5k | pst->args.data_on_heap = false; |
211 | 19.5k | pst->short_hand = false; |
212 | 19.5k | pst->min_bytes_needed = 0; |
213 | | |
214 | | /* |
215 | | * RTL Files should start with a PCL escape sequence to enter the |
216 | | * GL/2 parser but many do not, so we start in HPGL. If an escape |
217 | | * sequence is detected the parse mode returns to PCL. |
218 | | */ |
219 | | |
220 | 19.5k | if (pcs->personality == rtl) { |
221 | 0 | arg_set_uint(&args, 0); |
222 | 0 | code = rtl_enter_hpgl_mode(&args, pcs); |
223 | 0 | } |
224 | 19.5k | return code; |
225 | 19.5k | } |
226 | | |
227 | | /* Adjust the argument value according to the command's argument type. */ |
228 | | /* Return 1 if the command should be ignored. */ |
229 | | static int |
230 | | pcl_adjust_arg(pcl_args_t * pargs, const pcl_command_definition_t * pdefn) |
231 | 241k | { |
232 | 241k | uint acts = pdefn->actions; |
233 | | |
234 | 241k | if (value_is_neg(&pargs->value)) { |
235 | 8.32k | switch (acts & pca_neg_action) { |
236 | 0 | case pca_neg_clamp: |
237 | 0 | arg_set_uint(pargs, 0); |
238 | 0 | break; |
239 | 191 | case pca_neg_error: |
240 | 191 | return e_Range; |
241 | 0 | case pca_neg_ignore: |
242 | 0 | return 1; |
243 | 8.13k | default: /* case pca_neg_ok */ |
244 | 8.13k | ; |
245 | 8.32k | } |
246 | 233k | } else if (pargs->value.i > 32767) /* overflowed int range */ |
247 | 272 | switch (acts & pca_big_action) { |
248 | 8 | case pca_big_clamp: |
249 | 8 | arg_set_uint(pargs, 32767); |
250 | 8 | break; |
251 | 149 | case pca_big_error: |
252 | 149 | return e_Range; |
253 | 14 | case pca_big_ignore: |
254 | 14 | return 1; |
255 | 101 | default: /* case pca_big_ok */ |
256 | 101 | ; |
257 | 272 | } |
258 | 241k | return 0; |
259 | 241k | } |
260 | | |
261 | | /* Append some just-scanned input data to the macro being defined. */ |
262 | | static int |
263 | | append_macro(const byte * from, const byte * to, pcl_state_t * pcs) |
264 | 84 | { |
265 | 84 | if (pcs->macro_definition != NULL) { |
266 | 84 | uint count = to - from; |
267 | 84 | uint size = gs_object_size(pcs->memory, pcs->macro_definition); |
268 | 84 | byte *new_defn = |
269 | 84 | gs_resize_object(pcs->memory, pcs->macro_definition, size + count, |
270 | 84 | "append_macro"); |
271 | | |
272 | 84 | if (new_defn == 0) |
273 | 0 | return_error(e_Memory); |
274 | 84 | memcpy(new_defn + size, from + 1, count); |
275 | 84 | pcs->macro_definition = new_defn; |
276 | 84 | } |
277 | 84 | return 0; |
278 | 84 | } |
279 | | |
280 | | #ifdef DEBUG |
281 | | static void |
282 | | debug_dump_char(gs_memory_t *mem, char chr) |
283 | | { |
284 | | dmprintf1(mem, (chr >= 33 && chr <= 126 ? |
285 | | "%c" : "\\%03o"), (unsigned char)chr); |
286 | | if (chr == '\\') |
287 | | dmprintf1(mem, "%c", '\\'); |
288 | | return; |
289 | | } |
290 | | #endif |
291 | | |
292 | | /* Process a buffer of PCL commands. */ |
293 | | int |
294 | | pcl_process(pcl_parser_state_t * pst, pcl_state_t * pcs, |
295 | | stream_cursor_read * pr) |
296 | 2.33M | { |
297 | 2.33M | const byte *p = pr->ptr; |
298 | 2.33M | const byte *rlimit = pr->limit; |
299 | 2.33M | int code = 0; |
300 | 2.33M | int bytelen = 0; |
301 | 2.33M | bool in_macro = pcs->defining_macro; |
302 | | /* Record how much of the input we've copied into a macro */ |
303 | | /* in the process of being defined. */ |
304 | 2.33M | const byte *macro_p = p; |
305 | | |
306 | 2.46M | top: |
307 | | /* Reset the parameter scanner */ |
308 | 25.3M | #define avalue pst->args.value |
309 | 2.46M | #define param_init()\ |
310 | 12.0M | (avalue.type = pcv_none, avalue.i = 0) |
311 | | |
312 | | #ifdef DISPLAY_FUNCTIONS_IN_MACRO |
313 | | # define do_display_functions() 1 |
314 | | #else |
315 | 2.46M | # define do_display_functions() (!in_macro) |
316 | 2.46M | #endif |
317 | | |
318 | 2.46M | if (rlimit - p < pst->min_bytes_needed) { |
319 | 621 | pst->min_bytes_needed = 0; |
320 | 621 | p = rlimit; |
321 | 621 | goto x; |
322 | 2.46M | } else { |
323 | 2.46M | pst->min_bytes_needed = 0; |
324 | 2.46M | } |
325 | | |
326 | 15.7M | while (p < rlimit) { |
327 | 13.4M | byte chr = 0x00; /* silence a compiler warning */ |
328 | 13.4M | const pcl_command_definition_t *cdefn = NULL; |
329 | 13.4M | switch (pst->scan_type) { |
330 | 2.85k | case scanning_data: |
331 | 2.85k | { /* Accumulate command data in a buffer. */ |
332 | 2.85k | uint count = uint_arg(&pst->args); |
333 | 2.85k | uint pos = pst->data_pos; |
334 | | |
335 | 2.85k | if (pos < count) { |
336 | 2.09k | uint avail = rlimit - p; |
337 | 2.09k | uint copy = min(count - pos, avail); |
338 | | |
339 | 2.09k | memcpy(pst->args.data + pos, p + 1, copy); |
340 | 2.09k | pst->data_pos += copy; |
341 | 2.09k | p += copy; |
342 | 2.09k | continue; |
343 | 2.09k | } |
344 | | /* Invoke the command. */ |
345 | 761 | cdefn = pcl_get_command_definition(pst, |
346 | 761 | pst->param_class, |
347 | 761 | pst->param_group, |
348 | 761 | pst->args.command); |
349 | 761 | if (pst->short_hand) { |
350 | 1 | pst->scan_type = scanning_parameter; |
351 | 1 | } else |
352 | 760 | pst->scan_type = scanning_none; |
353 | 761 | break; |
354 | 2.85k | } |
355 | 1.06M | case scanning_display: |
356 | 1.06M | { |
357 | | /* Display, don't execute, all characters. */ |
358 | 1.06M | chr = *++p; |
359 | 1.06M | if (chr == ESC) { |
360 | 59.5k | int index; |
361 | | |
362 | 59.5k | if (p >= rlimit) |
363 | 35 | goto x; |
364 | 59.5k | if (p[1] >= min_escape_2char |
365 | 4.25k | && p[1] <= max_escape_2char |
366 | 2.13k | && (index = |
367 | 2.13k | pst-> |
368 | 2.13k | definitions->pcl_escape_command_indices[p[1] - |
369 | 2.13k | min_escape_2char]) |
370 | 2.13k | != 0 |
371 | 216 | && pst->definitions-> |
372 | 216 | pcl_command_list[index]->proc == |
373 | 216 | pcl_disable_display_functions) { |
374 | 38 | if (do_display_functions()) { |
375 | 38 | pst->args.command = chr; |
376 | 38 | code = pcl_plain_char(&pst->args, pcs); |
377 | 38 | if (code < 0) |
378 | 0 | goto x; |
379 | 38 | } |
380 | 38 | pst->args.command = chr = *++p; |
381 | 38 | pcl_disable_display_functions(&pst->args, pcs); |
382 | 38 | pst->scan_type = scanning_none; |
383 | 38 | } |
384 | 59.5k | } |
385 | 1.06M | if (do_display_functions()) { |
386 | 1.06M | if (chr == CR) { |
387 | 4.36k | code = pcl_do_CR(pcs); |
388 | 4.36k | if (code >= 0) |
389 | 4.36k | code = pcl_do_LF(pcs); |
390 | 1.06M | } else { |
391 | 1.06M | pst->args.command = chr; |
392 | 1.06M | code = pcl_plain_char(&pst->args, pcs); |
393 | 1.06M | } |
394 | 1.06M | if (code < 0) |
395 | 0 | goto x; |
396 | 1.06M | } |
397 | 1.06M | continue; |
398 | 1.06M | } |
399 | 1.06M | case scanning_parameter: |
400 | 760k | for (;;) { |
401 | 760k | if (p >= rlimit) |
402 | 340 | goto x; |
403 | 760k | chr = *++p; |
404 | | /* |
405 | | * The parser for numbers is very lenient, and accepts |
406 | | * many strings that aren't valid numbers. If this |
407 | | * ever becomes a problem, we can tighten it up.... |
408 | | */ |
409 | 760k | if (pst->garbage_in_parameter) { |
410 | 35.8k | if (chr < ' ' || chr > '?') { |
411 | 2.64k | pst->garbage_in_parameter = false; /* no garbage anymore */ |
412 | 2.64k | break; |
413 | 2.64k | } |
414 | 724k | } else { |
415 | 724k | if (chr >= '0' && chr <= '9') { |
416 | 428k | chr -= '0'; |
417 | 428k | if (value_is_float(&avalue)) |
418 | 8.69k | avalue.fraction += (chr / (pst->scale *= 10)); |
419 | 420k | else |
420 | 420k | avalue.type |= pcv_int, |
421 | 420k | avalue.i = avalue.i * 10 + chr; |
422 | 428k | } else if (chr == '-') |
423 | 10.5k | avalue.type |= pcv_neg; |
424 | 284k | else if (chr == '+') |
425 | 1.00k | avalue.type |= pcv_pos; |
426 | 283k | else if (chr == '.') |
427 | 4.74k | avalue.type |= pcv_float, |
428 | 4.74k | avalue.fraction = 0, pst->scale = 1.0; |
429 | 279k | else if (chr == ' ') |
430 | 759 | continue; |
431 | 278k | else if (chr >= ' ' && chr <= '?') { /* Ignore garbage nearby in the code space. */ |
432 | | /* skip the remainder until a chr outside this range is found */ |
433 | 9.81k | if (avalue.type != pcv_none) |
434 | 2.65k | pst->garbage_in_parameter = true; |
435 | 9.81k | continue; |
436 | 9.81k | } else |
437 | 268k | break; |
438 | 724k | } |
439 | 760k | } |
440 | | #ifdef DEBUG |
441 | | if (gs_debug_c('i')) { |
442 | | dmprintf(pcs->memory, "ESC "); |
443 | | debug_dump_char(pcs->memory, pst->param_class); |
444 | | dmprintf(pcs->memory, " "); |
445 | | debug_dump_char(pcs->memory, pst->param_group); |
446 | | if (value_is_present(&avalue)) { |
447 | | dmputc(pcs->memory, ' '); |
448 | | if (value_is_signed(&avalue)) |
449 | | dmputc(pcs->memory, |
450 | | (value_is_neg(&avalue) ? '-' : '+')); |
451 | | if (value_is_float(&avalue)) |
452 | | dmprintf1(pcs->memory, "%g", |
453 | | avalue.i + avalue.fraction); |
454 | | else |
455 | | dmprintf1(pcs->memory, "%u", avalue.i); |
456 | | } |
457 | | dmprintf1(pcs->memory, " %c\n", chr); |
458 | | } |
459 | | #endif |
460 | 271k | pst->short_hand = false; |
461 | 271k | if (chr >= min_escape_command + 32 && |
462 | 102k | chr <= max_escape_command + 32) { |
463 | 98.5k | pst->short_hand = true; |
464 | 98.5k | chr -= 32; |
465 | 172k | } else if (chr >= min_escape_command && |
466 | 164k | chr <= max_escape_command) |
467 | 160k | pst->scan_type = scanning_none; |
468 | 12.3k | else { |
469 | 12.3k | pst->scan_type = scanning_none; |
470 | | /* Rescan the out-of-place character. */ |
471 | 12.3k | --p; |
472 | 12.3k | continue; |
473 | 12.3k | } |
474 | | /* Dispatch on param_class, param_group, and chr. */ |
475 | 258k | cdefn = pcl_get_command_definition(pst, |
476 | 258k | pst->param_class, |
477 | 258k | pst->param_group, chr); |
478 | 258k | if (cdefn) { |
479 | 241k | if_debug1m('i', pcs->memory, " [%s]\n", cdefn->cname); |
480 | 241k | code = pcl_adjust_arg(&pst->args, cdefn); |
481 | 241k | if (code < 0) |
482 | 0 | goto x; |
483 | 241k | if (cdefn->actions & pca_byte_data) { |
484 | 71.0k | uint count = uint_arg(&pst->args); |
485 | | |
486 | 71.0k | if ((count > 0) && (rlimit - p < count)) { |
487 | 1.26k | pst->args.data = |
488 | 1.26k | gs_alloc_bytes(pcs->memory, count, |
489 | 1.26k | "command data"); |
490 | 1.26k | if (pst->args.data == 0) { |
491 | 0 | --p; |
492 | 0 | code = gs_note_error(e_Memory); |
493 | 0 | (void)pcl_grestore(pcs); |
494 | 0 | goto x; |
495 | 0 | } |
496 | 1.26k | pst->args.data_on_heap = true; |
497 | 1.26k | pst->args.command = chr; |
498 | 1.26k | pst->data_pos = 0; |
499 | 1.26k | pst->scan_type = scanning_data; |
500 | 1.26k | continue; |
501 | 1.26k | } |
502 | 69.8k | pst->args.data = (byte *) (p + 1); |
503 | 69.8k | pst->args.data_on_heap = false; |
504 | 69.8k | p += count; |
505 | 69.8k | } |
506 | 240k | break; |
507 | 241k | } |
508 | 17.0k | param_init(); |
509 | 17.0k | continue; |
510 | 12.0M | case scanning_none: |
511 | 12.0M | if (pcs->parse_other) { /* HPGL/2 mode */ |
512 | 172k | pr->ptr = p; |
513 | 172k | code = (*pcs->parse_other) |
514 | 172k | (pcs->parse_data, pcs, pr); |
515 | 172k | p = pr->ptr; |
516 | 172k | if (code < 0 || (code == 0 && pcs->parse_other)) |
517 | | // goto x; |
518 | 125k | goto top; |
519 | 172k | } |
520 | | |
521 | 11.9M | chr = *++p; |
522 | | /* check for multi-byte scanning */ |
523 | 11.9M | bytelen = pcl_char_bytelen(chr, pcs->text_parsing_method); |
524 | 11.9M | if (bytelen == 0) { |
525 | 12 | bytelen = 1; /* invalid utf-8 leading char */ |
526 | 12 | } |
527 | 11.9M | if (bytelen > 1) { |
528 | | /* check if we need more data */ |
529 | 410k | if ((p + bytelen - 1) > rlimit) { |
530 | 41 | pst->min_bytes_needed = 2; |
531 | 41 | --p; |
532 | 41 | goto x; |
533 | 41 | } |
534 | 410k | if_debug2m('i', pcs->memory, "%x%x\n", p[0], p[1]); |
535 | 410k | code = pcl_text(p, bytelen, pcs, false); |
536 | 410k | if (code < 0) |
537 | 0 | goto x; |
538 | | /* now pass over the remaining bytes */ |
539 | 410k | p += (bytelen - 1); |
540 | 410k | cdefn = NULL; |
541 | 11.5M | } else if (chr != ESC) { |
542 | | #ifdef DEBUG |
543 | | if (gs_debug_c('i')) { |
544 | | if_debug1m('i', pcs->memory, "[i%d] ", bytelen); |
545 | | debug_dump_char(pcs->memory, chr); |
546 | | if_debug0m('i', pcs->memory, "\n"); |
547 | | } |
548 | | #endif |
549 | 11.1M | cdefn = pst->definitions->pcl_command_list |
550 | 11.1M | [chr < 33 ? |
551 | 5.40M | pst->definitions->pcl_control_command_indices[chr] : |
552 | 11.1M | pst->definitions->pcl_control_command_indices[1]]; |
553 | 11.1M | if ((cdefn == 0 || cdefn->proc == pcl_plain_char) && |
554 | 10.3M | !in_macro && !pcs->parse_other |
555 | 10.3M | && !pcs->raster_state.graphics_mode) { |
556 | | /* Look ahead for a run of plain text. We can |
557 | | be very conservative about this, because |
558 | | this is only a performance enhancement. */ |
559 | 10.3M | const byte *str = p; |
560 | | |
561 | 15.8M | while (p < rlimit && p[1] >= 32 && p[1] <= 127) { |
562 | | #ifdef DEBUG |
563 | | if (gs_debug_c('i')) { |
564 | | if (p == str) |
565 | | if_debug1m('i', pcs->memory, "[i%d] ", bytelen); |
566 | | debug_dump_char(pcs->memory, p[1]); |
567 | | } |
568 | | #endif |
569 | 5.50M | ++p; |
570 | 5.50M | } |
571 | | |
572 | 10.3M | if_debug0m('i', pcs->memory, "\n"); |
573 | 10.3M | code = pcl_text(str, (uint) (p + 1 - str), |
574 | 10.3M | pcs, false); |
575 | 10.3M | if (code < 0) |
576 | 0 | goto x; |
577 | 10.3M | cdefn = NULL; |
578 | 10.3M | } |
579 | 11.1M | } else { |
580 | 376k | if (p >= rlimit) { |
581 | 1.20k | pst->min_bytes_needed = 2; |
582 | 1.20k | --p; |
583 | 1.20k | goto x; |
584 | 1.20k | } |
585 | 375k | chr = *++p; |
586 | 375k | if (chr < min_escape_class || chr > max_escape_class) { |
587 | 202k | cdefn = pcl_get_command_definition(pst, 0, 0, chr); |
588 | 202k | if (!cdefn) { |
589 | | /* Skip the ESC, back up |
590 | | to the char following the |
591 | | ESC. */ |
592 | 188k | --p; |
593 | | #ifdef DEBUG |
594 | | if (gs_debug_c('i')) { |
595 | | debug_dump_char(pcs->memory, '\033'); |
596 | | } |
597 | | #endif |
598 | 188k | continue; |
599 | 188k | } |
600 | | #ifdef DEBUG |
601 | | if (gs_debug_c('i')) { |
602 | | dmprintf(pcs->memory, "ESC "); |
603 | | debug_dump_char(pcs->memory, chr); |
604 | | dmprintf(pcs->memory, "\n"); |
605 | | dmprintf1(pcs->memory, " [%s]\n", cdefn->cname); |
606 | | } |
607 | | #endif |
608 | 202k | } else { |
609 | 173k | if (p >= rlimit) { |
610 | 171 | p -= 2; |
611 | 171 | pst->min_bytes_needed = 3; |
612 | 171 | goto x; |
613 | 171 | } |
614 | 172k | pst->param_class = chr; |
615 | 172k | chr = *++p; |
616 | 172k | if (chr < min_escape_group || chr > max_escape_group) { /* Class but no group */ |
617 | 30.6k | --p; |
618 | 30.6k | chr = 0; |
619 | 30.6k | } |
620 | 172k | pst->param_group = chr; |
621 | 172k | pst->scan_type = scanning_parameter; |
622 | 172k | pst->garbage_in_parameter = false; |
623 | 172k | param_init(); |
624 | 172k | continue; |
625 | 173k | } |
626 | 375k | } |
627 | 11.6M | break; |
628 | 13.4M | } |
629 | 11.8M | if (cdefn == NULL) { |
630 | 10.7M | param_init(); |
631 | 10.7M | continue; |
632 | 10.7M | } |
633 | 1.05M | if (!in_macro || (cdefn->actions & pca_in_macro)) { |
634 | | /* This might be the end-of-macro command. */ |
635 | | /* Make sure all the data through this point */ |
636 | | /* has been captured in the macro definition. */ |
637 | 1.04M | if (in_macro) { |
638 | 11 | code = append_macro(macro_p, p, pcs); |
639 | 11 | macro_p = p; |
640 | 11 | if (code < 0) |
641 | 0 | goto x; |
642 | 11 | } |
643 | 1.04M | pst->args.command = chr; |
644 | 1.04M | if (!pcs->raster_state.graphics_mode || |
645 | 109k | (cdefn->actions & pca_raster_graphics) || |
646 | 5.20k | (code = pcl_end_graphics_mode_implicit(pcs, |
647 | 5.20k | cdefn-> |
648 | 5.20k | actions & |
649 | 5.20k | pca_dont_lockout_in_rtl)) |
650 | 1.04M | >= 0) { |
651 | 1.04M | if ((pcs->personality != rtl) || ((pcs->personality == rtl) |
652 | 0 | && (cdefn-> |
653 | 0 | actions & pca_in_rtl))) |
654 | 1.04M | code = (*cdefn->proc) (&pst->args, pcs); |
655 | 1.04M | } |
656 | | /* |
657 | | * If we allocated a buffer for command data, |
658 | | * and the command didn't take possession of it, |
659 | | * free it now. |
660 | | */ |
661 | 1.04M | if (pst->args.data_on_heap && pst->args.data) { |
662 | 745 | gs_free_object(pcs->memory, pst->args.data, "command data"); |
663 | 745 | pst->args.data = 0; |
664 | 745 | } |
665 | 1.04M | if (code == e_Unimplemented) { |
666 | | #if e_Unimplemented != 0 |
667 | | if_debug0m('i', pcs->memory, "Unimplemented\n"); |
668 | | #endif |
669 | 1.04M | } else if (code < 0) |
670 | 5.56k | break; |
671 | 1.04M | if (pcs->display_functions) { |
672 | | /* This calls for a special parsing state. */ |
673 | 135 | pst->scan_type = scanning_display; |
674 | 135 | } |
675 | 1.04M | if (pcs->defining_macro && !in_macro) { |
676 | | /* We just started a macro definition. */ |
677 | 39 | if (pst->scan_type != scanning_none) { |
678 | | /* macro was defined with an incomple combined command */ |
679 | | /* start definition of macro with esc&f preloaded */ |
680 | 1 | static const byte macro_prefix[4] = " \033&f"; |
681 | | |
682 | 1 | code = append_macro(¯o_prefix[0], ¯o_prefix[3], pcs); |
683 | 1 | if (code < 0) |
684 | 0 | goto x; |
685 | 1 | } |
686 | 39 | macro_p = p; |
687 | 39 | } |
688 | 1.04M | in_macro = pcs->defining_macro; |
689 | 1.04M | } else { |
690 | | /* |
691 | | * If we allocated a buffer for command data, |
692 | | * free it now. |
693 | | */ |
694 | 6.34k | if (pst->args.data_on_heap && pst->args.data) { |
695 | 16 | gs_free_object(pcs->memory, pst->args.data, "command data"); |
696 | 16 | pst->args.data = 0; |
697 | 16 | } |
698 | 6.34k | } |
699 | 1.04M | param_init(); |
700 | 1.04M | } |
701 | 2.33M | x:pr->ptr = p; |
702 | | /* Append the last bit of data to the macro, if defining. */ |
703 | 2.33M | if (in_macro) { |
704 | 72 | int mcode = append_macro(macro_p, p, pcs); |
705 | | |
706 | 72 | if (mcode < 0 && code >= 0) |
707 | 0 | code = mcode; |
708 | 72 | } |
709 | 2.33M | if (code < 0) { |
710 | | /* This avoids memento squeeze leaks. */ |
711 | 5.56k | (void) pcl_complete_raster(pcs); |
712 | 5.56k | } |
713 | 2.33M | return code; |
714 | 2.46M | } |
715 | | |
716 | | /* inialize the pcl command counter */ |
717 | | int |
718 | | pcl_init_command_index(pcl_parser_state_t * pcl_parser_state, |
719 | | pcl_state_t * pcs) |
720 | 16.1k | { |
721 | 16.1k | pcl_command_definitions_t *definitions = |
722 | 16.1k | (pcl_command_definitions_t *) gs_alloc_bytes(pcs->memory, |
723 | 16.1k | sizeof |
724 | 16.1k | (pcl_command_definitions_t), |
725 | 16.1k | "pcl_init_command_index"); |
726 | | |
727 | | /* fatal */ |
728 | 16.1k | if (definitions == 0) |
729 | 0 | return -1; |
730 | | /* we should set these individually but each field is properly |
731 | | initialized to zero */ |
732 | 16.1k | memset(definitions, 0, sizeof(pcl_command_definitions_t)); |
733 | | /* plug command definitions into the parser state and a pointer |
734 | | for the command definitions into pcl's state for use by macros, |
735 | | I don't like this but the alternative is getting the parser |
736 | | state to the code that executer macros which is inconvenient at |
737 | | this time */ |
738 | 16.1k | pcs->pcl_commands = pcl_parser_state->definitions = definitions; |
739 | 16.1k | return 0; |
740 | 16.1k | } |
741 | | |
742 | | /* for now deallocates the memory associated with the command definitions */ |
743 | | int |
744 | | pcl_parser_shutdown(pcl_parser_state_t * pcl_parser_state, gs_memory_t * mem) |
745 | 16.1k | { |
746 | 16.1k | gs_free_object(mem, pcl_parser_state->definitions, "pcl_parser_shutdown"); |
747 | 16.1k | return 0; |
748 | 16.1k | } |
749 | | /* ---------------- Initialization ---------------- */ |
750 | | |
751 | | int |
752 | | pcparse_do_reset(pcl_state_t * pcs, pcl_reset_type_t type) |
753 | 49.4k | { |
754 | 49.4k | if (type & (pcl_reset_initial | pcl_reset_printer)) |
755 | 49.4k | pcs->parse_other = 0; |
756 | | |
757 | 49.4k | return 0; |
758 | 49.4k | } |
759 | | |
760 | | const pcl_init_t pcparse_init = { |
761 | | 0, pcparse_do_reset |
762 | | }; |