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