Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/idparam.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
47.7M
{
41
47.7M
    ref *pdval;
42
43
47.7M
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
44
47.6M
        *pvalue = defaultval;
45
47.6M
        return 1;
46
47.6M
    }
47
75.4k
    if (!r_has_type(pdval, t_boolean))
48
0
        return_error(gs_error_typecheck);
49
75.4k
    *pvalue = pdval->value.boolval;
50
75.4k
    return 0;
51
75.4k
}
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
5.33M
{
62
5.33M
    ref *pdval;
63
5.33M
    int code, ival;
64
65
5.33M
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
66
3.43M
        ival = defaultval;
67
3.43M
        code = 1;
68
3.43M
    } else {
69
1.90M
        switch (r_type(pdval)) {
70
1.90M
            case t_integer:
71
1.90M
                if (pdval->value.intval < minval || pdval->value.intval > maxval)
72
15
                    return_error(gs_error_rangecheck);
73
1.90M
                ival = pdval->value.intval;
74
1.90M
                break;
75
12
            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
12
                if (pdval->value.realval < minval || pdval->value.realval > maxval)
81
6
                    return_error(gs_error_rangecheck);
82
6
                ival = (long)pdval->value.realval;
83
6
                if (ival != pdval->value.realval)
84
6
                    return_error(gs_error_rangecheck);
85
0
                break;
86
0
            case t_null:
87
0
                return 2;
88
22
            default:
89
22
                return_error(gs_error_typecheck);
90
1.90M
        }
91
1.90M
        code = 0;
92
1.90M
    }
93
5.33M
    if (ival < minval || ival > maxval) {
94
1
        if (code == 1)
95
1
            return_error(gs_error_undefined);
96
0
        else
97
0
            return_error(gs_error_rangecheck);
98
1
    }
99
5.33M
    *pvalue = (int)ival;
100
5.33M
    return code;
101
5.33M
}
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
2.95M
{
108
2.95M
    int code = dict_int_null_param(pdict, kstr, minval, maxval,
109
2.95M
                                   defaultval, pvalue);
110
111
2.95M
    return (code == 2 ? gs_note_error(gs_error_typecheck) : code);
112
2.95M
}
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
74.5k
{
122
74.5k
    ref *pdval;
123
74.5k
    int code;
124
74.5k
    uint ival;
125
126
74.5k
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
127
64.5k
        ival = defaultval;
128
64.5k
        code = 1;
129
64.5k
    } else {
130
10.0k
        check_type_only(*pdval, t_integer);
131
10.0k
        if (pdval->value.intval != (uint) pdval->value.intval)
132
0
            return_error(gs_error_rangecheck);
133
10.0k
        ival = (uint) pdval->value.intval;
134
10.0k
        code = 0;
135
10.0k
    }
136
74.5k
    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
74.5k
    *pvalue = ival;
143
74.5k
    return code;
144
74.5k
}
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
258k
{
152
258k
    ref *pdval;
153
154
258k
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
155
193k
        *pvalue = defaultval;
156
193k
        return 1;
157
193k
    }
158
64.6k
    switch (r_type(pdval)) {
159
76
        case t_integer:
160
76
            *pvalue = (float)pdval->value.intval;
161
76
            return 0;
162
64.5k
        case t_real:
163
64.5k
            *pvalue = pdval->value.realval;
164
64.5k
            return 0;
165
64.6k
    }
166
64.6k
    return_error(gs_error_typecheck);
167
64.6k
}
168
169
170
/* Get an integer array from a dictionary. */
171
/* See idparam.h for specification. */
172
int
173
dict_int_array_check_param(const gs_memory_t *mem, const ref * pdict,
174
   const char *kstr, uint len, int *ivec, int under_error, int over_error)
