1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gsparam.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* Support for parameter lists */
16 #include "memory_.h"
17 #include "string_.h"
18 #include "gx.h"
19 #include "gserrors.h"
20 #include "gsparam.h"
21 #include "gsstruct.h"
22
23 /* GC procedures */
24 ENUM_PTRS_WITH(gs_param_typed_value_enum_ptrs, gs_param_typed_value *pvalue) return 0;
25 case 0:
26 switch (pvalue->type) {
27 case gs_param_type_string:
28 return ENUM_STRING(&pvalue->value.s);
29 case gs_param_type_name:
30 return ENUM_STRING(&pvalue->value.n);
31 case gs_param_type_int_array:
32 return ENUM_OBJ(pvalue->value.ia.data);
33 case gs_param_type_float_array:
34 return ENUM_OBJ(pvalue->value.fa.data);
35 case gs_param_type_string_array:
36 return ENUM_OBJ(pvalue->value.sa.data);
37 case gs_param_type_name_array:
38 return ENUM_OBJ(pvalue->value.na.data);
39 default:
40 return ENUM_OBJ(0); /* don't stop early */
41 }
42 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_param_typed_value_reloc_ptrs,gs_param_typed_value * pvalue)43 RELOC_PTRS_WITH(gs_param_typed_value_reloc_ptrs, gs_param_typed_value *pvalue) {
44 switch (pvalue->type) {
45 case gs_param_type_string:
46 case gs_param_type_name: {
47 gs_const_string str;
48
49 str.data = pvalue->value.s.data; /* n == s */
50 str.size = pvalue->value.s.size;
51 RELOC_CONST_STRING_VAR(str);
52 pvalue->value.s.data = str.data;
53 break;
54 }
55 case gs_param_type_int_array:
56 RELOC_VAR(pvalue->value.ia.data);
57 break;
58 case gs_param_type_float_array:
59 RELOC_VAR(pvalue->value.fa.data);
60 break;
61 case gs_param_type_string_array:
62 RELOC_VAR(pvalue->value.sa.data);
63 break;
64 case gs_param_type_name_array:
65 RELOC_VAR(pvalue->value.na.data);
66 break;
67 default:
68 break;
69 }
70 }
71 RELOC_PTRS_END
72
73 /* Internal procedure to initialize the common part of a parameter list. */
74 void
gs_param_list_init(gs_param_list * plist,const gs_param_list_procs * procs,gs_memory_t * mem)75 gs_param_list_init(gs_param_list *plist, const gs_param_list_procs *procs,
76 gs_memory_t *mem)
77 {
78 plist->procs = procs;
79 plist->memory = mem;
80 plist->persistent_keys = true;
81 }
82
83 /* Set whether the keys for param_write_XXX are persistent. */
84 void
gs_param_list_set_persistent_keys(gs_param_list * plist,bool persistent)85 gs_param_list_set_persistent_keys(gs_param_list *plist, bool persistent)
86 {
87 plist->persistent_keys = persistent;
88 }
89
90 /* Reset a gs_param_key_t enumerator to its initial state */
91 void
param_init_enumerator(gs_param_enumerator_t * enumerator)92 param_init_enumerator(gs_param_enumerator_t * enumerator)
93 {
94 memset(enumerator, 0, sizeof(*enumerator));
95 }
96
97 /* Transfer a collection of parameters. */
98 static const byte xfer_item_sizes[] = {
99 GS_PARAM_TYPE_SIZES(0)
100 };
101 int
gs_param_read_items(gs_param_list * plist,void * obj,const gs_param_item_t * items)102 gs_param_read_items(gs_param_list * plist, void *obj,
103 const gs_param_item_t * items)
104 {
105 const gs_param_item_t *pi;
106 int ecode = 0;
107
108 for (pi = items; pi->key != 0; ++pi) {
109 const char *key = pi->key;
110 void *pvalue = (void *)((char *)obj + pi->offset);
111 gs_param_typed_value typed;
112 int code;
113
114 typed.type = pi->type;
115 code = param_read_requested_typed(plist, key, &typed);
116 switch (code) {
117 default: /* < 0 */
118 ecode = code;
119 case 1:
120 break;
121 case 0:
122 if (typed.type != pi->type) /* shouldn't happen! */
123 ecode = gs_note_error(gs_error_typecheck);
124 else
125 memcpy(pvalue, &typed.value, xfer_item_sizes[pi->type]);
126 }
127 }
128 return ecode;
129 }
130 int
gs_param_write_items(gs_param_list * plist,const void * obj,const void * default_obj,const gs_param_item_t * items)131 gs_param_write_items(gs_param_list * plist, const void *obj,
132 const void *default_obj, const gs_param_item_t * items)
133 {
134 const gs_param_item_t *pi;
135 int ecode = 0;
136
137 for (pi = items; pi->key != 0; ++pi) {
138 const char *key = pi->key;
139 const void *pvalue = (const void *)((const char *)obj + pi->offset);
140 int size = xfer_item_sizes[pi->type];
141 gs_param_typed_value typed;
142 int code;
143
144 if (default_obj != 0 &&
145 !memcmp((const void *)((const char *)default_obj + pi->offset),
146 pvalue, size)
147 )
148 continue;
149 memcpy(&typed.value, pvalue, size);
150 typed.type = pi->type;
151 code = (*plist->procs->xmit_typed) (plist, key, &typed);
152 if (code < 0)
153 ecode = code;
154 }
155 return ecode;
156 }
157
158 /* Read a value, with coercion if requested, needed, and possible. */
159 /* If mem != 0, we can coerce int arrays to float arrays. */
160 int
param_coerce_typed(gs_param_typed_value * pvalue,gs_param_type req_type,gs_memory_t * mem)161 param_coerce_typed(gs_param_typed_value * pvalue, gs_param_type req_type,
162 gs_memory_t * mem)
163 {
164 if (req_type == gs_param_type_any || pvalue->type == req_type)
165 return 0;
166 /*
167 * Look for coercion opportunities. It would be wonderful if we
168 * could convert int/float arrays and name/string arrays, but
169 * right now we can't. However, a 0-length heterogenous array
170 * will satisfy a request for any specific type.
171 */
172 switch (pvalue->type /* actual type */ ) {
173 case gs_param_type_int:
174 switch (req_type) {
175 case gs_param_type_long:
176 pvalue->value.l = pvalue->value.i;
177 goto ok;
178 case gs_param_type_float:
179 pvalue->value.f = (float)pvalue->value.l;
180 goto ok;
181 default:
182 break;
183 }
184 break;
185 case gs_param_type_long:
186 switch (req_type) {
187 case gs_param_type_int:
188 #if arch_sizeof_int < arch_sizeof_long
189 if (pvalue->value.l != (int)pvalue->value.l)
190 return_error(gs_error_rangecheck);
191 #endif
192 pvalue->value.i = (int)pvalue->value.l;
193 goto ok;
194 case gs_param_type_float:
195 pvalue->value.f = (float)pvalue->value.l;
196 goto ok;
197 default:
198 break;
199 }
200 break;
201 case gs_param_type_string:
202 if (req_type == gs_param_type_name)
203 goto ok;
204 break;
205 case gs_param_type_name:
206 if (req_type == gs_param_type_string)
207 goto ok;
208 break;
209 case gs_param_type_int_array:
210 switch (req_type) {
211 case gs_param_type_float_array:{
212 uint size = pvalue->value.ia.size;
213 float *fv;
214 uint i;
215
216 if (mem == 0)
217 break;
218 fv = (float *)gs_alloc_byte_array(mem, size, sizeof(float),
219 "int array => float array");
220
221 if (fv == 0)
222 return_error(gs_error_VMerror);
223 for (i = 0; i < size; ++i)
224 fv[i] = (float)pvalue->value.ia.data[i];
225 pvalue->value.fa.data = fv;
226 pvalue->value.fa.persistent = false;
227 goto ok;
228 }
229 default:
230 break;
231 }
232 break;
233 case gs_param_type_string_array:
234 if (req_type == gs_param_type_name_array)
235 goto ok;
236 break;
237 case gs_param_type_name_array:
238 if (req_type == gs_param_type_string_array)
239 goto ok;
240 break;
241 case gs_param_type_array:
242 if (pvalue->value.d.size == 0 &&
243 (req_type == gs_param_type_int_array ||
244 req_type == gs_param_type_float_array ||
245 req_type == gs_param_type_string_array ||
246 req_type == gs_param_type_name_array)
247 )
248 goto ok;
249 break;
250 default:
251 break;
252 }
253 return_error(gs_error_typecheck);
254 ok:pvalue->type = req_type;
255 return 0;
256 }
257 int
param_read_requested_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)258 param_read_requested_typed(gs_param_list * plist, gs_param_name pkey,
259 gs_param_typed_value * pvalue)
260 {
261 gs_param_type req_type = pvalue->type;
262 int code = (*plist->procs->xmit_typed) (plist, pkey, pvalue);
263
264 if (code != 0)
265 return code;
266 return param_coerce_typed(pvalue, req_type, plist->memory);
267 }
268
269
270 /* ---------------- Fixed-type reading procedures ---------------- */
271
272 #define RETURN_READ_TYPED(alt, ptype)\
273 gs_param_typed_value typed;\
274 int code;\
275 \
276 typed.type = ptype;\
277 code = param_read_requested_typed(plist, pkey, &typed);\
278 if ( code == 0 )\
279 *pvalue = typed.value.alt;\
280 return code
281
282 int
param_read_null(gs_param_list * plist,gs_param_name pkey)283 param_read_null(gs_param_list * plist, gs_param_name pkey)
284 {
285 gs_param_typed_value typed;
286
287 typed.type = gs_param_type_null;
288 return param_read_requested_typed(plist, pkey, &typed);
289 }
290 int
param_read_bool(gs_param_list * plist,gs_param_name pkey,bool * pvalue)291 param_read_bool(gs_param_list * plist, gs_param_name pkey, bool * pvalue)
292 {
293 RETURN_READ_TYPED(b, gs_param_type_bool);
294 }
295 int
param_read_int(gs_param_list * plist,gs_param_name pkey,int * pvalue)296 param_read_int(gs_param_list * plist, gs_param_name pkey, int *pvalue)
297 {
298 RETURN_READ_TYPED(i, gs_param_type_int);
299 }
300 int
param_read_long(gs_param_list * plist,gs_param_name pkey,long * pvalue)301 param_read_long(gs_param_list * plist, gs_param_name pkey, long *pvalue)
302 {
303 RETURN_READ_TYPED(l, gs_param_type_long);
304 }
305 int
param_read_float(gs_param_list * plist,gs_param_name pkey,float * pvalue)306 param_read_float(gs_param_list * plist, gs_param_name pkey, float *pvalue)
307 {
308 RETURN_READ_TYPED(f, gs_param_type_float);
309 }
310 int
param_read_string(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)311 param_read_string(gs_param_list * plist, gs_param_name pkey,
312 gs_param_string * pvalue)
313 {
314 RETURN_READ_TYPED(s, gs_param_type_string);
315 }
316 int
param_read_name(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)317 param_read_name(gs_param_list * plist, gs_param_name pkey,
318 gs_param_string * pvalue)
319 {
320 RETURN_READ_TYPED(n, gs_param_type_string);
321 }
322 int
param_read_int_array(gs_param_list * plist,gs_param_name pkey,gs_param_int_array * pvalue)323 param_read_int_array(gs_param_list * plist, gs_param_name pkey,
324 gs_param_int_array * pvalue)
325 {
326 RETURN_READ_TYPED(ia, gs_param_type_int_array);
327 }
328 int
param_read_float_array(gs_param_list * plist,gs_param_name pkey,gs_param_float_array * pvalue)329 param_read_float_array(gs_param_list * plist, gs_param_name pkey,
330 gs_param_float_array * pvalue)
331 {
332 RETURN_READ_TYPED(fa, gs_param_type_float_array);
333 }
334 int
param_read_string_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)335 param_read_string_array(gs_param_list * plist, gs_param_name pkey,
336 gs_param_string_array * pvalue)
337 {
338 RETURN_READ_TYPED(sa, gs_param_type_string_array);
339 }
340 int
param_read_name_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)341 param_read_name_array(gs_param_list * plist, gs_param_name pkey,
342 gs_param_string_array * pvalue)
343 {
344 RETURN_READ_TYPED(na, gs_param_type_name_array);
345 }
346
347 #undef RETURN_READ_TYPED
348
349 /* ---------------- Default writing procedures ---------------- */
350
351 #define RETURN_WRITE_TYPED(alt, ptype)\
352 gs_param_typed_value typed;\
353 \
354 typed.value.alt = *pvalue;\
355 typed.type = ptype;\
356 return param_write_typed(plist, pkey, &typed)
357
358 int
param_write_null(gs_param_list * plist,gs_param_name pkey)359 param_write_null(gs_param_list * plist, gs_param_name pkey)
360 {
361 gs_param_typed_value typed;
362
363 typed.type = gs_param_type_null;
364 return param_write_typed(plist, pkey, &typed);
365 }
366 int
param_write_bool(gs_param_list * plist,gs_param_name pkey,const bool * pvalue)367 param_write_bool(gs_param_list * plist, gs_param_name pkey, const bool * pvalue)
368 {
369 RETURN_WRITE_TYPED(b, gs_param_type_bool);
370 }
371 int
param_write_int(gs_param_list * plist,gs_param_name pkey,const int * pvalue)372 param_write_int(gs_param_list * plist, gs_param_name pkey, const int *pvalue)
373 {
374 RETURN_WRITE_TYPED(i, gs_param_type_int);
375 }
376 int
param_write_long(gs_param_list * plist,gs_param_name pkey,const long * pvalue)377 param_write_long(gs_param_list * plist, gs_param_name pkey, const long *pvalue)
378 {
379 RETURN_WRITE_TYPED(l, gs_param_type_long);
380 }
381 int
param_write_float(gs_param_list * plist,gs_param_name pkey,const float * pvalue)382 param_write_float(gs_param_list * plist, gs_param_name pkey,
383 const float *pvalue)
384 {
385 RETURN_WRITE_TYPED(f, gs_param_type_float);
386 }
387 int
param_write_string(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)388 param_write_string(gs_param_list * plist, gs_param_name pkey,
389 const gs_param_string * pvalue)
390 {
391 RETURN_WRITE_TYPED(s, gs_param_type_string);
392 }
393 int
param_write_name(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)394 param_write_name(gs_param_list * plist, gs_param_name pkey,
395 const gs_param_string * pvalue)
396 {
397 RETURN_WRITE_TYPED(n, gs_param_type_name);
398 }
399 int
param_write_int_array(gs_param_list * plist,gs_param_name pkey,const gs_param_int_array * pvalue)400 param_write_int_array(gs_param_list * plist, gs_param_name pkey,
401 const gs_param_int_array * pvalue)
402 {
403 RETURN_WRITE_TYPED(ia, gs_param_type_int_array);
404 }
405 int
param_write_int_values(gs_param_list * plist,gs_param_name pkey,const int * values,uint size,bool persistent)406 param_write_int_values(gs_param_list * plist, gs_param_name pkey,
407 const int *values, uint size, bool persistent)
408 {
409 gs_param_int_array ia;
410
411 ia.data = values, ia.size = size, ia.persistent = persistent;
412 return param_write_int_array(plist, pkey, &ia);
413 }
414 int
param_write_float_array(gs_param_list * plist,gs_param_name pkey,const gs_param_float_array * pvalue)415 param_write_float_array(gs_param_list * plist, gs_param_name pkey,
416 const gs_param_float_array * pvalue)
417 {
418 RETURN_WRITE_TYPED(fa, gs_param_type_float_array);
419 }
420 int
param_write_float_values(gs_param_list * plist,gs_param_name pkey,const float * values,uint size,bool persistent)421 param_write_float_values(gs_param_list * plist, gs_param_name pkey,
422 const float *values, uint size, bool persistent)
423 {
424 gs_param_float_array fa;
425
426 fa.data = values, fa.size = size, fa.persistent = persistent;
427 return param_write_float_array(plist, pkey, &fa);
428 }
429 int
param_write_string_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)430 param_write_string_array(gs_param_list * plist, gs_param_name pkey,
431 const gs_param_string_array * pvalue)
432 {
433 RETURN_WRITE_TYPED(sa, gs_param_type_string_array);
434 }
435 int
param_write_name_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)436 param_write_name_array(gs_param_list * plist, gs_param_name pkey,
437 const gs_param_string_array * pvalue)
438 {
439 RETURN_WRITE_TYPED(na, gs_param_type_name_array);
440 }
441
442 #undef RETURN_WRITE_TYPED
443
444 /* ---------------- Default request implementation ---------------- */
445
446 int
gs_param_request_default(gs_param_list * plist,gs_param_name pkey)447 gs_param_request_default(gs_param_list * plist, gs_param_name pkey)
448 {
449 return 0;
450 }
451
452 int
gs_param_requested_default(const gs_param_list * plist,gs_param_name pkey)453 gs_param_requested_default(const gs_param_list * plist, gs_param_name pkey)
454 {
455 return -1; /* requested by default */
456 }
457