1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, 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 /* Strictly speaking assigning one element of union
175 * to another, overlapping element of a different size is
176 * undefined behavior, hence assign to intermediate variables
177 */
178 switch (pvalue->type /* actual type */ ) {
179 case gs_param_type_int:
180 switch (req_type) {
181 case gs_param_type_long:
182 {
183 long l = (long)pvalue->value.i;
184 pvalue->value.l = l;
185 goto ok;
186 }
187 case gs_param_type_float:
188 {
189 float fl = (float)pvalue->value.l;
190 pvalue->value.f = fl;
191 goto ok;
192 }
193 default:
194 break;
195 }
196 break;
197 case gs_param_type_long:
198 switch (req_type) {
199 case gs_param_type_int:
200 {
201 int int1;
202 #if ARCH_SIZEOF_INT < ARCH_SIZEOF_LONG
203 if (pvalue->value.l != (int)pvalue->value.l)
204 return_error(gs_error_rangecheck);
205 #endif
206 int1 = (int)pvalue->value.l;
207 pvalue->value.i = int1;
208 goto ok;
209 }
210 case gs_param_type_float:
211 {
212 float fl = (float)pvalue->value.l;
213 pvalue->value.f = fl;
214 goto ok;
215 }
216 default:
217 break;
218 }
219 break;
220 case gs_param_type_string:
221 if (req_type == gs_param_type_name)
222 goto ok;
223 break;
224 case gs_param_type_name:
225 if (req_type == gs_param_type_string)
226 goto ok;
227 break;
228 case gs_param_type_int_array:
229 switch (req_type) {
230 case gs_param_type_float_array:{
231 uint size = pvalue->value.ia.size;
232 float *fv;
233 uint i;
234
235 if (mem == 0)
236 break;
237 fv = (float *)gs_alloc_byte_array(mem, size, sizeof(float),
238 "int array => float array");
239
240 if (fv == 0)
241 return_error(gs_error_VMerror);
242 for (i = 0; i < size; ++i)
243 fv[i] = (float)pvalue->value.ia.data[i];
244 pvalue->value.fa.data = fv;
245 pvalue->value.fa.persistent = false;
246 goto ok;
247 }
248 default:
249 break;
250 }
251 break;
252 case gs_param_type_string_array:
253 if (req_type == gs_param_type_name_array)
254 goto ok;
255 break;
256 case gs_param_type_name_array:
257 if (req_type == gs_param_type_string_array)
258 goto ok;
259 break;
260 case gs_param_type_array:
261 if (pvalue->value.d.size == 0 &&
262 (req_type == gs_param_type_int_array ||
263 req_type == gs_param_type_float_array ||
264 req_type == gs_param_type_string_array ||
265 req_type == gs_param_type_name_array)
266 )
267 goto ok;
268 break;
269 default:
270 break;
271 }
272 return_error(gs_error_typecheck);
273 ok:pvalue->type = req_type;
274 return 0;
275 }
276 int
param_read_requested_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)277 param_read_requested_typed(gs_param_list * plist, gs_param_name pkey,
278 gs_param_typed_value * pvalue)
279 {
280 gs_param_type req_type = pvalue->type;
281 int code = (*plist->procs->xmit_typed) (plist, pkey, pvalue);
282
283 if (code != 0)
284 return code;
285 return param_coerce_typed(pvalue, req_type, plist->memory);
286 }
287
288 /* ---------------- Fixed-type reading procedures ---------------- */
289
290 #define RETURN_READ_TYPED(alt, ptype)\
291 gs_param_typed_value typed;\
292 int code;\
293 \
294 typed.type = ptype;\
295 code = param_read_requested_typed(plist, pkey, &typed);\
296 if ( code == 0 )\
297 *pvalue = typed.value.alt;\
298 return code
299
300 int
param_read_null(gs_param_list * plist,gs_param_name pkey)301 param_read_null(gs_param_list * plist, gs_param_name pkey)
302 {
303 gs_param_typed_value typed;
304
305 typed.type = gs_param_type_null;
306 return param_read_requested_typed(plist, pkey, &typed);
307 }
308 int
param_read_bool(gs_param_list * plist,gs_param_name pkey,bool * pvalue)309 param_read_bool(gs_param_list * plist, gs_param_name pkey, bool * pvalue)
310 {
311 RETURN_READ_TYPED(b, gs_param_type_bool);
312 }
313 int
param_read_int(gs_param_list * plist,gs_param_name pkey,int * pvalue)314 param_read_int(gs_param_list * plist, gs_param_name pkey, int *pvalue)
315 {
316 RETURN_READ_TYPED(i, gs_param_type_int);
317 }
318 int
param_read_long(gs_param_list * plist,gs_param_name pkey,long * pvalue)319 param_read_long(gs_param_list * plist, gs_param_name pkey, long *pvalue)
320 {
321 RETURN_READ_TYPED(l, gs_param_type_long);
322 }
323 int
param_read_float(gs_param_list * plist,gs_param_name pkey,float * pvalue)324 param_read_float(gs_param_list * plist, gs_param_name pkey, float *pvalue)
325 {
326 RETURN_READ_TYPED(f, gs_param_type_float);
327 }
328 int
param_read_string(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)329 param_read_string(gs_param_list * plist, gs_param_name pkey,
330 gs_param_string * pvalue)
331 {
332 RETURN_READ_TYPED(s, gs_param_type_string);
333 }
334 int
param_read_name(gs_param_list * plist,gs_param_name pkey,gs_param_string * pvalue)335 param_read_name(gs_param_list * plist, gs_param_name pkey,
336 gs_param_string * pvalue)
337 {
338 RETURN_READ_TYPED(n, gs_param_type_string);
339 }
340 int
param_read_int_array(gs_param_list * plist,gs_param_name pkey,gs_param_int_array * pvalue)341 param_read_int_array(gs_param_list * plist, gs_param_name pkey,
342 gs_param_int_array * pvalue)
343 {
344 RETURN_READ_TYPED(ia, gs_param_type_int_array);
345 }
346 int
param_read_float_array(gs_param_list * plist,gs_param_name pkey,gs_param_float_array * pvalue)347 param_read_float_array(gs_param_list * plist, gs_param_name pkey,
348 gs_param_float_array * pvalue)
349 {
350 RETURN_READ_TYPED(fa, gs_param_type_float_array);
351 }
352 int
param_read_string_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)353 param_read_string_array(gs_param_list * plist, gs_param_name pkey,
354 gs_param_string_array * pvalue)
355 {
356 RETURN_READ_TYPED(sa, gs_param_type_string_array);
357 }
358 int
param_read_name_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)359 param_read_name_array(gs_param_list * plist, gs_param_name pkey,
360 gs_param_string_array * pvalue)
361 {
362 RETURN_READ_TYPED(na, gs_param_type_name_array);
363 }
364
365 #undef RETURN_READ_TYPED
366
367 /* ---------------- Default writing procedures ---------------- */
368
369 #define RETURN_WRITE_TYPED(alt, ptype)\
370 gs_param_typed_value typed;\
371 \
372 typed.value.alt = *pvalue;\
373 typed.type = ptype;\
374 return param_write_typed(plist, pkey, &typed)
375
376 int
param_write_null(gs_param_list * plist,gs_param_name pkey)377 param_write_null(gs_param_list * plist, gs_param_name pkey)
378 {
379 gs_param_typed_value typed;
380
381 typed.type = gs_param_type_null;
382 return param_write_typed(plist, pkey, &typed);
383 }
384 int
param_write_bool(gs_param_list * plist,gs_param_name pkey,const bool * pvalue)385 param_write_bool(gs_param_list * plist, gs_param_name pkey, const bool * pvalue)
386 {
387 RETURN_WRITE_TYPED(b, gs_param_type_bool);
388 }
389 int
param_write_int(gs_param_list * plist,gs_param_name pkey,const int * pvalue)390 param_write_int(gs_param_list * plist, gs_param_name pkey, const int *pvalue)
391 {
392 RETURN_WRITE_TYPED(i, gs_param_type_int);
393 }
394 int
param_write_long(gs_param_list * plist,gs_param_name pkey,const long * pvalue)395 param_write_long(gs_param_list * plist, gs_param_name pkey, const long *pvalue)
396 {
397 RETURN_WRITE_TYPED(l, gs_param_type_long);
398 }
399 int
param_write_float(gs_param_list * plist,gs_param_name pkey,const float * pvalue)400 param_write_float(gs_param_list * plist, gs_param_name pkey,
401 const float *pvalue)
402 {
403 RETURN_WRITE_TYPED(f, gs_param_type_float);
404 }
405 int
param_write_string(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)406 param_write_string(gs_param_list * plist, gs_param_name pkey,
407 const gs_param_string * pvalue)
408 {
409 RETURN_WRITE_TYPED(s, gs_param_type_string);
410 }
411 int
param_write_name(gs_param_list * plist,gs_param_name pkey,const gs_param_string * pvalue)412 param_write_name(gs_param_list * plist, gs_param_name pkey,
413 const gs_param_string * pvalue)
414 {
415 RETURN_WRITE_TYPED(n, gs_param_type_name);
416 }
417 int
param_write_int_array(gs_param_list * plist,gs_param_name pkey,const gs_param_int_array * pvalue)418 param_write_int_array(gs_param_list * plist, gs_param_name pkey,
419 const gs_param_int_array * pvalue)
420 {
421 RETURN_WRITE_TYPED(ia, gs_param_type_int_array);
422 }
423 int
param_write_int_values(gs_param_list * plist,gs_param_name pkey,const int * values,uint size,bool persistent)424 param_write_int_values(gs_param_list * plist, gs_param_name pkey,
425 const int *values, uint size, bool persistent)
426 {
427 gs_param_int_array ia;
428
429 ia.data = values, ia.size = size, ia.persistent = persistent;
430 return param_write_int_array(plist, pkey, &ia);
431 }
432 int
param_write_float_array(gs_param_list * plist,gs_param_name pkey,const gs_param_float_array * pvalue)433 param_write_float_array(gs_param_list * plist, gs_param_name pkey,
434 const gs_param_float_array * pvalue)
435 {
436 RETURN_WRITE_TYPED(fa, gs_param_type_float_array);
437 }
438 int
param_write_float_values(gs_param_list * plist,gs_param_name pkey,const float * values,uint size,bool persistent)439 param_write_float_values(gs_param_list * plist, gs_param_name pkey,
440 const float *values, uint size, bool persistent)
441 {
442 gs_param_float_array fa;
443
444 fa.data = values, fa.size = size, fa.persistent = persistent;
445 return param_write_float_array(plist, pkey, &fa);
446 }
447 int
param_write_string_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)448 param_write_string_array(gs_param_list * plist, gs_param_name pkey,
449 const gs_param_string_array * pvalue)
450 {
451 RETURN_WRITE_TYPED(sa, gs_param_type_string_array);
452 }
453 int
param_write_name_array(gs_param_list * plist,gs_param_name pkey,const gs_param_string_array * pvalue)454 param_write_name_array(gs_param_list * plist, gs_param_name pkey,
455 const gs_param_string_array * pvalue)
456 {
457 RETURN_WRITE_TYPED(na, gs_param_type_name_array);
458 }
459
460 #undef RETURN_WRITE_TYPED
461
462 /* ---------------- Default request implementation ---------------- */
463
464 int
gs_param_request_default(gs_param_list * plist,gs_param_name pkey)465 gs_param_request_default(gs_param_list * plist, gs_param_name pkey)
466 {
467 return 0;
468 }
469
470 int
gs_param_requested_default(const gs_param_list * plist,gs_param_name pkey)471 gs_param_requested_default(const gs_param_list * plist, gs_param_name pkey)
472 {
473 return -1; /* requested by default */
474 }
475