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