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