175
0
{
176
0
    ref pa, *pdval;
177
0
    uint size;
178
0
    int i, code;
179
180
0
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
181
0
        return 0;
182
0
    if (!r_is_array(pdval))
183
0
        return_error(gs_error_typecheck);
184
0
    size = r_size(pdval);
185
0
    if (size > len)
186
0
        return_error(over_error);
187
0
    for (i = 0; i < size; i++) {
188
0
        code = array_get(mem, pdval, i, &pa);
189
0
        if (code < 0)
190
0
            return code;
191
        /* See dict_int_param above for why we allow reals here. */
192
0
        switch (r_type(&pa)) {
193
0
            case t_integer:
194
0
                if (pa.value.intval != (int)pa.value.intval)
195
0
                    return_error(gs_error_rangecheck);
196
0
                ivec[i] = (int)pa.value.intval;
197
0
                break;
198
0
            case t_real:
199
0
                if (pa.value.realval < (float)(min_int + 1) ||
200
0
                    pa.value.realval > (float)(max_int - 1) ||
201
0
                    pa.value.realval != (int)pa.value.realval
202
0
                    )
203
0
                    return_error(gs_error_rangecheck);
204
0
                ivec[i] = (int)pa.value.realval;
205
0
                break;
206
0
            default:
207
0
                return_error(gs_error_typecheck);
208
0
        }
209
0
    }
210
0
    return (size == len || under_error >= 0 ? size :
211
0
            gs_note_error(under_error));
212
0
}
213
int
214
dict_int_array_param(const gs_memory_t *mem, const ref * pdict,
215
   const char *kstr, uint maxlen, int *ivec)
216
0
{
217
0
    return dict_int_array_check_param(mem, pdict, kstr, maxlen, ivec,
218
0
                                      0, gs_error_limitcheck);
219
0
}
220
int
221
dict_ints_param(const gs_memory_t *mem, const ref * pdict,
222
   const char *kstr, uint len, int *ivec)
223
0
{
224
0
    return dict_int_array_check_param(mem, pdict, kstr, len, ivec,
225
0
                                      gs_error_rangecheck, gs_error_rangecheck);
226
0
}
227
228
/* Get a float array from a dictionary. */
229
/* Return the element count if OK, <0 if invalid. */
230
/* If the parameter is missing, then if defaultvec is NULL, return 0; */
231
/* if defaultvec is not NULL, copy it into fvec (maxlen elements) */
232
/* and return maxlen. */
233
int
234
dict_float_array_check_param(const gs_memory_t *mem,
235
                             const ref * pdict, const char *kstr,
236
                             uint len, float *fvec, const float *defaultvec,
237
                             int under_error, int over_error)
238
1.92M
{
239
1.92M
    ref *pdval;
240
1.92M
    uint size;
241
1.92M
    int code;
242
243
1.92M
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
244
700k
        if (defaultvec == NULL)
245
552k
            return 0;
246
147k
        memcpy(fvec, defaultvec, len * sizeof(float));
247
147k
        return len;
248
700k
    }
249
250
1.22M
    if (!r_is_array(pdval))
251
0
        return_error(gs_error_typecheck);
252
1.22M
    size = r_size(pdval);
253
1.22M
    if (size > len)
254
6
        return_error(over_error);
255
256
1.22M
    code = process_float_array(mem, pdval, size, fvec);
257
1.22M
    return (code < 0 ? code :
258
1.22M
            size == len || under_error >= 0 ? size :
259
1.22M
            gs_note_error(under_error));
260
1.22M
}
261
int
262
dict_float_array_param(const gs_memory_t *mem,
263
                       const ref * pdict, const char *kstr,
264
                       uint maxlen, float *fvec, const float *defaultvec)
265
451k
{
266
451k
    return dict_float_array_check_param(mem ,pdict, kstr, maxlen, fvec,
267
451k
                                        defaultvec, 0, gs_error_limitcheck);
268
451k
}
269
int
270
dict_floats_param(const gs_memory_t *mem,
271
                  const ref * pdict, const char *kstr,
272
                  uint maxlen, float *fvec, const float *defaultvec)
273
1.34M
{
274
1.34M
    return dict_float_array_check_param(mem, pdict, kstr, maxlen,
275
1.34M
                                        fvec, defaultvec,
276
1.34M
                                        gs_error_rangecheck, gs_error_rangecheck);
277
1.34M
}
278
279
/* Do dict_floats_param() and store [/key any] array in $error.errorinfo
280
 * on failure. The key must be a permanently allocated C string.
281
 */
