Coverage Report

Created: 2025-06-24 07:01

/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
}