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