xref: /plan9/sys/src/cmd/gs/src/gsparam2.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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