/src/ghostpdl/base/gsparams.c
Line | Count | Source (jump to first uncovered line) |
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 | | /* Generic parameter list serializer & expander */ |
18 | | |
19 | | /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */ |
20 | | /* 11/16/98 L. Peter Deutsch (ghost@aladdin.com) edited to remove names |
21 | | put_bytes, put_word which conflicted with other modules */ |
22 | | |
23 | | #include "gx.h" |
24 | | #include "memory_.h" |
25 | | #include "gserrors.h" |
26 | | #include "gsparams.h" |
27 | | |
28 | | /* ----------- Local Type Decl's ------------ */ |
29 | | typedef struct { |
30 | | byte *buf; /* current buffer ptr */ |
31 | | byte *buf_end; /* end of buffer */ |
32 | | unsigned total_sizeof; /* current # bytes in buf */ |
33 | | } WriteBuffer; |
34 | | |
35 | | /* ---------- Forward refs ----------- */ |
36 | | static void |
37 | | ptr_align_to( |
38 | | const byte ** src, /* pointer to align */ |
39 | | unsigned alignment /* alignment, must be power of 2 */ |
40 | | ); |
41 | | static void |
42 | | wb_put_word( |
43 | | unsigned source, /* number to put to buffer */ |
44 | | WriteBuffer * dest /* destination descriptor */ |
45 | | ); |
46 | | static void |
47 | | wb_put_bytes( |
48 | | const byte * source, /* bytes to put to buffer */ |
49 | | unsigned source_sizeof, /* # bytes to put */ |
50 | | WriteBuffer * dest /* destination descriptor */ |
51 | | ); |
52 | | static void |
53 | | wb_put_alignment( |
54 | | unsigned alignment, /* alignment to match, must be power 2 */ |
55 | | WriteBuffer * dest /* destination descriptor */ |
56 | | ); |
57 | | |
58 | | /* Get word compressed with wb_put_word */ |
59 | | static unsigned /* decompressed word */ |
60 | | buf_get_word( |
61 | | const byte ** src /* UPDATES: ptr to src buf ptr */ |
62 | | ); |
63 | | |
64 | | /* ------------ Serializer ------------ */ |
65 | | /* Serialize the contents of a gs_param_list (including sub-dicts) */ |
66 | | int /* ret -ve err, else # bytes needed to represent param list, whether */ |
67 | | |
68 | | /* or not it actually fit into buffer. List was successully */ |
69 | | |
70 | | /* serialized only if if this # is <= supplied buf size. */ |
71 | | gs_param_list_serialize( |
72 | | gs_param_list * list, /* root of list to serialize */ |
73 | | /* list MUST BE IN READ MODE */ |
74 | | byte * buf, /* destination buffer (can be 0) */ |
75 | | int buf_sizeof /* # bytes available in buf (can be 0) */ |
76 | | ) |
77 | 0 | { |
78 | 0 | int code = 0; |
79 | 0 | int temp_code; |
80 | 0 | gs_param_enumerator_t key_enum; |
81 | 0 | gs_param_key_t key; |
82 | 0 | WriteBuffer write_buf; |
83 | |
|
84 | 0 | write_buf.buf = buf; |
85 | 0 | write_buf.buf_end = buf + (buf ? buf_sizeof : 0); |
86 | 0 | write_buf.total_sizeof = 0; |
87 | 0 | param_init_enumerator(&key_enum); |
88 | | |
89 | | /* Each item is serialized as ("word" means compressed word): |
90 | | * word: key sizeof + 1, or 0 if end of list/dict |
91 | | * word: data type(gs_param_type_xxx) |
92 | | * byte[]: key, including trailing \0 |
93 | | * (if simple type) |
94 | | * byte[]: unpacked representation of data |
95 | | * (if simple array or string) |
96 | | * byte[]: unpacked mem image of gs_param_xxx_array structure |
97 | | * pad: to array alignment |
98 | | * byte[]: data associated with array contents |
99 | | * (if string/name array) |
100 | | * byte[]: unpacked mem image of gs_param_string_array structure |
101 | | * pad: to void * |
102 | | * { gs_param_string structure mem image; |
103 | | * data associated with string; |
104 | | * } for each string in array |
105 | | * (if dict/dict_int_keys) |
106 | | * word: # of entries in dict, |
107 | | * pad: to void * |
108 | | * dict entries follow immediately until end-of-dict |
109 | | * |
110 | | * NB that this format is designed to allow using an input buffer |
111 | | * as the direct source of data when expanding a gs_c_param_list |
112 | | */ |
113 | | /* Enumerate all the keys; use keys to get their typed values */ |
114 | 0 | while ((code = param_get_next_key(list, &key_enum, &key)) == 0) { |
115 | 0 | int value_top_sizeof; |
116 | 0 | int value_base_sizeof; |
117 | | |
118 | | /* Get next datum & put its type & key to buffer */ |
119 | 0 | gs_param_typed_value value; |
120 | 0 | char string_key[256]; |
121 | |
|
122 | 0 | if (sizeof(string_key) < key.size + 1) { |
123 | 0 | code = gs_note_error(gs_error_rangecheck); |
124 | 0 | break; |
125 | 0 | } |
126 | 0 | memcpy(string_key, key.data, key.size); |
127 | 0 | string_key[key.size] = 0; |
128 | 0 | if ((code = param_read_typed(list, string_key, &value)) != 0) { |
129 | 0 | code = code > 0 ? gs_note_error(gs_error_unknownerror) : code; |
130 | 0 | break; |
131 | 0 | } |
132 | 0 | wb_put_word((unsigned)key.size + 1, &write_buf); |
133 | 0 | wb_put_word((unsigned)value.type, &write_buf); |
134 | 0 | wb_put_bytes((byte *) string_key, key.size + 1, &write_buf); |
135 | | |
136 | | /* Put value & its size to buffer */ |
137 | 0 | value_top_sizeof = gs_param_type_sizes[value.type]; |
138 | 0 | value_base_sizeof = gs_param_type_base_sizes[value.type]; |
139 | 0 | switch (value.type) { |
140 | 0 | case gs_param_type_null: |
141 | 0 | case gs_param_type_bool: |
142 | 0 | case gs_param_type_int: |
143 | 0 | case gs_param_type_long: |
144 | 0 | case gs_param_type_size_t: |
145 | 0 | case gs_param_type_i64: |
146 | 0 | case gs_param_type_float: |
147 | 0 | wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf); |
148 | 0 | break; |
149 | | |
150 | 0 | case gs_param_type_string: |
151 | 0 | case gs_param_type_name: |
152 | 0 | case gs_param_type_int_array: |
153 | 0 | case gs_param_type_float_array: |
154 | 0 | wb_put_bytes((byte *) & value.value, value_top_sizeof, &write_buf); |
155 | 0 | wb_put_alignment(value_base_sizeof, &write_buf); |
156 | 0 | value_base_sizeof *= value.value.s.size; |
157 | 0 | wb_put_bytes(value.value.s.data, value_base_sizeof, &write_buf); |
158 | 0 | break; |
159 | | |
160 | 0 | case gs_param_type_string_array: |
161 | 0 | case gs_param_type_name_array: |
162 | 0 | value_base_sizeof *= value.value.sa.size; |
163 | 0 | wb_put_bytes((const byte *)&value.value, value_top_sizeof, &write_buf); |
164 | 0 | wb_put_alignment(sizeof(void *), &write_buf); |
165 | |
|
166 | 0 | wb_put_bytes((const byte *)value.value.sa.data, value_base_sizeof, |
167 | 0 | &write_buf); |
168 | 0 | { |
169 | 0 | int str_count; |
170 | 0 | const gs_param_string *sa; |
171 | |
|
172 | 0 | for (str_count = value.value.sa.size, |
173 | 0 | sa = value.value.sa.data; str_count-- > 0; ++sa) |
174 | 0 | wb_put_bytes(sa->data, sa->size, &write_buf); |
175 | 0 | } |
176 | 0 | break; |
177 | | |
178 | 0 | case gs_param_type_dict: |
179 | 0 | case gs_param_type_dict_int_keys: |
180 | 0 | wb_put_word(value.value.d.size, &write_buf); |
181 | 0 | wb_put_alignment(sizeof(void *), &write_buf); |
182 | |
|
183 | 0 | { |
184 | 0 | int bytes_written = |
185 | 0 | gs_param_list_serialize(value.value.d.list, |
186 | 0 | write_buf.buf, |
187 | 0 | write_buf.buf ? write_buf.buf_end - write_buf.buf : 0); |
188 | |
|
189 | 0 | temp_code = param_end_read_dict(list, |
190 | 0 | (const char *)key.data, |
191 | 0 | &value.value.d); |
192 | 0 | if (bytes_written < 0) |
193 | 0 | code = bytes_written; |
194 | 0 | else { |
195 | 0 | code = temp_code; |
196 | 0 | if (bytes_written) |
197 | 0 | wb_put_bytes(write_buf.buf, bytes_written, &write_buf); |
198 | 0 | } |
199 | 0 | } |
200 | 0 | break; |
201 | | |
202 | 0 | default: |
203 | 0 | code = gs_note_error(gs_error_unknownerror); |
204 | 0 | break; |
205 | 0 | } |
206 | 0 | if (code < 0) |
207 | 0 | break; |
208 | 0 | } |
209 | | |
210 | | /* Write end marker, which is an (illegal) 0 key length */ |
211 | 0 | if (code >= 0) { |
212 | 0 | wb_put_word(0, &write_buf); |
213 | 0 | code = write_buf.total_sizeof; |
214 | 0 | } |
215 | 0 | return code; |
216 | 0 | } |
217 | | |
218 | | /* ------------ Expander --------------- */ |
219 | | /* Expand a buffer into a gs_param_list (including sub-dicts) */ |
220 | | int /* ret -ve err, +ve # of chars read from buffer */ |
221 | | gs_param_list_unserialize( |
222 | | gs_param_list * list, /* root of list to expand to */ |
223 | | /* list MUST BE IN WRITE MODE */ |
224 | | const byte * buf /* source buffer */ |
225 | | ) |
226 | 0 | { |
227 | 0 | int code = 0; |
228 | 0 | const byte *orig_buf = buf; |
229 | |
|
230 | 0 | do { |
231 | 0 | gs_param_typed_value typed; |
232 | 0 | gs_param_name key; |
233 | 0 | unsigned key_sizeof; |
234 | 0 | int value_top_sizeof; |
235 | 0 | int value_base_sizeof; |
236 | 0 | int temp_code; |
237 | 0 | gs_param_type type; |
238 | | |
239 | | /* key length, 0 indicates end of data */ |
240 | 0 | key_sizeof = buf_get_word(&buf); |
241 | 0 | if (key_sizeof == 0) /* end of data */ |
242 | 0 | break; |
243 | | |
244 | | /* data type */ |
245 | 0 | type = (gs_param_type) buf_get_word(&buf); |
246 | | |
247 | | /* key */ |
248 | 0 | key = (gs_param_name) buf; |
249 | 0 | buf += key_sizeof; |
250 | | |
251 | | /* Data values */ |
252 | 0 | value_top_sizeof = gs_param_type_sizes[type]; |
253 | 0 | value_base_sizeof = gs_param_type_base_sizes[type]; |
254 | 0 | typed.type = type; |
255 | 0 | if (type != gs_param_type_dict && type != gs_param_type_dict_int_keys) { |
256 | 0 | memcpy(&typed.value, buf, value_top_sizeof); |
257 | 0 | buf += value_top_sizeof; |
258 | 0 | } |
259 | 0 | switch (type) { |
260 | 0 | case gs_param_type_null: |
261 | 0 | case gs_param_type_bool: |
262 | 0 | case gs_param_type_int: |
263 | 0 | case gs_param_type_long: |
264 | 0 | case gs_param_type_size_t: |
265 | 0 | case gs_param_type_i64: |
266 | 0 | case gs_param_type_float: |
267 | 0 | break; |
268 | | |
269 | 0 | case gs_param_type_string: |
270 | 0 | case gs_param_type_name: |
271 | 0 | case gs_param_type_int_array: |
272 | 0 | case gs_param_type_float_array: |
273 | 0 | ptr_align_to(&buf, value_base_sizeof); |
274 | 0 | typed.value.s.data = buf; |
275 | 0 | typed.value.s.persistent = false; |
276 | 0 | buf += typed.value.s.size * value_base_sizeof; |
277 | 0 | break; |
278 | | |
279 | 0 | case gs_param_type_string_array: |
280 | 0 | case gs_param_type_name_array: |
281 | 0 | ptr_align_to(&buf, sizeof(void *)); |
282 | |
|
283 | 0 | typed.value.sa.data = (const gs_param_string *)buf; |
284 | 0 | typed.value.sa.persistent = false; |
285 | 0 | buf += typed.value.s.size * value_base_sizeof; |
286 | 0 | { |
287 | 0 | int str_count; |
288 | 0 | gs_param_string *sa; |
289 | |
|
290 | 0 | for (str_count = typed.value.sa.size, |
291 | 0 | sa = (gs_param_string *) typed.value.sa.data; |
292 | 0 | str_count-- > 0; ++sa) { |
293 | 0 | sa->data = buf; |
294 | 0 | sa->persistent = false; |
295 | 0 | buf += sa->size; |
296 | 0 | } |
297 | 0 | } |
298 | 0 | break; |
299 | | |
300 | 0 | case gs_param_type_dict: |
301 | 0 | case gs_param_type_dict_int_keys: |
302 | 0 | typed.value.d.size = buf_get_word(&buf); |
303 | 0 | code = param_begin_write_dict |
304 | 0 | (list, key, &typed.value.d, type == gs_param_type_dict_int_keys); |
305 | 0 | if (code < 0) |
306 | 0 | break; |
307 | 0 | ptr_align_to(&buf, sizeof(void *)); |
308 | |
|
309 | 0 | code = gs_param_list_unserialize(typed.value.d.list, buf); |
310 | 0 | temp_code = param_end_write_dict(list, key, &typed.value.d); |
311 | 0 | if (code >= 0) { |
312 | 0 | buf += code; |
313 | 0 | code = temp_code; |
314 | 0 | } |
315 | 0 | break; |
316 | | |
317 | 0 | default: |
318 | 0 | code = gs_note_error(gs_error_unknownerror); |
319 | 0 | break; |
320 | 0 | } |
321 | 0 | if (code < 0) |
322 | 0 | break; |
323 | 0 | if (typed.type != gs_param_type_dict && typed.type != gs_param_type_dict_int_keys) |
324 | 0 | code = param_write_typed(list, key, &typed); |
325 | 0 | } |
326 | 0 | while (code >= 0); |
327 | | |
328 | 0 | return code >= 0 ? buf - orig_buf : code; |
329 | 0 | } |
330 | | |
331 | | /* ---------- Utility functions -------- */ |
332 | | |
333 | | /* Align a byte pointer on the next Nth byte */ |
334 | | static void |
335 | | ptr_align_to( |
336 | | const byte ** src, /* pointer to align */ |
337 | | unsigned alignment /* alignment, must be power of 2 */ |
338 | | ) |
339 | 0 | { |
340 | 0 | *src += -(int)ALIGNMENT_MOD(*src, alignment) & (alignment - 1); |
341 | 0 | } |
342 | | |
343 | | /* Put compressed word repr to a buffer */ |
344 | | static void |
345 | | wb_put_word( |
346 | | unsigned source, /* number to put to buffer */ |
347 | | WriteBuffer * dest /* destination descriptor */ |
348 | | ) |
349 | 0 | { |
350 | 0 | do { |
351 | 0 | byte chunk = source & 0x7f; |
352 | |
|
353 | 0 | if (source >= 0x80) |
354 | 0 | chunk |= 0x80; |
355 | 0 | source >>= 7; |
356 | 0 | ++dest->total_sizeof; |
357 | 0 | if (dest->buf && dest->buf < dest->buf_end) |
358 | 0 | *dest->buf++ = chunk; |
359 | 0 | } |
360 | 0 | while (source != 0); |
361 | 0 | } |
362 | | |
363 | | /* Put array of bytes to buffer */ |
364 | | static void |
365 | | wb_put_bytes( |
366 | | const byte * source, /* bytes to put to buffer */ |
367 | | unsigned source_sizeof, /* # bytes to put */ |
368 | | WriteBuffer * dest /* destination descriptor */ |
369 | | ) |
370 | 0 | { |
371 | 0 | dest->total_sizeof += source_sizeof; |
372 | 0 | if (dest->buf && dest->buf + source_sizeof <= dest->buf_end) { |
373 | 0 | if (dest->buf != source) |
374 | 0 | memcpy(dest->buf, source, source_sizeof); |
375 | 0 | dest->buf += source_sizeof; |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | | /* Pad destination out to req'd alignment w/zeros */ |
380 | | static void |
381 | | wb_put_alignment( |
382 | | unsigned alignment, /* alignment to match, must be power 2 */ |
383 | | WriteBuffer * dest /* destination descriptor */ |
384 | | ) |
385 | 0 | { |
386 | 0 | static const byte zero = |
387 | 0 | {0}; |
388 | |
|
389 | 0 | while ((dest->total_sizeof & (alignment - 1)) != 0) |
390 | 0 | wb_put_bytes(&zero, 1, dest); |
391 | 0 | } |
392 | | |
393 | | /* Get word compressed with wb_put_word */ |
394 | | static unsigned /* decompressed word */ |
395 | | buf_get_word( |
396 | | const byte ** src /* UPDATES: ptr to src buf ptr */ |
397 | | ) |
398 | 0 | { |
399 | 0 | unsigned dest = 0; |
400 | 0 | byte chunk; |
401 | 0 | unsigned shift = 0; |
402 | |
|
403 | 0 | do { |
404 | 0 | chunk = *(*src)++; |
405 | 0 | dest |= (chunk & 0x7f) << shift; |
406 | 0 | shift += 7; |
407 | 0 | } |
408 | 0 | while (chunk & 0x80); |
409 | |
|
410 | 0 | return dest; |
411 | 0 | } |