1 /* Copyright (C) 1998 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: gsparam2.c,v 1.6 2002/07/01 14:27:43 jeong Exp $ */
18 /* Serialize and unserialize parameter lists */
19
20 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
21 /* 8/8/98 L. Peter Deutsch (ghost@aladdin.com) Rewritten to use streams */
22
23 #include "gx.h"
24 #include "memory_.h"
25 #include "gserrors.h"
26 #include "gsparams.h"
27
28 #define MAX_PARAM_KEY 255
29
30 /* ---------------- Serializer ---------------- */
31
32 /* Forward references */
33 private int sput_word(stream *dest, uint value);
34 private int sput_bytes(stream *dest, const byte *data, uint size);
35
36 /*
37 * Serialize the contents of a gs_param_list, including sub-dictionaries,
38 * onto a stream. The list must be in READ mode.
39 */
40 int
gs_param_list_puts(stream * dest,gs_param_list * list)41 gs_param_list_puts(stream *dest, gs_param_list *list)
42 {
43 int code = 0;
44 gs_param_enumerator_t key_enum;
45 gs_param_key_t key;
46
47 param_init_enumerator(&key_enum);
48
49 /* Each item is serialized as ("word" means compressed word):
50 * word: key sizeof + 1, or 0 if end of list/dict
51 * word: data type(gs_param_type_xxx)
52 * byte[]: key, including trailing \0
53 * (if simple type)
54 * byte[]: unpacked representation of data
55 * (if simple array or string)
56 * word: # of elements
57 * byte[]: data associated with array contents
58 * (if string/name array)
59 * word: # of elements
60 * { word: length of string
61 * byte[]: string data
62 * } for each string in array
63 * (if dict/dict_int_keys/hetero_array)
64 * word: # of entries in collection
65 * entries follow immediately
66 */
67 /* Enumerate all the keys; use keys to get their typed values */
68 while ((code = param_get_next_key(list, &key_enum, &key)) == 0) {
69 int value_top_sizeof;
70 int value_base_sizeof;
71 const void *data;
72 uint size;
73
74 /* Get next datum & put its type & key to stream */
75 gs_param_typed_value value;
76 char string_key[MAX_PARAM_KEY + 1];
77
78 if (sizeof(string_key) < key.size + 1) {
79 code = gs_note_error(gs_error_rangecheck);
80 break;
81 }
82 memcpy(string_key, key.data, key.size);
83 string_key[key.size] = 0;
84 if ((code = param_read_typed(list, string_key, &value)) != 0) {
85 if (code > 0)
86 code = gs_note_error(gs_error_unknownerror);
87 break;
88 }
89 sput_word(dest, (unsigned)key.size + 1);
90 sput_word(dest, (unsigned)value.type);
91 sput_bytes(dest, (byte *)string_key, key.size + 1);
92
93 /* Put value & its size to stream */
94 value_top_sizeof = gs_param_type_sizes[value.type];
95 value_base_sizeof = gs_param_type_base_sizes[value.type];
96 switch (value.type) {
97 case gs_param_type_bool:
98 case gs_param_type_int:
99 case gs_param_type_long:
100 case gs_param_type_float:
101 sput_bytes(dest, (byte *)&value.value, value_top_sizeof);
102 case gs_param_type_null:
103 break;
104
105 case gs_param_type_string:
106 data = value.value.s.data, size = value.value.s.size;
107 goto scalar_array;
108 case gs_param_type_name:
109 data = value.value.n.data, size = value.value.n.size;
110 goto scalar_array;
111 case gs_param_type_int_array:
112 data = value.value.ia.data, size = value.value.ia.size;
113 goto scalar_array;
114 case gs_param_type_float_array:
115 data = value.value.fa.data, size = value.value.fa.size;
116 scalar_array: sput_word(dest, size);
117 sput_bytes(dest, data, value_base_sizeof * size);
118 break;
119
120 case gs_param_type_string_array:
121 data = value.value.sa.data, size = value.value.sa.size;
122 goto string_array;
123 case gs_param_type_name_array:
124 data = value.value.na.data, size = value.value.na.size;
125 string_array: sput_word(dest, size);
126 {
127 uint count;
128 const gs_param_string *sa;
129
130 for (count = size, sa = data; count-- > 0; ++sa) {
131 sput_word(dest, sa->size);
132 sput_bytes(dest, sa->data, sa->size);
133 }
134 }
135 break;
136
137 case gs_param_type_dict:
138 case gs_param_type_dict_int_keys:
139 case gs_param_type_array:
140 sput_word(dest, value.value.d.size);
141 code = gs_param_list_puts(dest, value.value.d.list);
142 {
143 int end_code =
144 param_end_read_dict(list, key.data, &value.value.d);
145
146 if (code >= 0)
147 code = end_code;
148 }
149 break;
150
151 default:
152 code = gs_note_error(gs_error_unknownerror);
153 break;
154 }
155 if (code < 0)
156 break;
157 }
158
159 /* Write end marker, which is an (illegal) 0 key length */
160 return (code < 0 ? code : sput_word(dest, 0));
161 }
162
163 /* Put a variable-length value on a stream. */
164 private int
sput_word(stream * dest,uint value)165 sput_word(stream *dest, uint value)
166 {
167 int code = 0;
168
169 do {
170 byte chunk = value & 0x7f;
171
172 if ((value >>= 7) != 0)
173 chunk |= 0x80;
174 if ((code = sputc(dest, chunk)) < 0)
175 break;
176 }
177 while (value != 0);
178 return code;
179 }
180
181 /* Put bytes on a stream. */
182 private int
sput_bytes(stream * dest,const byte * data,uint size)183 sput_bytes(stream *dest, const byte *data, uint size)
184 {
185 uint ignore_count;
186
187 return sputs(dest, data, size, &ignore_count);
188 }
189
190 /* ---------------- Unserializer ---------------- */
191
192 /* Forward references */
193 private int sget_word(stream *src, uint *pvalue);
194 private int sget_bytes(stream *src, byte *data, uint size);
195
196 /*
197 * Unserialize a parameter list from a stream. The list must be in WRITE
198 * mode.
199 */
200 int
gs_param_list_gets(stream * src,gs_param_list * list,gs_memory_t * mem)201 gs_param_list_gets(stream *src, gs_param_list *list, gs_memory_t *mem)
202 {
203 int code = 0;
204
205 do {
206 gs_param_typed_value typed;
207 uint key_sizeof;
208 int value_top_sizeof;
209 int value_base_sizeof;
210 uint temp;
211 void *data;
212 uint size;
213 gs_param_type type;
214 char string_key[MAX_PARAM_KEY + 1];
215
216 /* key length 0 indicates end of data */
217 if ((code = sget_word(src, &key_sizeof)) < 0 ||
218 key_sizeof == 0 ||
219 /* data type */
220 (code = sget_word(src, &temp)) < 0)
221 break;
222
223 if (key_sizeof > sizeof(string_key)) {
224 code = gs_note_error(gs_error_rangecheck);
225 break;
226 }
227 /* key */
228 code = sget_bytes(src, (byte *)string_key, key_sizeof);
229 if (code < 0)
230 break;
231
232 /* Data values */
233 type = (gs_param_type)temp;
234 value_top_sizeof = gs_param_type_sizes[type];
235 value_base_sizeof = gs_param_type_base_sizes[type];
236 typed.type = type;
237 switch (type) {
238 case gs_param_type_bool:
239 case gs_param_type_int:
240 case gs_param_type_long:
241 case gs_param_type_float:
242 code = sget_bytes(src, (byte *)&typed.value, value_top_sizeof);
243 case gs_param_type_null:
244 goto put;
245 default:
246 ;
247 }
248 /* All other data values start with a size. */
249 code = sget_word(src, &size);
250 if (code < 0)
251 break;
252
253 switch (type) {
254 case gs_param_type_string:
255 case gs_param_type_name:
256 case gs_param_type_int_array:
257 case gs_param_type_float_array:
258 data =
259 (value_base_sizeof == 1 ?
260 gs_alloc_string(mem, size, "param string/name") :
261 gs_alloc_byte_array(mem, size, value_base_sizeof,
262 "param scalar array"));
263 if (data == 0) {
264 code = gs_note_error(gs_error_VMerror);
265 break;
266 }
267 typed.value.s.data = data;
268 typed.value.s.persistent = false;
269 typed.value.s.size = size;
270 code = sget_bytes(src, data, size * value_base_sizeof);
271 break;
272
273 case gs_param_type_string_array:
274 case gs_param_type_name_array:
275 /****** SHOULD BE STRUCT ARRAY ******/
276 data = gs_alloc_byte_array(mem, size, value_top_sizeof,
277 "param string/name array");
278 if (data == 0) {
279 code = gs_note_error(gs_error_VMerror);
280 break;
281 }
282 typed.value.sa.data = data;
283 typed.value.sa.persistent = false;
284 typed.value.sa.size = size;
285 {
286 gs_param_string *sa = data;
287 byte *str_data;
288 uint index, str_size;
289
290 /* Clean pointers in case we bail out. */
291 for (index = 0; index < size; ++index)
292 sa[index].data = 0, sa[index].size = 0;
293 for (index = 0; index < size; ++index, ++sa) {
294 code = sget_word(src, &str_size);
295 if (code < 0)
296 break;
297 str_data = gs_alloc_string(mem, str_size,
298 "param string/name element");
299 if (str_data == 0) {
300 code = gs_note_error(gs_error_VMerror);
301 break;
302 }
303 code = sget_bytes(src, str_data, str_size);
304 if (code < 0)
305 break;
306 }
307 }
308 break;
309
310 case gs_param_type_dict:
311 case gs_param_type_dict_int_keys:
312 case gs_param_type_array:
313 typed.value.d.size = size;
314 code = param_begin_write_collection
315 (list, string_key, &typed.value.d,
316 type - gs_param_type_dict);
317 if (code < 0)
318 break;
319 code = gs_param_list_gets(src, typed.value.d.list, mem);
320 {
321 int end_code =
322 param_end_write_collection(list, string_key,
323 &typed.value.d);
324
325 if (code >= 0)
326 code = end_code;
327 }
328 break;
329
330 default:
331 code = gs_note_error(gs_error_unknownerror);
332 break;
333 }
334 put: if (code < 0)
335 break;
336 if (typed.type != gs_param_type_dict &&
337 typed.type != gs_param_type_dict_int_keys &&
338 typed.type != gs_param_type_array
339 )
340 code = param_write_typed(list, string_key, &typed);
341 }
342 while (code >= 0);
343
344 return code;
345 }
346
347
348 /* ---------- Utility functions -------- */
349
350 /* Get a value stored with sput_word */
351 private int
sget_word(stream * src,uint * pvalue)352 sget_word(stream *src, uint *pvalue)
353 {
354 uint value = 0;
355 int chunk;
356 uint shift = 0;
357
358 do {
359 chunk = sgetc(src);
360 if (chunk < 0)
361 return chunk;
362 value |= (chunk & 0x7f) << shift;
363 shift += 7;
364 }
365 while (chunk & 0x80);
366
367 *pvalue = value;
368 return 0;
369 }
370
371 /* Get bytes from a stream */
372 private int
sget_bytes(stream * src,byte * data,uint size)373 sget_bytes(stream *src, byte *data, uint size)
374 {
375 uint ignore_count;
376
377 int status = sgets(src, data, size, &ignore_count);
378
379 if (status < 0 && status != EOFC)
380 return_error(gs_error_ioerror);
381 };
382
383 return 0;
384 }
385