1 /* Copyright (C) 1993, 2000 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: iparam.c,v 1.10 2004/08/04 19:36:13 stefan Exp $ */
18 /* Interpreter implementations of parameter dictionaries */
19 #include "memory_.h"
20 #include "string_.h"
21 #include "ghost.h"
22 #include "ierrors.h"
23 #include "oper.h" /* for check_type */
24 #include "opcheck.h"
25 #include "ialloc.h"
26 #include "idict.h"
27 #include "imemory.h" /* for iutil.h */
28 #include "iname.h"
29 #include "istack.h"
30 #include "iparam.h"
31 #include "iutil.h" /* for num_params */
32 #include "ivmspace.h"
33 #include "store.h"
34
35 /* ================ Utilities ================ */
36
37 /* Convert a key to a ref. */
38 private int
ref_param_key(const iparam_list * plist,gs_param_name pkey,ref * pkref)39 ref_param_key(const iparam_list * plist, gs_param_name pkey, ref * pkref)
40 {
41 if (plist->int_keys) {
42 long key;
43
44 if (sscanf(pkey, "%ld", &key) != 1)
45 return_error(e_rangecheck);
46 make_int(pkref, key);
47 return 0;
48 } else
49 return name_ref(plist->memory, (const byte *)pkey, strlen(pkey), pkref, 0);
50 }
51
52 /* Fill in a gs_param_key_t from a name or int ref. */
53 private int
ref_to_key(const ref * pref,gs_param_key_t * key,iparam_list * plist)54 ref_to_key(const ref * pref, gs_param_key_t * key, iparam_list *plist)
55 {
56 if (r_has_type(pref, t_name)) {
57 ref nref;
58
59 name_string_ref(plist->memory, pref, &nref);
60 key->data = nref.value.const_bytes;
61 key->size = r_size(&nref);
62 key->persistent = false; /* names may be freed */
63 } else if (r_has_type(pref, t_integer)) {
64 char istr[sizeof(long) * 8 / 3 + 2];
65 int len;
66 byte *buf;
67
68 sprintf(istr, "%ld", pref->value.intval);
69 len = strlen(istr);
70 /* GC will take care of freeing this: */
71 buf = gs_alloc_string(plist->memory, len, "ref_to_key");
72 if (!buf)
73 return_error(e_VMerror);
74 key->data = buf;
75 key->size = len;
76 key->persistent = true;
77 } else
78 return_error(e_typecheck);
79 return 0;
80 }
81
82 /* ================ Writing parameters to refs ================ */
83
84 /* Forward references */
85 private int array_new_indexed_plist_write(dict_param_list *plist,
86 ref *parray, const ref *pwanted,
87 gs_ref_memory_t *imem);
88
89 /* ---------------- Generic writing procedures ---------------- */
90
91 private param_proc_begin_xmit_collection(ref_param_begin_write_collection);
92 private param_proc_end_xmit_collection(ref_param_end_write_collection);
93 private param_proc_xmit_typed(ref_param_write_typed);
94 private param_proc_next_key(ref_param_get_next_key);
95 private param_proc_requested(ref_param_requested);
96 private const gs_param_list_procs ref_write_procs =
97 {
98 ref_param_write_typed,
99 ref_param_begin_write_collection,
100 ref_param_end_write_collection,
101 ref_param_get_next_key,
102 NULL, /* request */
103 ref_param_requested
104 };
105 private int ref_array_param_requested(const iparam_list *, gs_param_name,
106 ref *, uint, client_name_t);
107 private int ref_param_write(iparam_list *, gs_param_name, const ref *);
108 private int ref_param_write_string_value(ref *, const gs_param_string *,
109 gs_ref_memory_t *);
110 private int ref_param_write_name_value(const gs_memory_t *mem, ref *, const gs_param_string *);
111 private int
ref_param_make_int(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)112 ref_param_make_int(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
113 {
114 make_tav(pe, t_integer, imemory_new_mask(imem), intval,
115 ((const gs_param_int_array *)pvalue)->data[i]);
116 return 0;
117 }
118 private int
ref_param_make_float(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)119 ref_param_make_float(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
120 {
121 make_tav(pe, t_real, imemory_new_mask(imem), realval,
122 ((const gs_param_float_array *)pvalue)->data[i]);
123 return 0;
124 }
125 private int
ref_param_make_string(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)126 ref_param_make_string(ref *pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
127 {
128 return ref_param_write_string_value(pe,
129 &((const gs_param_string_array *)pvalue)->data[i],
130 imem);
131 }
132 private int
ref_param_make_name(ref * pe,const void * pvalue,uint i,gs_ref_memory_t * imem)133 ref_param_make_name(ref * pe, const void *pvalue, uint i, gs_ref_memory_t *imem)
134 {
135 return ref_param_write_name_value((const gs_memory_t *)imem, pe,
136 &((const gs_param_string_array *)pvalue)->data[i]);
137 }
138 private int
ref_param_write_typed_array(gs_param_list * plist,gs_param_name pkey,void * pvalue,uint count,int (* make)(ref *,const void *,uint,gs_ref_memory_t *))139 ref_param_write_typed_array(gs_param_list * plist, gs_param_name pkey,
140 void *pvalue, uint count,
141 int (*make)(ref *, const void *, uint,
142 gs_ref_memory_t *))
143 {
144 iparam_list *const iplist = (iparam_list *) plist;
145 ref value;
146 uint i;
147 ref *pe;
148 int code;
149
150 if ((code = ref_array_param_requested(iplist, pkey, &value, count,
151 "ref_param_write_typed_array")) <= 0)
152 return code;
153 for (i = 0, pe = value.value.refs; i < count; ++i, ++pe)
154 if ((code = (*make) (pe, pvalue, i, iplist->ref_memory)) < 0)
155 return code;
156 return ref_param_write(iplist, pkey, &value);
157 }
158 private int
ref_param_begin_write_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue,gs_param_collection_type_t coll_type)159 ref_param_begin_write_collection(gs_param_list * plist, gs_param_name pkey,
160 gs_param_dict * pvalue,
161 gs_param_collection_type_t coll_type)
162 {
163 iparam_list *const iplist = (iparam_list *) plist;
164 gs_ref_memory_t *imem = iplist->ref_memory;
165 dict_param_list *dlist = (dict_param_list *)
166 gs_alloc_bytes(plist->memory, size_of(dict_param_list),
167 "ref_param_begin_write_collection");
168 int code;
169
170 if (dlist == 0)
171 return_error(e_VMerror);
172 if (coll_type != gs_param_collection_array) {
173 ref dref;
174
175 code = dict_alloc(imem, pvalue->size, &dref);
176 if (code >= 0) {
177 code = dict_param_list_write(dlist, &dref, NULL, imem);
178 dlist->int_keys = coll_type == gs_param_collection_dict_int_keys;
179 }
180 } else {
181 ref aref;
182
183 code = gs_alloc_ref_array(imem, &aref, a_all, pvalue->size,
184 "ref_param_begin_write_collection");
185 if (code >= 0)
186 code = array_new_indexed_plist_write(dlist, &aref, NULL, imem);
187 }
188 if (code < 0)
189 gs_free_object(plist->memory, dlist, "ref_param_begin_write_collection");
190 else
191 pvalue->list = (gs_param_list *) dlist;
192 return code;
193 }
194 private int
ref_param_end_write_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue)195 ref_param_end_write_collection(gs_param_list * plist, gs_param_name pkey,
196 gs_param_dict * pvalue)
197 {
198 iparam_list *const iplist = (iparam_list *) plist;
199 int code = ref_param_write(iplist, pkey,
200 &((dict_param_list *) pvalue->list)->dict);
201
202 gs_free_object(plist->memory, pvalue->list, "ref_param_end_write_collection");
203 return code;
204 }
205 private int
ref_param_write_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)206 ref_param_write_typed(gs_param_list * plist, gs_param_name pkey,
207 gs_param_typed_value * pvalue)
208 {
209 iparam_list *const iplist = (iparam_list *) plist;
210 ref value;
211 int code = 0;
212
213 switch (pvalue->type) {
214 case gs_param_type_null:
215 make_null(&value);
216 break;
217 case gs_param_type_bool:
218 make_bool(&value, pvalue->value.b);
219 break;
220 case gs_param_type_int:
221 make_int(&value, pvalue->value.i);
222 break;
223 case gs_param_type_long:
224 make_int(&value, pvalue->value.l);
225 break;
226 case gs_param_type_float:
227 make_real(&value, pvalue->value.f);
228 break;
229 case gs_param_type_string:
230 if (!ref_param_requested(plist, pkey))
231 return 0;
232 code = ref_param_write_string_value(&value, &pvalue->value.s,
233 iplist->ref_memory);
234 break;
235 case gs_param_type_name:
236 if (!ref_param_requested(plist, pkey))
237 return 0;
238 code = ref_param_write_name_value(iplist->memory, &value, &pvalue->value.n);
239 break;
240 case gs_param_type_int_array:
241 return ref_param_write_typed_array(plist, pkey, &pvalue->value.ia,
242 pvalue->value.ia.size,
243 ref_param_make_int);
244 case gs_param_type_float_array:
245 return ref_param_write_typed_array(plist, pkey, &pvalue->value.fa,
246 pvalue->value.fa.size,
247 ref_param_make_float);
248 case gs_param_type_string_array:
249 return ref_param_write_typed_array(plist, pkey, &pvalue->value.sa,
250 pvalue->value.sa.size,
251 ref_param_make_string);
252 case gs_param_type_name_array:
253 return ref_param_write_typed_array(plist, pkey, &pvalue->value.na,
254 pvalue->value.na.size,
255 ref_param_make_name);
256 case gs_param_type_dict:
257 case gs_param_type_dict_int_keys:
258 case gs_param_type_array:
259 return ref_param_begin_write_collection(plist, pkey,
260 &pvalue->value.d,
261 (gs_param_collection_type_t)(pvalue->type - gs_param_type_dict));
262 default:
263 return_error(e_typecheck);
264 }
265 if (code < 0)
266 return code;
267 return ref_param_write(iplist, pkey, &value);
268 }
269
270 /* Check whether a given parameter was requested. */
271 private int
ref_param_requested(const gs_param_list * plist,gs_param_name pkey)272 ref_param_requested(const gs_param_list * plist, gs_param_name pkey)
273 {
274 const iparam_list *const ciplist = (const iparam_list *)plist;
275 ref kref;
276 ref *ignore_value;
277
278 if (!r_has_type(&ciplist->u.w.wanted, t_dictionary))
279 return -1;
280 if (ref_param_key(ciplist, pkey, &kref) < 0)
281 return -1; /* catch it later */
282 return (dict_find(&ciplist->u.w.wanted, &kref, &ignore_value) > 0);
283 }
284
285 /* Check whether an array parameter is wanted, and allocate it if so. */
286 /* Return <0 on error, 0 if not wanted, 1 if wanted. */
287 private int
ref_array_param_requested(const iparam_list * iplist,gs_param_name pkey,ref * pvalue,uint size,client_name_t cname)288 ref_array_param_requested(const iparam_list *iplist, gs_param_name pkey,
289 ref *pvalue, uint size, client_name_t cname)
290 {
291 int code;
292
293 if (!ref_param_requested((const gs_param_list *)iplist, pkey))
294 return 0;
295 code = gs_alloc_ref_array(iplist->ref_memory, pvalue, a_all, size, cname);
296 return (code < 0 ? code : 1);
297 }
298
299 /* ---------------- Internal routines ---------------- */
300
301 /* Prepare to write a string value. */
302 private int
ref_param_write_string_value(ref * pref,const gs_param_string * pvalue,gs_ref_memory_t * imem)303 ref_param_write_string_value(ref * pref, const gs_param_string * pvalue,
304 gs_ref_memory_t *imem)
305 {
306 const byte *pdata = pvalue->data;
307 uint n = pvalue->size;
308
309 if (pvalue->persistent)
310 make_const_string(pref, a_readonly | avm_foreign, n, pdata);
311 else {
312 byte *pstr = gs_alloc_string((gs_memory_t *)imem, n,
313 "ref_param_write_string");
314
315 if (pstr == 0)
316 return_error(e_VMerror);
317 memcpy(pstr, pdata, n);
318 make_string(pref, a_readonly | imemory_space(imem), n, pstr);
319 }
320 return 0;
321 }
322
323 /* Prepare to write a name value. */
324 private int
ref_param_write_name_value(const gs_memory_t * mem,ref * pref,const gs_param_string * pvalue)325 ref_param_write_name_value(const gs_memory_t *mem, ref * pref, const gs_param_string * pvalue)
326 {
327 return name_ref(mem, pvalue->data, pvalue->size, pref,
328 (pvalue->persistent ? 0 : 1));
329 }
330
331 /* Generic routine for writing a ref parameter. */
332 private int
ref_param_write(iparam_list * plist,gs_param_name pkey,const ref * pvalue)333 ref_param_write(iparam_list * plist, gs_param_name pkey, const ref * pvalue)
334 {
335 ref kref;
336 int code;
337
338 if (!ref_param_requested((gs_param_list *) plist, pkey))
339 return 0;
340 code = ref_param_key(plist, pkey, &kref);
341 if (code < 0)
342 return code;
343 return (*plist->u.w.write) (plist, &kref, pvalue);
344 }
345
346 /* ---------------- Implementations ---------------- */
347
348 /* Initialize for writing parameters. */
349 private void
ref_param_write_init(iparam_list * plist,const ref * pwanted,gs_ref_memory_t * imem)350 ref_param_write_init(iparam_list * plist, const ref * pwanted,
351 gs_ref_memory_t *imem)
352 {
353 gs_param_list_init((gs_param_list *)plist, &ref_write_procs,
354 (gs_memory_t *)imem);
355 plist->ref_memory = imem;
356 if (pwanted == 0)
357 make_null(&plist->u.w.wanted);
358 else
359 plist->u.w.wanted = *pwanted;
360 plist->results = 0;
361 plist->int_keys = false;
362 }
363
364 /* Implementation for getting parameters to a stack. */
365 private int
stack_param_write(iparam_list * plist,const ref * pkey,const ref * pvalue)366 stack_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
367 {
368 stack_param_list *const splist = (stack_param_list *) plist;
369 ref_stack_t *pstack = splist->pstack;
370 s_ptr p = pstack->p;
371
372 if (pstack->top - p < 2) {
373 int code = ref_stack_push(pstack, 2);
374
375 if (code < 0)
376 return code;
377 *ref_stack_index(pstack, 1) = *pkey;
378 p = pstack->p;
379 } else {
380 pstack->p = p += 2;
381 p[-1] = *pkey;
382 }
383 *p = *pvalue;
384 splist->count++;
385 return 0;
386 }
387
388 /* Implementation for enumerating parameters on a stack */
389 private int /* ret 0 ok, 1 if EOF, or -ve err */
stack_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)390 stack_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
391 gs_param_key_t * key, ref_type * type)
392 {
393 int code;
394 stack_param_list *const splist = (stack_param_list *) plist;
395 long index = penum->intval;
396 ref *stack_element;
397
398 do {
399 stack_element =
400 ref_stack_index(splist->pstack, index + 1 + splist->skip);
401 if (!stack_element)
402 return 1;
403 } while (index += 2, !r_has_type(stack_element, t_name));
404 *type = r_type(stack_element);
405 code = ref_to_key(stack_element, key, plist);
406 penum->intval = index;
407 return code;
408 }
409
410 int
stack_param_list_write(stack_param_list * plist,ref_stack_t * pstack,const ref * pwanted,gs_ref_memory_t * imem)411 stack_param_list_write(stack_param_list * plist, ref_stack_t * pstack,
412 const ref * pwanted, gs_ref_memory_t *imem)
413 {
414 plist->u.w.write = stack_param_write;
415 ref_param_write_init((iparam_list *) plist, pwanted, imem);
416 plist->enumerate = stack_param_enumerate;
417 plist->pstack = pstack;
418 plist->skip = 0;
419 plist->count = 0;
420 return 0;
421 }
422
423 /* Implementation for getting parameters to a dictionary. */
424 private int
dict_param_write(iparam_list * plist,const ref * pkey,const ref * pvalue)425 dict_param_write(iparam_list * plist, const ref * pkey, const ref * pvalue)
426 {
427 int code =
428 dict_put(&((dict_param_list *) plist)->dict, pkey, pvalue, NULL);
429
430 return min(code, 0);
431 }
432
433 /* Implementation for enumerating parameters in a dictionary */
434 private int /* ret 0 ok, 1 if EOF, or -ve err */
dict_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)435 dict_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
436 gs_param_key_t * key, ref_type * type)
437 {
438 ref elt[2];
439 int code;
440 dict_param_list *const pdlist = (dict_param_list *) plist;
441 int index =
442 (penum->intval != 0 ? penum->intval : dict_first(&pdlist->dict));
443
444 index = dict_next(&pdlist->dict, index, elt);
445 if (index < 0)
446 return 1;
447 *type = r_type(&elt[1]);
448 code = ref_to_key(&elt[0], key, plist);
449 penum->intval = index;
450 return code;
451 }
452
453 int
dict_param_list_write(dict_param_list * plist,ref * pdict,const ref * pwanted,gs_ref_memory_t * imem)454 dict_param_list_write(dict_param_list *plist, ref *pdict, const ref *pwanted,
455 gs_ref_memory_t *imem)
456 {
457 check_dict_write(*pdict);
458 plist->u.w.write = dict_param_write;
459 plist->enumerate = dict_param_enumerate;
460 ref_param_write_init((iparam_list *) plist, pwanted, imem);
461 plist->dict = *pdict;
462 return 0;
463 }
464
465 /* Implementation for getting parameters to an indexed array. */
466 /* Note that this is now internal, since it only handles "new" arrays. */
467 private int
array_new_indexed_param_write(iparam_list * iplist,const ref * pkey,const ref * pvalue)468 array_new_indexed_param_write(iparam_list * iplist, const ref * pkey,
469 const ref * pvalue)
470 {
471 const ref *const arr = &((dict_param_list *)iplist)->dict;
472 ref *eltp;
473
474 if (!r_has_type(pkey, t_integer))
475 return_error(e_typecheck);
476 check_int_ltu(*pkey, r_size(arr));
477 store_check_dest(arr, pvalue);
478 eltp = arr->value.refs + pkey->value.intval;
479 /* ref_assign_new(eltp, pvalue); */
480 ref_assign(eltp, pvalue);
481 r_set_attrs(eltp, imemory_new_mask(iplist->ref_memory));
482 return 0;
483 }
484 private int
array_new_indexed_plist_write(dict_param_list * plist,ref * parray,const ref * pwanted,gs_ref_memory_t * imem)485 array_new_indexed_plist_write(dict_param_list * plist, ref * parray,
486 const ref * pwanted, gs_ref_memory_t *imem)
487 {
488 check_array(*parray);
489 check_write(*parray);
490 plist->u.w.write = array_new_indexed_param_write;
491 ref_param_write_init((iparam_list *) plist, pwanted, imem);
492 plist->dict = *parray;
493 plist->int_keys = true;
494 return 0;
495 }
496
497 /* ================ Reading refs to parameters ================ */
498
499 /* ---------------- Generic reading procedures ---------------- */
500
501 private param_proc_begin_xmit_collection(ref_param_begin_read_collection);
502 private param_proc_end_xmit_collection(ref_param_end_read_collection);
503 private param_proc_xmit_typed(ref_param_read_typed);
504
505 /*private param_proc_next_key(ref_param_get_next_key); already dec'ld above */
506 private param_proc_get_policy(ref_param_read_get_policy);
507 private param_proc_signal_error(ref_param_read_signal_error);
508 private param_proc_commit(ref_param_read_commit);
509 private const gs_param_list_procs ref_read_procs =
510 {
511 ref_param_read_typed,
512 ref_param_begin_read_collection,
513 ref_param_end_read_collection,
514 ref_param_get_next_key,
515 NULL, /* request */
516 NULL, /* requested */
517 ref_param_read_get_policy,
518 ref_param_read_signal_error,
519 ref_param_read_commit
520 };
521 private int ref_param_read(iparam_list *, gs_param_name,
522 iparam_loc *, int);
523 private int ref_param_read_string_value(const gs_memory_t *mem,
524 const iparam_loc *,
525 gs_param_string *);
526 private int ref_param_read_array(iparam_list *, gs_param_name,
527 iparam_loc *);
528
529 #define iparam_note_error(loc, code)\
530 gs_note_error(*(loc).presult = code)
531 #define iparam_check_type(loc, typ)\
532 if ( !r_has_type((loc).pvalue, typ) )\
533 return iparam_note_error(loc, e_typecheck)
534 #define iparam_check_read(loc)\
535 if ( !r_has_attr((loc).pvalue, a_read) )\
536 return iparam_note_error(loc, e_invalidaccess)
537
538 private int
ref_param_read_int_array(gs_param_list * plist,gs_param_name pkey,gs_param_int_array * pvalue)539 ref_param_read_int_array(gs_param_list * plist, gs_param_name pkey,
540 gs_param_int_array * pvalue)
541 {
542 iparam_list *const iplist = (iparam_list *) plist;
543 iparam_loc loc;
544 int code = ref_param_read_array(iplist, pkey, &loc);
545 int *piv;
546 uint size;
547 long i;
548
549 if (code != 0)
550 return code;
551 size = r_size(loc.pvalue);
552 piv = (int *)gs_alloc_byte_array(plist->memory, size, sizeof(int),
553 "ref_param_read_int_array");
554
555 if (piv == 0)
556 return_error(e_VMerror);
557 for (i = 0; i < size; i++) {
558 ref elt;
559
560 array_get(plist->memory, loc.pvalue, i, &elt);
561 if (!r_has_type(&elt, t_integer)) {
562 code = gs_note_error(e_typecheck);
563 break;
564 }
565 #if arch_sizeof_int < arch_sizeof_long
566 if (elt.value.intval != (int)elt.value.intval) {
567 code = gs_note_error(e_rangecheck);
568 break;
569 }
570 #endif
571 piv[i] = (int)elt.value.intval;
572 }
573 if (code < 0) {
574 gs_free_object(plist->memory, piv, "ref_param_read_int_array");
575 return (*loc.presult = code);
576 }
577 pvalue->data = piv;
578 pvalue->size = size;
579 pvalue->persistent = true;
580 return 0;
581 }
582 private int
ref_param_read_float_array(gs_param_list * plist,gs_param_name pkey,gs_param_float_array * pvalue)583 ref_param_read_float_array(gs_param_list * plist, gs_param_name pkey,
584 gs_param_float_array * pvalue)
585 {
586 iparam_list *const iplist = (iparam_list *) plist;
587 iparam_loc loc;
588 ref aref, elt;
589 int code = ref_param_read_array(iplist, pkey, &loc);
590 float *pfv;
591 uint size;
592 long i;
593
594 if (code != 0)
595 return code;
596 size = r_size(loc.pvalue);
597 pfv = (float *)gs_alloc_byte_array(plist->memory, size, sizeof(float),
598 "ref_param_read_float_array");
599
600 if (pfv == 0)
601 return_error(e_VMerror);
602 aref = *loc.pvalue;
603 loc.pvalue = &elt;
604 for (i = 0; code >= 0 && i < size; i++) {
605 array_get(plist->memory, &aref, i, &elt);
606 code = float_param(&elt, pfv + i);
607 }
608 if (code < 0) {
609 gs_free_object(plist->memory, pfv, "ref_read_float_array_param");
610 return (*loc.presult = code);
611 }
612 pvalue->data = pfv;
613 pvalue->size = size;
614 pvalue->persistent = true;
615 return 0;
616 }
617 private int
ref_param_read_string_array(gs_param_list * plist,gs_param_name pkey,gs_param_string_array * pvalue)618 ref_param_read_string_array(gs_param_list * plist, gs_param_name pkey,
619 gs_param_string_array * pvalue)
620 {
621 iparam_list *const iplist = (iparam_list *) plist;
622 iparam_loc loc;
623 ref aref;
624 int code = ref_param_read_array(iplist, pkey, &loc);
625 gs_param_string *psv;
626 uint size;
627 long i;
628
629 if (code != 0)
630 return code;
631 size = r_size(loc.pvalue);
632 psv = (gs_param_string *)
633 gs_alloc_byte_array(plist->memory, size, sizeof(gs_param_string),
634 "ref_param_read_string_array");
635 if (psv == 0)
636 return_error(e_VMerror);
637 aref = *loc.pvalue;
638 if (r_has_type(&aref, t_array)) {
639 for (i = 0; code >= 0 && i < size; i++) {
640 loc.pvalue = aref.value.refs + i;
641 code = ref_param_read_string_value(plist->memory, &loc, psv + i);
642 }
643 } else {
644 ref elt;
645
646 loc.pvalue = &elt;
647 for (i = 0; code >= 0 && i < size; i++) {
648 array_get(plist->memory, &aref, i, &elt);
649 code = ref_param_read_string_value(plist->memory, &loc, psv + i);
650 }
651 }
652 if (code < 0) {
653 gs_free_object(plist->memory, psv, "ref_param_read_string_array");
654 return (*loc.presult = code);
655 }
656 pvalue->data = psv;
657 pvalue->size = size;
658 pvalue->persistent = true;
659 return 0;
660 }
661 private int
ref_param_begin_read_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue,gs_param_collection_type_t coll_type)662 ref_param_begin_read_collection(gs_param_list * plist, gs_param_name pkey,
663 gs_param_dict * pvalue,
664 gs_param_collection_type_t coll_type)
665 {
666 iparam_list *const iplist = (iparam_list *) plist;
667 iparam_loc loc;
668 bool int_keys = coll_type != 0;
669 int code = ref_param_read(iplist, pkey, &loc, -1);
670 dict_param_list *dlist;
671
672 if (code != 0)
673 return code;
674 dlist = (dict_param_list *)
675 gs_alloc_bytes(plist->memory, size_of(dict_param_list),
676 "ref_param_begin_read_collection");
677 if (dlist == 0)
678 return_error(e_VMerror);
679 if (r_has_type(loc.pvalue, t_dictionary)) {
680 code = dict_param_list_read(dlist, loc.pvalue, NULL, false,
681 iplist->ref_memory);
682 dlist->int_keys = int_keys;
683 if (code >= 0)
684 pvalue->size = dict_length(loc.pvalue);
685 } else if (int_keys && r_is_array(loc.pvalue)) {
686 code = array_indexed_param_list_read(dlist, loc.pvalue, NULL, false,
687 iplist->ref_memory);
688 if (code >= 0)
689 pvalue->size = r_size(loc.pvalue);
690 } else
691 code = gs_note_error(e_typecheck);
692 if (code < 0) {
693 gs_free_object(plist->memory, dlist, "ref_param_begin_write_collection");
694 return iparam_note_error(loc, code);
695 }
696 pvalue->list = (gs_param_list *) dlist;
697 return 0;
698 }
699 private int
ref_param_end_read_collection(gs_param_list * plist,gs_param_name pkey,gs_param_dict * pvalue)700 ref_param_end_read_collection(gs_param_list * plist, gs_param_name pkey,
701 gs_param_dict * pvalue)
702 {
703 iparam_list_release((dict_param_list *) pvalue->list);
704 gs_free_object(plist->memory, pvalue->list,
705 "ref_param_end_read_collection");
706 return 0;
707 }
708 private int
ref_param_read_typed(gs_param_list * plist,gs_param_name pkey,gs_param_typed_value * pvalue)709 ref_param_read_typed(gs_param_list * plist, gs_param_name pkey,
710 gs_param_typed_value * pvalue)
711 {
712 iparam_list *const iplist = (iparam_list *) plist;
713 iparam_loc loc;
714 ref elt;
715 int code = ref_param_read(iplist, pkey, &loc, -1);
716
717 if (code != 0)
718 return code;
719 switch (r_type(loc.pvalue)) {
720 case t_array:
721 case t_mixedarray:
722 case t_shortarray:
723 iparam_check_read(loc);
724 if (r_size(loc.pvalue) <= 0) {
725 /* 0-length array; can't get type info */
726 pvalue->type = gs_param_type_array;
727 pvalue->value.d.list = 0;
728 pvalue->value.d.size = 0;
729 return 0;
730 }
731 /*
732 * We have to guess at the array type. First we guess based
733 * on the type of the first element of the array. If that
734 * fails, we try again with more general types.
735 */
736 array_get(plist->memory, loc.pvalue, 0, &elt);
737 switch (r_type(&elt)) {
738 case t_integer:
739 pvalue->type = gs_param_type_int_array;
740 code = ref_param_read_int_array(plist, pkey,
741 &pvalue->value.ia);
742 if (code != e_typecheck)
743 return code;
744 /* This might be a float array. Fall through. */
745 *loc.presult = 0; /* reset error */
746 case t_real:
747 pvalue->type = gs_param_type_float_array;
748 return ref_param_read_float_array(plist, pkey,
749 &pvalue->value.fa);
750 case t_string:
751 pvalue->type = gs_param_type_string_array;
752 return ref_param_read_string_array(plist, pkey,
753 &pvalue->value.sa);
754 case t_name:
755 pvalue->type = gs_param_type_name_array;
756 return ref_param_read_string_array(plist, pkey,
757 &pvalue->value.na);
758 default:
759 break;
760 }
761 return gs_note_error(e_typecheck);
762 case t_boolean:
763 pvalue->type = gs_param_type_bool;
764 pvalue->value.b = loc.pvalue->value.boolval;
765 return 0;
766 case t_dictionary:
767 code = ref_param_begin_read_collection(plist, pkey,
768 &pvalue->value.d, gs_param_collection_dict_any);
769 if (code < 0)
770 return code;
771 pvalue->type = gs_param_type_dict;
772
773 /* fixup new dict's type & int_keys field if contents have int keys */
774 {
775 gs_param_enumerator_t enumr;
776 gs_param_key_t key;
777 ref_type keytype;
778
779 param_init_enumerator(&enumr);
780 if (!(*((iparam_list *) plist)->enumerate)
781 ((iparam_list *) pvalue->value.d.list, &enumr, &key, &keytype)
782 && keytype == t_integer) {
783 ((dict_param_list *) pvalue->value.d.list)->int_keys = 1;
784 pvalue->type = gs_param_type_dict_int_keys;
785 }
786 }
787 return 0;
788 case t_integer:
789 pvalue->type = gs_param_type_long;
790 pvalue->value.l = loc.pvalue->value.intval;
791 return 0;
792 case t_name:
793 pvalue->type = gs_param_type_name;
794 return ref_param_read_string_value(plist->memory, &loc, &pvalue->value.n);
795 case t_null:
796 pvalue->type = gs_param_type_null;
797 return 0;
798 case t_real:
799 pvalue->value.f = loc.pvalue->value.realval;
800 pvalue->type = gs_param_type_float;
801 return 0;
802 case t_string:
803 pvalue->type = gs_param_type_string;
804 return ref_param_read_string_value(plist->memory, &loc, &pvalue->value.s);
805 default:
806 break;
807 }
808 return gs_note_error(e_typecheck);
809 }
810
811 private int
ref_param_read_get_policy(gs_param_list * plist,gs_param_name pkey)812 ref_param_read_get_policy(gs_param_list * plist, gs_param_name pkey)
813 {
814 iparam_list *const iplist = (iparam_list *) plist;
815 ref *pvalue;
816
817 if (!(r_has_type(&iplist->u.r.policies, t_dictionary) &&
818 dict_find_string(&iplist->u.r.policies, pkey, &pvalue) > 0 &&
819 r_has_type(pvalue, t_integer))
820 )
821 return gs_param_policy_ignore;
822 return (int)pvalue->value.intval;
823 }
824 private int
ref_param_read_signal_error(gs_param_list * plist,gs_param_name pkey,int code)825 ref_param_read_signal_error(gs_param_list * plist, gs_param_name pkey, int code)
826 {
827 iparam_list *const iplist = (iparam_list *) plist;
828 iparam_loc loc;
829
830 ref_param_read(iplist, pkey, &loc, -1); /* can't fail */
831 *loc.presult = code;
832 switch (ref_param_read_get_policy(plist, pkey)) {
833 case gs_param_policy_ignore:
834 return 0;
835 case gs_param_policy_consult_user:
836 return_error(e_configurationerror);
837 default:
838 return code;
839 }
840 }
841 private int
ref_param_read_commit(gs_param_list * plist)842 ref_param_read_commit(gs_param_list * plist)
843 {
844 iparam_list *const iplist = (iparam_list *) plist;
845 int i;
846 int ecode = 0;
847
848 if (!iplist->u.r.require_all)
849 return 0;
850 /* Check to make sure that all parameters were actually read. */
851 for (i = 0; i < iplist->count; ++i)
852 if (iplist->results[i] == 0)
853 iplist->results[i] = ecode = gs_note_error(e_undefined);
854 return ecode;
855 }
856 private int
ref_param_get_next_key(gs_param_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key)857 ref_param_get_next_key(gs_param_list * plist, gs_param_enumerator_t * penum,
858 gs_param_key_t * key)
859 {
860 ref_type keytype; /* result not needed here */
861 iparam_list *const pilist = (iparam_list *) plist;
862
863 return (*pilist->enumerate) (pilist, penum, key, &keytype);
864 }
865
866 /* ---------------- Internal routines ---------------- */
867
868 /* Read a string value. */
869 private int
ref_param_read_string_value(const gs_memory_t * mem,const iparam_loc * ploc,gs_param_string * pvalue)870 ref_param_read_string_value(const gs_memory_t *mem, const iparam_loc * ploc, gs_param_string * pvalue)
871 {
872 const ref *pref = ploc->pvalue;
873
874 switch (r_type(pref)) {
875 case t_name: {
876 ref nref;
877
878 name_string_ref(mem, pref, &nref);
879 pvalue->data = nref.value.const_bytes;
880 pvalue->size = r_size(&nref);
881 pvalue->persistent = true;
882 }
883 break;
884 case t_string:
885 iparam_check_read(*ploc);
886 pvalue->data = pref->value.const_bytes;
887 pvalue->size = r_size(pref);
888 pvalue->persistent = false;
889 break;
890 default:
891 return iparam_note_error(*ploc, e_typecheck);
892 }
893 return 0;
894 }
895
896 /* Read an array (or packed array) parameter. */
897 private int
ref_param_read_array(iparam_list * plist,gs_param_name pkey,iparam_loc * ploc)898 ref_param_read_array(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc)
899 {
900 int code = ref_param_read(plist, pkey, ploc, -1);
901
902 if (code != 0)
903 return code;
904 if (!r_is_array(ploc->pvalue))
905 return iparam_note_error(*ploc, e_typecheck);
906 iparam_check_read(*ploc);
907 return 0;
908 }
909
910 /* Generic routine for reading a ref parameter. */
911 private int
ref_param_read(iparam_list * plist,gs_param_name pkey,iparam_loc * ploc,int type)912 ref_param_read(iparam_list * plist, gs_param_name pkey, iparam_loc * ploc,
913 int type)
914 {
915 iparam_list *const iplist = (iparam_list *) plist;
916 ref kref;
917 int code = ref_param_key(plist, pkey, &kref);
918
919 if (code < 0)
920 return code;
921 code = (*plist->u.r.read) (iplist, &kref, ploc);
922 if (code != 0)
923 return code;
924 if (type >= 0)
925 iparam_check_type(*ploc, type);
926 return 0;
927 }
928
929 /* ---------------- Implementations ---------------- */
930
931 /* Implementation for putting parameters from an empty collection. */
932 private int
empty_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)933 empty_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
934 {
935 return 1;
936 }
937
938 /* Initialize for reading parameters. */
939 private int
ref_param_read_init(iparam_list * plist,uint count,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)940 ref_param_read_init(iparam_list * plist, uint count, const ref * ppolicies,
941 bool require_all, gs_ref_memory_t *imem)
942 {
943 gs_param_list_init((gs_param_list *)plist, &ref_read_procs,
944 (gs_memory_t *)imem);
945 plist->ref_memory = imem;
946 if (ppolicies == 0)
947 make_null(&plist->u.r.policies);
948 else
949 plist->u.r.policies = *ppolicies;
950 plist->u.r.require_all = require_all;
951 plist->count = count;
952 plist->results = (int *)
953 gs_alloc_byte_array(plist->memory, count, sizeof(int),
954 "ref_param_read_init");
955
956 if (plist->results == 0)
957 return_error(e_VMerror);
958 memset(plist->results, 0, count * sizeof(int));
959
960 plist->int_keys = false;
961 return 0;
962 }
963
964 /* Implementation for putting parameters from an indexed array. */
965 private int
array_indexed_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)966 array_indexed_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
967 {
968 ref *const arr = &((dict_param_list *) plist)->dict;
969
970 check_type(*pkey, t_integer);
971 if (pkey->value.intval < 0 || pkey->value.intval >= r_size(arr))
972 return 1;
973 ploc->pvalue = arr->value.refs + pkey->value.intval;
974 ploc->presult = &plist->results[pkey->value.intval];
975 *ploc->presult = 1;
976 return 0;
977 }
978 int
array_indexed_param_list_read(dict_param_list * plist,const ref * parray,const ref * ppolicies,bool require_all,gs_ref_memory_t * ref_memory)979 array_indexed_param_list_read(dict_param_list * plist, const ref * parray,
980 const ref * ppolicies, bool require_all,
981 gs_ref_memory_t *ref_memory)
982 {
983 iparam_list *const iplist = (iparam_list *) plist;
984 int code;
985
986 check_read_type(*parray, t_array);
987 plist->u.r.read = array_indexed_param_read;
988 plist->dict = *parray;
989 code = ref_param_read_init(iplist, r_size(parray), ppolicies,
990 require_all, ref_memory);
991 plist->int_keys = true;
992 return code;
993 }
994
995 /* Implementation for putting parameters from an array. */
996 private int
array_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)997 array_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
998 {
999 ref *bot = ((array_param_list *) plist)->bot;
1000 ref *ptr = bot;
1001 ref *top = ((array_param_list *) plist)->top;
1002
1003 for (; ptr < top; ptr += 2) {
1004 if (r_has_type(ptr, t_name) && name_eq(ptr, pkey)) {
1005 ploc->pvalue = ptr + 1;
1006 ploc->presult = &plist->results[ptr - bot];
1007 *ploc->presult = 1;
1008 return 0;
1009 }
1010 }
1011 return 1;
1012 }
1013
1014 /* Implementation for enumerating parameters in an array */
1015 private int /* ret 0 ok, 1 if EOF, or -ve err */
array_param_enumerate(iparam_list * plist,gs_param_enumerator_t * penum,gs_param_key_t * key,ref_type * type)1016 array_param_enumerate(iparam_list * plist, gs_param_enumerator_t * penum,
1017 gs_param_key_t * key, ref_type * type)
1018 {
1019 int index = penum->intval;
1020 ref *bot = ((array_param_list *) plist)->bot;
1021 ref *ptr = bot + index;
1022 ref *top = ((array_param_list *) plist)->top;
1023
1024 for (; ptr < top; ptr += 2) {
1025 index += 2;
1026
1027 if (r_has_type(ptr, t_name)) {
1028 int code = ref_to_key(ptr, key, plist);
1029
1030 *type = r_type(ptr);
1031 penum->intval = index;
1032 return code;
1033 }
1034 }
1035 return 1;
1036 }
1037
1038 int
array_param_list_read(array_param_list * plist,ref * bot,uint count,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1039 array_param_list_read(array_param_list * plist, ref * bot, uint count,
1040 const ref * ppolicies, bool require_all,
1041 gs_ref_memory_t *imem)
1042 {
1043 iparam_list *const iplist = (iparam_list *) plist;
1044
1045 if (count & 1)
1046 return_error(e_rangecheck);
1047 plist->u.r.read = array_param_read;
1048 plist->enumerate = array_param_enumerate;
1049 plist->bot = bot;
1050 plist->top = bot + count;
1051 return ref_param_read_init(iplist, count, ppolicies, require_all, imem);
1052 }
1053
1054 /* Implementation for putting parameters from a stack. */
1055 private int
stack_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)1056 stack_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
1057 {
1058 stack_param_list *const splist = (stack_param_list *) plist;
1059 ref_stack_t *pstack = splist->pstack;
1060
1061 /* This implementation is slow, but it probably doesn't matter. */
1062 uint index = splist->skip + 1;
1063 uint count = splist->count;
1064
1065 for (; count; count--, index += 2) {
1066 const ref *p = ref_stack_index(pstack, index);
1067
1068 if (r_has_type(p, t_name) && name_eq(p, pkey)) {
1069 ploc->pvalue = ref_stack_index(pstack, index - 1);
1070 ploc->presult = &plist->results[count - 1];
1071 *ploc->presult = 1;
1072 return 0;
1073 }
1074 }
1075 return 1;
1076 }
1077 int
stack_param_list_read(stack_param_list * plist,ref_stack_t * pstack,uint skip,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1078 stack_param_list_read(stack_param_list * plist, ref_stack_t * pstack,
1079 uint skip, const ref * ppolicies, bool require_all,
1080 gs_ref_memory_t *imem)
1081 {
1082 iparam_list *const iplist = (iparam_list *) plist;
1083 uint count = ref_stack_counttomark(pstack);
1084
1085 if (count == 0)
1086 return_error(e_unmatchedmark);
1087 count -= skip + 1;
1088 if (count & 1)
1089 return_error(e_rangecheck);
1090 plist->u.r.read = stack_param_read;
1091 plist->enumerate = stack_param_enumerate;
1092 plist->pstack = pstack;
1093 plist->skip = skip;
1094 return ref_param_read_init(iplist, count >> 1, ppolicies, require_all, imem);
1095 }
1096
1097 /* Implementation for putting parameters from a dictionary. */
1098 private int
dict_param_read(iparam_list * plist,const ref * pkey,iparam_loc * ploc)1099 dict_param_read(iparam_list * plist, const ref * pkey, iparam_loc * ploc)
1100 {
1101 ref const *spdict = &((dict_param_list *) plist)->dict;
1102 int code = dict_find(spdict, pkey, &ploc->pvalue);
1103
1104 if (code != 1)
1105 return 1;
1106 ploc->presult =
1107 &plist->results[dict_value_index(spdict, ploc->pvalue)];
1108 *ploc->presult = 1;
1109 return 0;
1110 }
1111 int
dict_param_list_read(dict_param_list * plist,const ref * pdict,const ref * ppolicies,bool require_all,gs_ref_memory_t * imem)1112 dict_param_list_read(dict_param_list * plist, const ref * pdict,
1113 const ref * ppolicies, bool require_all,
1114 gs_ref_memory_t *imem)
1115 {
1116 iparam_list *const iplist = (iparam_list *) plist;
1117 uint count;
1118
1119 if (pdict == 0) {
1120 plist->u.r.read = empty_param_read;
1121 count = 0;
1122 } else {
1123 check_dict_read(*pdict);
1124 plist->u.r.read = dict_param_read;
1125 plist->dict = *pdict;
1126 count = dict_max_index(pdict) + 1;
1127 }
1128 plist->enumerate = dict_param_enumerate;
1129 return ref_param_read_init(iplist, count, ppolicies, require_all, imem);
1130 }
1131