282
int
283
dict_floats_param_errorinfo(i_ctx_t *i_ctx_p,
284
                  const ref * pdict, const char *kstr,
285
                  uint maxlen, float *fvec, const float *defaultvec)
286
6
{
287
6
    ref *val;
288
6
    int code = dict_float_array_check_param(imemory, pdict, kstr, maxlen,
289
6
                              fvec, defaultvec, gs_error_rangecheck, gs_error_rangecheck);
290
6
    if (code < 0) {
291
0
       if (dict_find_string(pdict, kstr, &val) > 0)
292
0
          gs_errorinfo_put_pair(i_ctx_p, kstr, strlen(kstr), val);
293
0
    }
294
6
    return code;
295
6
}
296
297
/*
298
 * Get a procedure from a dictionary.  If the key is missing,
299
 *      defaultval = false means substitute t__invalid;
300
 *      defaultval = true means substitute an empty procedure.
301
 * In either case, return 1.
302
 */
303
int
304
dict_proc_param(const ref * pdict, const char *kstr, ref * pproc,
305
                bool defaultval)
306
47
{
307
47
    ref *pdval;
308
309
47
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0) {
310
28
        if (defaultval)
311
28
            make_empty_const_array(pproc, a_readonly + a_executable);
312
21
        else
313
28
            make_t(pproc, t__invalid);
314
28
        return 1;
315
28
    }
316
47
    check_proc(*pdval);
317
19
    *pproc = *pdval;
318
19
    return 0;
319
19
}
320
321
/* Get a matrix from a dictionary. */
322
int
323
dict_matrix_param(const gs_memory_t *mem, const ref * pdict, const char *kstr, gs_matrix * pmat)
324
166k
{
325
166k
    ref *pdval;
326
327
166k
    if (pdict == 0 || dict_find_string(pdict, kstr, &pdval) <= 0)
328
0
        return_error(gs_error_typecheck);
329
166k
    return read_matrix(mem, pdval, pmat);
330
166k
}
331
332
/* Get a UniqueID or XUID from a dictionary. */
333
/* Return 0 if UniqueID, 1 if XUID, <0 if error. */
334
/* If there is no uid, return default. */
335
int
336
dict_uid_param(const ref * pdict, gs_uid * puid, int defaultval,
337
               gs_memory_t * mem, const i_ctx_t *i_ctx_p)
338
212k
{
339
212k
    ref *puniqueid;
340
341
212k
    if (pdict == 0) {
342
0
        uid_set_invalid(puid);
343
0
        return defaultval;
344
0
    }
345
    /* In a Level 2 environment, check for XUID first. */
346
212k
    if (level2_enabled &&
347
212k
        dict_find_string(pdict, "XUID", &puniqueid) > 0
348
212k
        ) {
349
0
        long *xvalues;
350
0
        uint size, i;
351
352
0
        if (!r_has_type(puniqueid, t_array))
353
0
            return_error(gs_error_typecheck);
354
0
        size = r_size(puniqueid);
355
0
        if (size == 0)
356
0
            return_error(gs_error_rangecheck);
357
0
        xvalues = (long *)gs_alloc_byte_array(mem, size, sizeof(long),
358
0
                                              "get XUID");
359
360
0
        if (xvalues == 0)
361
0
            return_error(gs_error_VMerror);
362
        /* Get the values from the XUID array. */
363
0
        for (i = 0; i < size; i++) {
364
0
            const ref *pvalue = puniqueid->value.const_refs + i;
365
366
0
            if (!r_has_type(pvalue, t_integer)) {
367
0
                gs_free_object(mem, xvalues, "get XUID");
368
0
                return_error(gs_error_typecheck);
369
0
            }
370
0
            xvalues[i] = pvalue->value.intval;
371
0
        }
372
0
        uid_set_XUID(puid, xvalues, size);
373
0
        return 1;
374
0
    }
375
    /* If no UniqueID entry, set the UID to invalid, */
376
    /* because UniqueID need not be present in all fonts, */
377
    /* and if it is, the legal range is 0 to 2^24-1. */
378
212k
    if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0) {
379
212k
        uid_set_invalid(puid);
380
212k
        return defaultval;
381
212k
    } else {
382
115
        if (!r_has_type(puniqueid, t_integer))
383
0
           return_error(gs_error_typecheck);
384
115
        if (puniqueid->value.intval < 0 || puniqueid->value.intval > 0x7fffffff)
385
0
           return_error(gs_error_rangecheck);
386
        /* Apparently fonts created by Fontographer often have */
387
        /* a UniqueID of 0, contrary to Adobe's specifications. */
388
        /* Treat 0 as equivalent to -1 (no UniqueID). */
389
115
        if (puniqueid->value.intval == 0) {
390
0
            uid_set_invalid(puid);
391
0
            return defaultval;
392
0
        } else
393
115
            uid_set_UniqueID(puid, puniqueid->value.intval);
394
115
    }
