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