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