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