395
115
    return 0;
396
212k
}
397
398
/* Check that a UID in a dictionary is equal to an existing, valid UID. */
399
bool
400
dict_check_uid_param(const ref * pdict, const gs_uid * puid)
401
115
{
402
115
    ref *puniqueid;
403
404
115
    if (uid_is_XUID(puid)) {
405
0
        uint size = uid_XUID_size(puid);
406
0
        uint i;
407
408
0
        if (dict_find_string(pdict, "XUID", &puniqueid) <= 0)
409
0
            return false;
410
0
        if (!r_has_type(puniqueid, t_array) ||
411
0
            r_size(puniqueid) != size
412
0
            )
413
0
            return false;
414
0
        for (i = 0; i < size; i++) {
415
0
            const ref *pvalue = puniqueid->value.const_refs + i;
416
417
0
            if (!r_has_type(pvalue, t_integer))
418
0
                return false;
419
0
            if (pvalue->value.intval != uid_XUID_values(puid)[i])
420
0
                return false;
421
0
        }
422
0
        return true;
423
115
    } else {
424
115
        if (dict_find_string(pdict, "UniqueID", &puniqueid) <= 0)
425
0
            return false;
426
115
        return (r_has_type(puniqueid, t_integer) &&
427
115
                puniqueid->value.intval == puid->id);
428
115
    }
429
115
}
430
431
/* Create and store [/key any] array in $error.errorinfo.
432
 * The key must be a permanently allocated C string.
433
 * This routine is here because it is often used with parameter dictionaries.
434
 */
435
int
436
gs_errorinfo_put_pair(i_ctx_t *i_ctx_p, const char *key, int len, const ref *any)
437
6
{
438
6
    int code;
439
6
    ref pair, *aptr, key_name, *pderror;
440
441
6
    code = name_ref(imemory_local, (const byte *)key, len, &key_name, 0);
442
6
    if (code < 0)
443
0
        return code;
444
6
    code = gs_alloc_ref_array(iimemory_local, &pair, a_readonly, 2, "gs_errorinfo_put_pair");
445
6
    if (code < 0)
446
0
        return code;
447
6
    aptr = pair.value.refs;
448
6
    ref_assign_new(aptr, &key_name);
449
6
    ref_assign_new(aptr+1, any);
450
6
    if (dict_find_string(systemdict, "$error", &pderror) <= 0 ||
451
6
        !r_has_type(pderror, t_dictionary) ||
452
6
        idict_put_string(pderror, "errorinfo", &pair) < 0
453
6
        )
454
0
        return_error(gs_error_Fatal);
455
6
    return 0;
456
6
}
457
458
/* Take a key's value from a given dictionary, create [/key any] array,
459
 * and store it in $error.errorinfo.
460
 * The key must be a permanently allocated C string.
461
 */
462
void
463
gs_errorinfo_put_pair_from_dict(i_ctx_t *i_ctx_p, const ref *op, const char *key)
464
6
{   ref *val, n;
465
6
    if (dict_find_string(op, key, &val) <= 0) {
466
0
        make_null(&n);
467
0
        val = &n;
468
0
    }
469
6
    gs_errorinfo_put_pair(i_ctx_p, key, strlen(key), val);
470
6
}