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