/src/ghostpdl/pcl/pxl/pxstream.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 | | /* pxstream.c */ |
18 | | /* PCL XL user-defined stream operators */ |
19 | | |
20 | | #include "memory_.h" |
21 | | #include "gsmemory.h" |
22 | | #include "scommon.h" |
23 | | #include "pxoper.h" |
24 | | #include "pxstate.h" |
25 | | #include "pxparse.h" |
26 | | #include "pxptable.h" |
27 | | |
28 | | /* ---------------- Internal procedures ---------------- */ |
29 | | |
30 | | /* Tag a stream name with its character width. */ |
31 | | static int |
32 | | tag_stream_name(const px_value_t * psnv, gs_string * pstr, |
33 | | gs_memory_t * mem, client_name_t cname) |
34 | 0 | { |
35 | 0 | uint size = array_value_size(psnv); |
36 | 0 | byte *str = gs_alloc_string(mem, size + 1, cname); |
37 | |
|
38 | 0 | if (str == 0) |
39 | 0 | return_error(errorInsufficientMemory); |
40 | 0 | str[0] = value_size(psnv); |
41 | 0 | memcpy(str + 1, psnv->value.array.data, size); |
42 | 0 | pstr->data = str; |
43 | 0 | pstr->size = size + 1; |
44 | 0 | return 0; |
45 | 0 | } |
46 | | |
47 | | /* ---------------- Operators ---------------- */ |
48 | | |
49 | | const byte apxBeginStream[] = { |
50 | | pxaStreamName, 0, 0 |
51 | | }; |
52 | | int |
53 | | pxBeginStream(px_args_t * par, px_state_t * pxs) |
54 | 0 | { |
55 | 0 | int code = tag_stream_name(par->pv[0], &pxs->stream_name, pxs->memory, |
56 | 0 | "pxBeginStream(name)"); |
57 | |
|
58 | 0 | if (code < 0) |
59 | 0 | return code; |
60 | 0 | pxs->stream_def.size = 0; |
61 | 0 | pl_dict_undef(&pxs->stream_dict, pxs->stream_name.data, |
62 | 0 | pxs->stream_name.size); |
63 | 0 | return 0; |
64 | 0 | } |
65 | | |
66 | | const byte apxReadStream[] = { |
67 | | pxaStreamDataLength, 0, 0 |
68 | | }; |
69 | | int |
70 | | pxReadStream(px_args_t * par, px_state_t * pxs) |
71 | 0 | { |
72 | 0 | ulong len = par->pv[0]->value.i; |
73 | 0 | ulong copy = min(len - par->source.position, par->source.available); |
74 | 0 | uint old_size = pxs->stream_def.size; |
75 | 0 | byte *str; |
76 | |
|
77 | 0 | if (copy == 0) |
78 | 0 | return pxNeedData; |
79 | 0 | if (old_size == 0) |
80 | 0 | str = gs_alloc_bytes(pxs->memory, copy, "pxReadStream"); |
81 | 0 | else |
82 | 0 | str = gs_resize_object(pxs->memory, pxs->stream_def.data, |
83 | 0 | old_size + copy, "pxReadStream"); |
84 | 0 | if (str == 0) |
85 | 0 | return_error(errorInsufficientMemory); |
86 | 0 | memcpy(str + old_size, par->source.data, copy); |
87 | 0 | pxs->stream_def.data = str; |
88 | 0 | pxs->stream_def.size = old_size + copy; |
89 | 0 | par->source.data += copy; |
90 | 0 | par->source.available -= copy; |
91 | 0 | return ((par->source.position += copy) == len ? 0 : pxNeedData); |
92 | 0 | } |
93 | | |
94 | | const byte apxEndStream[] = { 0, 0 }; |
95 | | int |
96 | | pxEndStream(px_args_t * par, px_state_t * pxs) |
97 | 0 | { |
98 | 0 | int code = pl_dict_put(&pxs->stream_dict, pxs->stream_name.data, |
99 | 0 | pxs->stream_name.size, pxs->stream_def.data); |
100 | |
|
101 | 0 | gs_free_string(pxs->memory, pxs->stream_name.data, |
102 | 0 | pxs->stream_name.size, "pxEndStream(name)"); |
103 | 0 | return (code < 0 ? gs_note_error(errorInsufficientMemory) : 0); |
104 | 0 | } |
105 | | |
106 | | const byte apxRemoveStream[] = { |
107 | | pxaStreamName, 0, 0 |
108 | | }; |
109 | | |
110 | | int |
111 | | pxRemoveStream(px_args_t * par, px_state_t * pxs) |
112 | 0 | { |
113 | 0 | gs_string str; |
114 | 0 | void *def; |
115 | |
|
116 | 0 | int code = tag_stream_name(par->pv[0], &str, pxs->memory, |
117 | 0 | "pxExecStream(name)"); |
118 | |
|
119 | 0 | if (code < 0) |
120 | 0 | return code; |
121 | 0 | { |
122 | 0 | bool found = pl_dict_find(&pxs->stream_dict, str.data, str.size, |
123 | 0 | &def); |
124 | |
|
125 | 0 | if (!found) |
126 | 0 | return_error(errorStreamUndefined); |
127 | 0 | pl_dict_undef(&pxs->stream_dict, str.data, str.size); |
128 | 0 | gs_free_string(pxs->memory, str.data, str.size, |
129 | 0 | "pxRemoveStream(name)"); |
130 | 0 | } |
131 | 0 | return 0; |
132 | 0 | } |
133 | | |
134 | | const byte apxExecStream[] = { |
135 | | pxaStreamName, 0, 0 |
136 | | }; |
137 | | int |
138 | | pxExecStream(px_args_t * par, px_state_t * pxs) |
139 | 0 | { |
140 | 0 | gs_string str; |
141 | 0 | void *def; |
142 | 0 | const byte *def_data; |
143 | 0 | uint def_size; |
144 | 0 | bool big_endian; |
145 | 0 | const byte *start; |
146 | 0 | px_parser_state_t *pst = par->parser; |
147 | 0 | px_parser_state_t st; |
148 | 0 | stream_cursor_read r; |
149 | |
|
150 | 0 | int code = tag_stream_name(par->pv[0], &str, pxs->memory, |
151 | 0 | "pxExecStream(name)"); |
152 | |
|
153 | 0 | if (code < 0) |
154 | 0 | return code; |
155 | | |
156 | 0 | if (pxs->stream_level > 32) |
157 | 0 | return_error(errorStreamNestingFull); |
158 | | |
159 | 0 | { |
160 | 0 | bool found = pl_dict_find(&pxs->stream_dict, str.data, str.size, |
161 | 0 | &def); |
162 | |
|
163 | 0 | gs_free_string(pxs->memory, str.data, str.size, "pxExecStream(name)"); |
164 | 0 | if (!found) |
165 | 0 | return_error(errorStreamUndefined); |
166 | 0 | } |
167 | 0 | def_data = def; |
168 | 0 | def_size = gs_object_size(pxs->memory, def); |
169 | | /* We do all the syntax checking for streams here, rather than */ |
170 | | /* in ReadStream or EndStream, for simplicity. */ |
171 | 0 | switch (def_data[0]) { |
172 | 0 | case '(': |
173 | 0 | big_endian = true; |
174 | 0 | break; |
175 | 0 | case ')': |
176 | 0 | big_endian = false; |
177 | 0 | break; |
178 | 0 | default: |
179 | 0 | return_error(errorUnsupportedBinding); |
180 | 0 | } |
181 | 0 | if (def_size < 16 || strncmp((const char *)def_data + 1, " HP-PCL XL", 10) |
182 | 0 | ) |
183 | 0 | return_error(errorUnsupportedClassName); |
184 | | /* support protocol level 1, 2 and 3 */ |
185 | 0 | if (strncmp((const char *)def_data + 11, ";1;", 3) && |
186 | 0 | strncmp((const char *)def_data + 11, ";2;", 3) && |
187 | 0 | strncmp((const char *)def_data + 11, ";3;", 3)) |
188 | 0 | return_error(errorUnsupportedProtocol); |
189 | 0 | start = memchr(def_data + 14, '\n', def_size - 14); |
190 | 0 | if (!start) |
191 | 0 | return_error(errorIllegalStreamHeader); |
192 | 0 | st.memory = pxs->memory; |
193 | 0 | px_process_init(&st, big_endian); |
194 | 0 | st.macro_state = pst->macro_state | ptsExecStream; |
195 | 0 | st.last_operator = pst->last_operator; |
196 | 0 | r.ptr = start; |
197 | 0 | r.limit = def_data + def_size - 1; |
198 | 0 | pxs->stream_level++; |
199 | 0 | code = px_process(&st, pxs, &r); |
200 | 0 | pxs->stream_level--; |
201 | 0 | pst->macro_state = st.macro_state & ~ptsExecStream; |
202 | 0 | if (code < 0) { /* Set the operator counts for error reporting. */ |
203 | 0 | pst->parent_operator_count = pst->operator_count; |
204 | 0 | pst->operator_count = st.operator_count; |
205 | 0 | pst->last_operator = st.last_operator; |
206 | 0 | } |
207 | 0 | return code; |
208 | 0 | } |