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