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