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