1 /* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
3 This file is part of GNU Ghostscript.
5 GNU Ghostscript is distributed in the hope that it will be useful, but
6 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
7 to anyone for the consequences of using it or for whether it serves any
8 particular purpose or works at all, unless he says so in writing. Refer
9 to the GNU General Public License for full details.
11 Everyone is granted permission to copy, modify and redistribute GNU
12 Ghostscript, but only under the conditions described in the GNU General
13 Public License. A copy of this license is supposed to have been given
14 to you along with GNU Ghostscript so you can know your rights and
15 responsibilities. It should be in a file named COPYING. Among other
16 things, the copyright notice and this notice must be preserved on all
19 Aladdin Enterprises supports the work of the GNU Project, but is not
20 affiliated with the Free Software Foundation or the GNU Project. GNU
21 Ghostscript, as distributed by Aladdin Enterprises, does not require any
22 GNU software to build or run it.
26 /* Generic parameter list serializer & expander */
28 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
35 /* ----------- Local Type Decl's ------------ */
37 byte
*buf
; /* current buffer ptr */
38 byte
*buf_end
; /* end of buffer */
39 unsigned total_sizeof
; /* current # bytes in buf */
42 /* ---------- Forward refs ----------- */
45 const byte
** src
, /* pointer to align */
46 unsigned alignment
/* alignment, must be power of 2 */
50 unsigned source
, /* number to put to buffer */
51 WriteBuffer
* dest
/* destination descriptor */
55 const byte
* source
, /* bytes to put to buffer */
56 unsigned source_sizeof
, /* # bytes to put */
57 WriteBuffer
* dest
/* destination descriptor */
61 unsigned alignment
, /* alignment to match, must be power 2 */
62 WriteBuffer
* dest
/* destination descriptor */
65 /* Get word compressed with put_word */
66 private unsigned /* decompressed word */
68 const byte
** src
/* UPDATES: ptr to src buf ptr */
72 /* ------------ Serializer ------------ */
73 /* Serialize the contents of a gs_param_list (including sub-dicts) */
74 int /* ret -ve err, else # bytes needed to represent param list, whether */
76 /* or not it actually fit into buffer. List was successully */
78 /* serialized only if if this # is <= supplied buf size. */
79 gs_param_list_serialize(
80 gs_param_list
* list
, /* root of list to serialize */
81 /* list MUST BE IN READ MODE */
82 byte
* buf
, /* destination buffer (can be 0) */
83 int buf_sizeof
/* # bytes available in buf (can be 0) */
88 gs_param_enumerator_t key_enum
;
90 WriteBuffer write_buf
;
93 write_buf
.buf_end
= buf
+ (buf
? buf_sizeof
: 0);
94 write_buf
.total_sizeof
= 0;
95 param_init_enumerator(&key_enum
);
97 /* Each item is serialized as ("word" means compressed word):
98 * word: key sizeof + 1, or 0 if end of list/dict
99 * word: data type(gs_param_type_xxx)
100 * byte[]: key, including trailing \0
102 * byte[]: unpacked representation of data
103 * (if simple array or string)
104 * byte[]: unpacked mem image of gs_param_xxx_array structure
105 * pad: to array alignment
106 * byte[]: data associated with array contents
107 * (if string/name array)
108 * byte[]: unpacked mem image of gs_param_string_array structure
110 * { gs_param_string structure mem image;
111 * data associated with string;
112 * } for each string in array
113 * (if dict/dict_int_keys)
114 * word: # of entries in dict,
116 * dict entries follow immediately until end-of-dict
118 * NB that this format is designed to allow using an input buffer
119 * as the direct source of data when expanding a gs_c_param_list
121 /* Enumerate all the keys; use keys to get their typed values */
122 while ((code
= param_get_next_key(list
, &key_enum
, &key
)) == 0) {
123 int value_top_sizeof
;
124 int value_base_sizeof
;
126 /* Get next datum & put its type & key to buffer */
127 gs_param_typed_value value
;
128 char string_key
[256];
130 if (sizeof(string_key
) < key
.size
+ 1) {
131 code
= gs_note_error(gs_error_rangecheck
);
134 memcpy(string_key
, key
.data
, key
.size
);
135 string_key
[key
.size
] = 0;
136 if ((code
= param_read_typed(list
, string_key
, &value
)) != 0) {
137 code
= code
> 0 ? gs_note_error(gs_error_unknownerror
) : code
;
140 put_word((unsigned)key
.size
+ 1, &write_buf
);
141 put_word((unsigned)value
.type
, &write_buf
);
142 put_bytes((byte
*) string_key
, key
.size
+ 1, &write_buf
);
144 /* Put value & its size to buffer */
145 value_top_sizeof
= gs_param_type_sizes
[value
.type
];
146 value_base_sizeof
= gs_param_type_base_sizes
[value
.type
];
147 switch (value
.type
) {
148 case gs_param_type_null
:
149 case gs_param_type_bool
:
150 case gs_param_type_int
:
151 case gs_param_type_long
:
152 case gs_param_type_float
:
153 put_bytes((byte
*) & value
.value
, value_top_sizeof
, &write_buf
);
156 case gs_param_type_string
:
157 case gs_param_type_name
:
158 case gs_param_type_int_array
:
159 case gs_param_type_float_array
:
160 put_bytes((byte
*) & value
.value
, value_top_sizeof
, &write_buf
);
161 put_alignment(value_base_sizeof
, &write_buf
);
162 value_base_sizeof
*= value
.value
.s
.size
;
163 put_bytes(value
.value
.s
.data
, value_base_sizeof
, &write_buf
);
166 case gs_param_type_string_array
:
167 case gs_param_type_name_array
:
168 value_base_sizeof
*= value
.value
.sa
.size
;
169 put_bytes((const byte
*)&value
.value
, value_top_sizeof
, &write_buf
);
170 put_alignment(sizeof(void *), &write_buf
);
172 put_bytes((const byte
*)value
.value
.sa
.data
, value_base_sizeof
,
176 const gs_param_string
*sa
;
178 for (str_count
= value
.value
.sa
.size
,
179 sa
= value
.value
.sa
.data
; str_count
-- > 0; ++sa
)
180 put_bytes(sa
->data
, sa
->size
, &write_buf
);
184 case gs_param_type_dict
:
185 case gs_param_type_dict_int_keys
:
186 put_word(value
.value
.d
.size
, &write_buf
);
187 put_alignment(sizeof(void *), &write_buf
);
191 gs_param_list_serialize(value
.value
.d
.list
,
193 write_buf
.buf
? write_buf
.buf_end
- write_buf
.buf
: 0);
195 temp_code
= param_end_read_dict(list
,
196 (const char *)key
.data
,
198 if (bytes_written
< 0)
199 code
= bytes_written
;
203 put_bytes(write_buf
.buf
, bytes_written
, &write_buf
);
209 code
= gs_note_error(gs_error_unknownerror
);
216 /* Write end marker, which is an (illegal) 0 key length */
218 put_word(0, &write_buf
);
219 code
= write_buf
.total_sizeof
;
225 /* ------------ Expander --------------- */
226 /* Expand a buffer into a gs_param_list (including sub-dicts) */
227 int /* ret -ve err, +ve # of chars read from buffer */
228 gs_param_list_unserialize(
229 gs_param_list
* list
, /* root of list to expand to */
230 /* list MUST BE IN WRITE MODE */
231 const byte
* buf
/* source buffer */
235 const byte
*orig_buf
= buf
;
238 gs_param_typed_value typed
;
241 int value_top_sizeof
;
242 int value_base_sizeof
;
246 /* key length, 0 indicates end of data */
247 key_sizeof
= get_word(&buf
);
248 if (key_sizeof
== 0) /* end of data */
252 type
= (gs_param_type
) get_word(&buf
);
255 key
= (gs_param_name
) buf
;
259 value_top_sizeof
= gs_param_type_sizes
[type
];
260 value_base_sizeof
= gs_param_type_base_sizes
[type
];
262 if (type
!= gs_param_type_dict
&& type
!= gs_param_type_dict_int_keys
) {
263 memcpy(&typed
.value
, buf
, value_top_sizeof
);
264 buf
+= value_top_sizeof
;
267 case gs_param_type_null
:
268 case gs_param_type_bool
:
269 case gs_param_type_int
:
270 case gs_param_type_long
:
271 case gs_param_type_float
:
274 case gs_param_type_string
:
275 case gs_param_type_name
:
276 case gs_param_type_int_array
:
277 case gs_param_type_float_array
:
278 align_to(&buf
, value_base_sizeof
);
279 typed
.value
.s
.data
= buf
;
280 typed
.value
.s
.persistent
= false;
281 buf
+= typed
.value
.s
.size
* value_base_sizeof
;
284 case gs_param_type_string_array
:
285 case gs_param_type_name_array
:
286 align_to(&buf
, sizeof(void *));
288 typed
.value
.sa
.data
= (const gs_param_string
*)buf
;
289 typed
.value
.sa
.persistent
= false;
290 buf
+= typed
.value
.s
.size
* value_base_sizeof
;
295 for (str_count
= typed
.value
.sa
.size
,
296 sa
= (gs_param_string
*) typed
.value
.sa
.data
;
297 str_count
-- > 0; ++sa
) {
299 sa
->persistent
= false;
305 case gs_param_type_dict
:
306 case gs_param_type_dict_int_keys
:
307 typed
.value
.d
.size
= get_word(&buf
);
308 code
= param_begin_write_dict
309 (list
, key
, &typed
.value
.d
, type
== gs_param_type_dict_int_keys
);
312 align_to(&buf
, sizeof(void *));
314 code
= gs_param_list_unserialize(typed
.value
.d
.list
, buf
);
315 temp_code
= param_end_write_dict(list
, key
, &typed
.value
.d
);
323 code
= gs_note_error(gs_error_unknownerror
);
328 if (typed
.type
!= gs_param_type_dict
&& typed
.type
!= gs_param_type_dict_int_keys
)
329 code
= param_write_typed(list
, key
, &typed
);
333 return code
>= 0 ? buf
- orig_buf
: code
;
337 /* ---------- Utility functions -------- */
339 /* Align a byte pointer on the next Nth byte */
342 const byte
** src
, /* pointer to align */
343 unsigned alignment
/* alignment, must be power of 2 */
346 *src
+= -(int)alignment_mod(*src
, alignment
) & (alignment
- 1);
349 /* Put compressed word repr to a buffer */
352 unsigned source
, /* number to put to buffer */
353 WriteBuffer
* dest
/* destination descriptor */
357 byte chunk
= source
& 0x7f;
362 ++dest
->total_sizeof
;
363 if (dest
->buf
&& dest
->buf
< dest
->buf_end
)
364 *dest
->buf
++ = chunk
;
369 /* Put array of bytes to buffer */
372 const byte
* source
, /* bytes to put to buffer */
373 unsigned source_sizeof
, /* # bytes to put */
374 WriteBuffer
* dest
/* destination descriptor */
377 dest
->total_sizeof
+= source_sizeof
;
378 if (dest
->buf
&& dest
->buf
+ source_sizeof
<= dest
->buf_end
) {
379 if (dest
->buf
!= source
)
380 memcpy(dest
->buf
, source
, source_sizeof
);
381 dest
->buf
+= source_sizeof
;
385 /* Pad destination out to req'd alignment w/zeros */
388 unsigned alignment
, /* alignment to match, must be power 2 */
389 WriteBuffer
* dest
/* destination descriptor */
392 static const byte zero
=
395 while ((dest
->total_sizeof
& (alignment
- 1)) != 0)
396 put_bytes(&zero
, 1, dest
);
399 /* Get word compressed with put_word */
400 private unsigned /* decompressed word */
402 const byte
** src
/* UPDATES: ptr to src buf ptr */
411 dest
|= (chunk
& 0x7f) << shift
;
414 while (chunk
& 0x80);