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: idparam.c 9778 2009-06-05 05:55:54Z alexcher $ */
15 /* Utilities for getting parameters out of dictionaries. */
16 #include "memory_.h"
17 #include "string_.h" /* for strlen */
18 #include "ghost.h"
19 #include "ierrors.h"
20 #include "gsmatrix.h" /* for dict_matrix_param */
21 #include "gsuid.h"
22 #include "dstack.h" /* for systemdict */
23 #include "idict.h"
24 #include "iddict.h"
25 #include "idparam.h" /* interface definition */
26 #include "ilevel.h"
27 #include "imemory.h" /* for iutil.h */
28 #include "iname.h"
29 #include "iutil.h"
30 #include "oper.h" /* for check_proc */
31 #include "store.h" /* for making empty proc */
32
33 /* Get a Boolean parameter from a dictionary. */
34 /* Return 0 if found, 1 if defaulted, <0 if wrong type. */
35 int
dict_bool_param(const ref * pdict,const char * kstr,bool defaultval,bool * pvalue)36 dict_bool_param(const ref * pdict, const char *kstr,
37 bool defaultval, bool * pvalue)
38 {
39 ref *pdval;
40
41 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
42 *pvalue = defaultval;
43 return 1;
44 }
45 if (!r_has_type(pdval, t_boolean))
46 return_error(e_typecheck);
47 *pvalue = pdval->value.boolval;
48 return 0;
49 }
50
51 /* Get an integer or null parameter from a dictionary. */
52 /* Return 0 if found, 1 if defaulted, <0 if invalid. */
53 /* If the parameter is null, return 2 without setting *pvalue. */
54 /* Note that the default value may be out of range, in which case */
55 /* a missing value will return e_undefined rather than 1. */
56 int
dict_int_null_param(const ref * pdict,const char * kstr,int minval,int maxval,int defaultval,int * pvalue)57 dict_int_null_param(const ref * pdict, const char *kstr, int minval,
58 int maxval, int defaultval, int *pvalue)
59 {
60 ref *pdval;
61 int code, ival;
62
63 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
64 ival = defaultval;
65 code = 1;
66 } else {
67 switch (r_type(pdval)) {
68 case t_integer:
69 ival = pdval->value.intval;
70 break;
71 case t_real:
72 /* Allow an integral real, because Fontographer */
73 /* (which violates the Adobe specs in other ways */
74 /* as well) sometimes generates output that */
75 /* needs this. */
76 if (pdval->value.realval < minval || pdval->value.realval > maxval)
77 return_error(e_rangecheck);
78 ival = (long)pdval->value.realval;
79 if (ival != pdval->value.realval)
80 return_error(e_rangecheck);
81 break;
82 case t_null:
83 return 2;
84 default:
85 return_error(e_typecheck);
86 }
87 code = 0;
88 }
89 if (ival < minval || ival > maxval) {
90 if (code == 1)
91 return_error(e_undefined);
92 else
93 return_error(e_rangecheck);
94 }
95 *pvalue = (int)ival;
96 return code;
97 }
98 /* Get an integer parameter from a dictionary. */
99 /* Return like dict_int_null_param, but return e_typecheck for null. */
100 int
dict_int_param(const ref * pdict,const char * kstr,int minval,int maxval,int defaultval,int * pvalue)101 dict_int_param(const ref * pdict, const char *kstr, int minval, int maxval,
102 int defaultval, int *pvalue)
103 {
104 int code = dict_int_null_param(pdict, kstr, minval, maxval,
105 defaultval, pvalue);
106
107 return (code == 2 ? gs_note_error(e_typecheck) : code);
108 }
109
110 /* Get an unsigned integer parameter from a dictionary. */
111 /* Return 0 if found, 1 if defaulted, <0 if invalid. */
112 /* Note that the default value may be out of range, in which case */
113 /* a missing value will return e_undefined rather than 1. */
114 int
dict_uint_param(const ref * pdict,const char * kstr,uint minval,uint maxval,uint defaultval,uint * pvalue)115 dict_uint_param(const ref * pdict, const char *kstr,
116 uint minval, uint maxval, uint defaultval, uint * pvalue)
117 {
118 ref *pdval;
119 int code;
120 uint ival;
121
122 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
123 ival = defaultval;
124 code = 1;
125 } else {
126 check_type_only(*pdval, t_integer);
127 if (pdval->value.intval != (uint) pdval->value.intval)
128 return_error(e_rangecheck);
129 ival = (uint) pdval->value.intval;
130 code = 0;
131 }
132 if (ival < minval || ival > maxval) {
133 if (code == 1)
134 return_error(e_undefined);
135 else
136 return_error(e_rangecheck);
137 }
138 *pvalue = ival;
139 return code;
140 }
141
142 /* Get a float parameter from a dictionary. */
143 /* Return 0 if found, 1 if defaulted, <0 if wrong type. */
144 int
dict_float_param(const ref * pdict,const char * kstr,floatp defaultval,float * pvalue)145 dict_float_param(const ref * pdict, const char *kstr,
146 floatp defaultval, float *pvalue)
147 {
148 ref *pdval;
149
150 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
151 *pvalue = defaultval;
152 return 1;
153 }
154 switch (r_type(pdval)) {
155 case t_integer:
156 *pvalue = (float)pdval->value.intval;
157 return 0;
158 case t_real:
159 *pvalue = pdval->value.realval;
160 return 0;
161 }
162 return_error(e_typecheck);
163 }
164
165 /* Get an integer array from a dictionary. */
166 /* See idparam.h for specification. */
167 int
dict_int_array_check_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint len,int * ivec,int under_error,int over_error)168 dict_int_array_check_param(const gs_memory_t *mem, const ref * pdict,
169 const char *kstr, uint len, int *ivec, int under_error, int over_error)
170 {
171 ref pa, *pdval;
172 uint size;
173 int i, code;
174
175 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
176 return 0;
177 if (!r_is_array(pdval))
178 return_error(e_typecheck);
179 size = r_size(pdval);
180 if (size > len)
181 return_error(over_error);
182 for (i = 0; i < size; i++) {
183 code = array_get(mem, pdval, i, &pa);
184 if (code < 0)
185 return code;
186 /* See dict_int_param above for why we allow reals here. */
187 switch (r_type(&pa)) {
188 case t_integer:
189 if (pa.value.intval != (int)pa.value.intval)
190 return_error(e_rangecheck);
191 ivec[i] = (int)pa.value.intval;
192 break;
193 case t_real:
194 if (pa.value.realval < min_int ||
195 pa.value.realval > max_int ||
196 pa.value.realval != (int)pa.value.realval
197 )
198 return_error(e_rangecheck);
199 ivec[i] = (int)pa.value.realval;
200 break;
201 default:
202 return_error(e_typecheck);
203 }
204 }
205 return (size == len || under_error >= 0 ? size :
206 gs_note_error(under_error));
207 }
208 int
dict_int_array_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint maxlen,int * ivec)209 dict_int_array_param(const gs_memory_t *mem, const ref * pdict,
210 const char *kstr, uint maxlen, int *ivec)
211 {
212 return dict_int_array_check_param(mem, pdict, kstr, maxlen, ivec,
213 0, e_limitcheck);
214 }
215 int
dict_ints_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint len,int * ivec)216 dict_ints_param(const gs_memory_t *mem, const ref * pdict,
217 const char *kstr, uint len, int *ivec)
218 {
219 return dict_int_array_check_param(mem, pdict, kstr, len, ivec,
220 e_rangecheck, e_rangecheck);
221 }
222
223 /* Get a float array from a dictionary. */
224 /* Return the element count if OK, <0 if invalid. */
225 /* If the parameter is missing, then if defaultvec is NULL, return 0; */
226 /* if defaultvec is not NULL, copy it into fvec (maxlen elements) */
227 /* and return maxlen. */
228 int
dict_float_array_check_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint len,float * fvec,const float * defaultvec,int under_error,int over_error)229 dict_float_array_check_param(const gs_memory_t *mem,
230 const ref * pdict, const char *kstr,
231 uint len, float *fvec, const float *defaultvec,
232 int under_error, int over_error)
233 {
234 ref *pdval;
235 uint size;
236 int code;
237
238 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
239 if (defaultvec == NULL)
240 return 0;
241 memcpy(fvec, defaultvec, len * sizeof(float));
242
243 return len;
244 }
245 if (!r_is_array(pdval))
246 return_error(e_typecheck);
247 size = r_size(pdval);
248 if (size > len)
249 return_error(over_error);
250 code = process_float_array(mem, pdval, size, fvec);
251 return (code < 0 ? code :
252 size == len || under_error >= 0 ? size :
253 gs_note_error(under_error));
254 }
255 int
dict_float_array_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint maxlen,float * fvec,const float * defaultvec)256 dict_float_array_param(const gs_memory_t *mem,
257 const ref * pdict, const char *kstr,
258 uint maxlen, float *fvec, const float *defaultvec)
259 {
260 return dict_float_array_check_param(mem ,pdict, kstr, maxlen, fvec,
261 defaultvec, 0, e_limitcheck);
262 }
263 int
dict_floats_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,uint maxlen,float * fvec,const float * defaultvec)264 dict_floats_param(const gs_memory_t *mem,
265 const ref * pdict, const char *kstr,
266 uint maxlen, float *fvec, const float *defaultvec)
267 {
268 return dict_float_array_check_param(mem, pdict, kstr, maxlen,
269 fvec, defaultvec,
270 e_rangecheck, e_rangecheck);
271 }
272
273
274 /* Do dict_floats_param() and store [/key any] array in $error.errorinfo
275 * on failure. The key must be a permanently allocated C string.
276 */
277 int
dict_floats_param_errorinfo(i_ctx_t * i_ctx_p,const ref * pdict,const char * kstr,uint maxlen,float * fvec,const float * defaultvec)278 dict_floats_param_errorinfo(i_ctx_t *i_ctx_p,
279 const ref * pdict, const char *kstr,
280 uint maxlen, float *fvec, const float *defaultvec)
281 {
282 ref *val;
283 int code = dict_float_array_check_param(imemory, pdict, kstr, maxlen,
284 fvec, defaultvec, e_rangecheck, e_rangecheck);
285 if (code < 0) {
286 if (dict_find_string(pdict, kstr, &val) > 0)
287 gs_errorinfo_put_pair(i_ctx_p, kstr, strlen(kstr), val);
288 }
289 return code;
290 }
291
292
293 /*
294 * Get a procedure from a dictionary. If the key is missing,
295 * defaultval = false means substitute t__invalid;
296 * defaultval = true means substitute an empty procedure.
297 * In either case, return 1.
298 */
299 int
dict_proc_param(const ref * pdict,const char * kstr,ref * pproc,bool defaultval)300 dict_proc_param(const ref * pdict, const char *kstr, ref * pproc,
301 bool defaultval)
302 {
303 ref *pdval;
304
305 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
306 if (defaultval)
307 make_empty_const_array(pproc, a_readonly + a_executable);
308 else
309 make_t(pproc, t__invalid);
310 return 1;
311 }
312 check_proc(*pdval);
313 *pproc = *pdval;
314 return 0;
315 }
316
317 /* Get a matrix from a dictionary. */
318 int
dict_matrix_param(const gs_memory_t * mem,const ref * pdict,const char * kstr,gs_matrix * pmat)319 dict_matrix_param(const gs_memory_t *mem, const ref * pdict, const char *kstr, gs_matrix * pmat)
320 {
321 ref *pdval;
322
323 if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
324 return_error(e_typecheck);
325 return read_matrix(mem, pdval, pmat);
326 }
327
328 /* Get a UniqueID or XUID from a dictionary. */
329 /* Return 0 if UniqueID, 1 if XUID, <0 if error. */
330 /* If there is no uid, return default. */
331 int
dict_uid_param(const ref * pdict,gs_uid * puid,int defaultval,gs_memory_t * mem,const i_ctx_t * i_ctx_p)332 dict_uid_param(const ref * pdict, gs_uid * puid, int defaultval,
333 gs_memory_t * mem, const i_ctx_t *i_ctx_p)
334 {
335 ref *puniqueid;
336
337 if (pdict == 0) {
338 uid_set_invalid(puid);
339 return defaultval;
340 }
341 /* In a Level 2 environment, check for XUID first. */
342 if (level2_enabled &&
343 dict_find_string(pdict, "XUID", &puniqueid) > 0
344 ) {
345 long *xvalues;
346 uint size, i;
347
348 if (!r_has_type(puniqueid, t_array))
349 return_error(e_typecheck);
350 size = r_size(puniqueid);
351 if (size == 0)
352 return_error(e_rangecheck);
353 xvalues = (long *)gs_alloc_byte_array(mem, size, sizeof(long),
354 "get XUID");
355
356 if (xvalues == 0)
357 return_error(e_VMerror);
358 /* Get the values from the XUID array. */
359 for (i = 0; i < size; i++) {
360 const ref *pvalue = puniqueid->value.const_refs + i;
361
362 if (!r_has_type(pvalue, t_integer)) {
363 gs_free_object(mem, xvalues, "get XUID");
364 return_error(e_typecheck);
365 }
366 xvalues[i] = pvalue->value.intval;
367 }
368 uid_set_XUID(puid, xvalues, size);
369 return 1;
370 }
371 /* If no UniqueID entry, set the UID to invalid, */
372 /* because UniqueID need not be present in all fonts, */
373 /* and if it is, the legal range is 0 to 2^24-1. */
374 if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0) {
375 uid_set_invalid(puid);
376 return defaultval;
377 } else {
378 if (!r_has_type(puniqueid, t_integer))
379 return_error(e_typecheck);
380 if (puniqueid->value.intval < 0 || puniqueid->value.intval > 0xffffff)
381 return_error(e_rangecheck);
382 /* Apparently fonts created by Fontographer often have */
383 /* a UniqueID of 0, contrary to Adobe's specifications. */
384 /* Treat 0 as equivalent to -1 (no UniqueID). */
385 if (puniqueid->value.intval == 0) {
386 uid_set_invalid(puid);
387 return defaultval;
388 } else
389 uid_set_UniqueID(puid, puniqueid->value.intval);
390 }
391 return 0;
392 }
393
394 /* Check that a UID in a dictionary is equal to an existing, valid UID. */
395 bool
dict_check_uid_param(const ref * pdict,const gs_uid * puid)396 dict_check_uid_param(const ref * pdict, const gs_uid * puid)
397 {
398 ref *puniqueid;
399
400 if (uid_is_XUID(puid)) {
401 uint size = uid_XUID_size(puid);
402 uint i;
403
404 if (dict_find_string(pdict, "XUID", &puniqueid) <= 0)
405 return false;
406 if (!r_has_type(puniqueid, t_array) ||
407 r_size(puniqueid) != size
408 )
409 return false;
410 for (i = 0; i < size; i++) {
411 const ref *pvalue = puniqueid->value.const_refs + i;
412
413 if (!r_has_type(pvalue, t_integer))
414 return false;
415 if (pvalue->value.intval != uid_XUID_values(puid)[i])
416 return false;
417 }
418 return true;
419 } else {
420 if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0)
421 return false;
422 return (r_has_type(puniqueid, t_integer) &&
423 puniqueid->value.intval == puid->id);
424 }
425 }
426
427 /* Create and store [/key any] array in $error.errorinfo.
428 * The key must be a permanently allocated C string.
429 * This routine is here because it is often used with parameter dictionaries.
430 */
431 int
gs_errorinfo_put_pair(i_ctx_t * i_ctx_p,const char * key,int len,const ref * any)432 gs_errorinfo_put_pair(i_ctx_t *i_ctx_p, const char *key, int len, const ref *any)
433 {
434 int code;
435 ref pair, *aptr, key_name, *pderror;
436
437 code = name_ref(imemory_local, (const byte *)key, len, &key_name, 0);
438 if (code < 0)
439 return code;
440 code = gs_alloc_ref_array(iimemory_local, &pair, a_readonly, 2, "gs_errorinfo_put_pair");
441 if (code < 0)
442 return code;
443 aptr = pair.value.refs;
444 ref_assign_new(aptr, &key_name);
445 ref_assign_new(aptr+1, any);
446 if (dict_find_string(systemdict, "$error", &pderror) <= 0 ||
447 !r_has_type(pderror, t_dictionary) ||
448 idict_put_string(pderror, "errorinfo", &pair) < 0
449 )
450 return_error(e_Fatal);
451 return 0;
452 }
453
454 /* Take a key's value from a given dictionary, create [/key any] array,
455 * and store it in $error.errorinfo.
456 * The key must be a permanently allocated C string.
457 */
458 void
gs_errorinfo_put_pair_from_dict(i_ctx_t * i_ctx_p,const ref * op,const char * key)459 gs_errorinfo_put_pair_from_dict(i_ctx_t *i_ctx_p, const ref *op, const char *key)
460 { ref *val, n;
461 if (dict_find_string(op, key, &val) <= 0) {
462 make_null(&n);
463 val = &n;
464 }
465 gs_errorinfo_put_pair(i_ctx_p, key, strlen(key), val);
466 }
467