]> git.ipfire.org Git - thirdparty/cups.git/blob - pstoraster/gsparams.c
Import cups.org releases
[thirdparty/cups.git] / pstoraster / gsparams.c
1 /* Copyright (C) 1998 Aladdin Enterprises. All rights reserved.
2
3 This file is part of GNU Ghostscript.
4
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.
10
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
17 copies.
18
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.
23 */
24
25 /*$Id$ */
26 /* Generic parameter list serializer & expander */
27
28 /* Initial version 2/1/98 by John Desrosiers (soho@crl.com) */
29
30 #include "gx.h"
31 #include "memory_.h"
32 #include "gserrors.h"
33 #include "gsparams.h"
34
35 /* ----------- Local Type Decl's ------------ */
36 typedef struct {
37 byte *buf; /* current buffer ptr */
38 byte *buf_end; /* end of buffer */
39 unsigned total_sizeof; /* current # bytes in buf */
40 } WriteBuffer;
41
42 /* ---------- Forward refs ----------- */
43 private void
44 align_to(P2(
45 const byte ** src, /* pointer to align */
46 unsigned alignment /* alignment, must be power of 2 */
47 ));
48 private void
49 put_word(P2(
50 unsigned source, /* number to put to buffer */
51 WriteBuffer * dest /* destination descriptor */
52 ));
53 private void
54 put_bytes(P3(
55 const byte * source, /* bytes to put to buffer */
56 unsigned source_sizeof, /* # bytes to put */
57 WriteBuffer * dest /* destination descriptor */
58 ));
59 private void
60 put_alignment(P2(
61 unsigned alignment, /* alignment to match, must be power 2 */
62 WriteBuffer * dest /* destination descriptor */
63 ));
64
65 /* Get word compressed with put_word */
66 private unsigned /* decompressed word */
67 get_word(P1(
68 const byte ** src /* UPDATES: ptr to src buf ptr */
69 ));
70
71
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 */
75
76 /* or not it actually fit into buffer. List was successully */
77
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) */
84 )
85 {
86 int code = 0;
87 int temp_code;
88 gs_param_enumerator_t key_enum;
89 gs_param_key_t key;
90 WriteBuffer write_buf;
91
92 write_buf.buf = buf;
93 write_buf.buf_end = buf + (buf ? buf_sizeof : 0);
94 write_buf.total_sizeof = 0;
95 param_init_enumerator(&key_enum);
96
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
101 * (if simple type)
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
109 * pad: to void *
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,
115 * pad: to void *
116 * dict entries follow immediately until end-of-dict
117 *
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
120 */
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;
125
126 /* Get next datum & put its type & key to buffer */
127 gs_param_typed_value value;
128 char string_key[256];
129
130 if (sizeof(string_key) < key.size + 1) {
131 code = gs_note_error(gs_error_rangecheck);
132 break;
133 }
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;
138 break;
139 }
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);
143
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);
154 break;
155
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);
164 break;
165
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);
171
172 put_bytes((const byte *)value.value.sa.data, value_base_sizeof,
173 &write_buf);
174 {
175 int str_count;
176 const gs_param_string *sa;
177
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);
181 }
182 break;
183
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);
188
189 {
190 int bytes_written =
191 gs_param_list_serialize(value.value.d.list,
192 write_buf.buf,
193 write_buf.buf ? write_buf.buf_end - write_buf.buf : 0);
194
195 temp_code = param_end_read_dict(list,
196 (const char *)key.data,
197 &value.value.d);
198 if (bytes_written < 0)
199 code = bytes_written;
200 else {
201 code = temp_code;
202 if (bytes_written)
203 put_bytes(write_buf.buf, bytes_written, &write_buf);
204 }
205 }
206 break;
207
208 default:
209 code = gs_note_error(gs_error_unknownerror);
210 break;
211 }
212 if (code < 0)
213 break;
214 }
215
216 /* Write end marker, which is an (illegal) 0 key length */
217 if (code >= 0) {
218 put_word(0, &write_buf);
219 code = write_buf.total_sizeof;
220 }
221 return code;
222 }
223
224
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 */
232 )
233 {
234 int code = 0;
235 const byte *orig_buf = buf;
236
237 do {
238 gs_param_typed_value typed;
239 gs_param_name key;
240 unsigned key_sizeof;
241 int value_top_sizeof;
242 int value_base_sizeof;
243 int temp_code;
244 gs_param_type type;
245
246 /* key length, 0 indicates end of data */
247 key_sizeof = get_word(&buf);
248 if (key_sizeof == 0) /* end of data */
249 break;
250
251 /* data type */
252 type = (gs_param_type) get_word(&buf);
253
254 /* key */
255 key = (gs_param_name) buf;
256 buf += key_sizeof;
257
258 /* Data values */
259 value_top_sizeof = gs_param_type_sizes[type];
260 value_base_sizeof = gs_param_type_base_sizes[type];
261 typed.type = 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;
265 }
266 switch (type) {
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:
272 break;
273
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;
282 break;
283
284 case gs_param_type_string_array:
285 case gs_param_type_name_array:
286 align_to(&buf, sizeof(void *));
287
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;
291 {
292 int str_count;
293 gs_param_string *sa;
294
295 for (str_count = typed.value.sa.size,
296 sa = (gs_param_string *) typed.value.sa.data;
297 str_count-- > 0; ++sa) {
298 sa->data = buf;
299 sa->persistent = false;
300 buf += sa->size;
301 }
302 }
303 break;
304
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);
310 if (code < 0)
311 break;
312 align_to(&buf, sizeof(void *));
313
314 code = gs_param_list_unserialize(typed.value.d.list, buf);
315 temp_code = param_end_write_dict(list, key, &typed.value.d);
316 if (code >= 0) {
317 buf += code;
318 code = temp_code;
319 }
320 break;
321
322 default:
323 code = gs_note_error(gs_error_unknownerror);
324 break;
325 }
326 if (code < 0)
327 break;
328 if (typed.type != gs_param_type_dict && typed.type != gs_param_type_dict_int_keys)
329 code = param_write_typed(list, key, &typed);
330 }
331 while (code >= 0);
332
333 return code >= 0 ? buf - orig_buf : code;
334 }
335
336
337 /* ---------- Utility functions -------- */
338
339 /* Align a byte pointer on the next Nth byte */
340 private void
341 align_to(
342 const byte ** src, /* pointer to align */
343 unsigned alignment /* alignment, must be power of 2 */
344 )
345 {
346 *src += -(int)alignment_mod(*src, alignment) & (alignment - 1);
347 }
348
349 /* Put compressed word repr to a buffer */
350 private void
351 put_word(
352 unsigned source, /* number to put to buffer */
353 WriteBuffer * dest /* destination descriptor */
354 )
355 {
356 do {
357 byte chunk = source & 0x7f;
358
359 if (source >= 0x80)
360 chunk |= 0x80;
361 source >>= 7;
362 ++dest->total_sizeof;
363 if (dest->buf && dest->buf < dest->buf_end)
364 *dest->buf++ = chunk;
365 }
366 while (source != 0);
367 }
368
369 /* Put array of bytes to buffer */
370 private void
371 put_bytes(
372 const byte * source, /* bytes to put to buffer */
373 unsigned source_sizeof, /* # bytes to put */
374 WriteBuffer * dest /* destination descriptor */
375 )
376 {
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;
382 }
383 }
384
385 /* Pad destination out to req'd alignment w/zeros */
386 private void
387 put_alignment(
388 unsigned alignment, /* alignment to match, must be power 2 */
389 WriteBuffer * dest /* destination descriptor */
390 )
391 {
392 static const byte zero =
393 {0};
394
395 while ((dest->total_sizeof & (alignment - 1)) != 0)
396 put_bytes(&zero, 1, dest);
397 }
398
399 /* Get word compressed with put_word */
400 private unsigned /* decompressed word */
401 get_word(
402 const byte ** src /* UPDATES: ptr to src buf ptr */
403 )
404 {
405 unsigned dest = 0;
406 byte chunk;
407 unsigned shift = 0;
408
409 do {
410 chunk = *(*src)++;
411 dest |= (chunk & 0x7f) << shift;
412 shift += 7;
413 }
414 while (chunk & 0x80);
415
416 return dest;
417 }