Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/idict.h
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
/* Interfaces for Ghostscript dictionary package */
18
19
#ifndef idict_INCLUDED
20
#  define idict_INCLUDED
21
22
#include "iddstack.h"
23
#include "gsalloc.h"
24
25
/*
26
 * Contrary to our usual practice, we expose the (first-level)
27
 * representation of a dictionary in the interface file,
28
 * because it is so important that access checking go fast.
29
 * The access attributes for the dictionary are stored in
30
 * the values ref.
31
 */
32
struct dict_s {
33
    ref values;     /* t_array, values */
34
    ref keys;     /* t_shortarray or t_array, keys */
35
    ref count;      /* t_integer, count of occupied entries */
36
    /* (length) */
37
    ref maxlength;    /* t_integer, maxlength as seen by client. */
38
    ref memory;     /* foreign t_struct, the allocator that */
39
    /* created this dictionary */
40
6.14G
#define dict_memory(pdict) r_ptr(&(pdict)->memory, gs_ref_memory_t)
41
24.4G
#define dict_mem(pdict) r_ptr(&(pdict)->memory, gs_memory_t)
42
};
43
44
/*
45
 * Define the maximum size of a dictionary.
46
 */
47
extern const uint dict_max_size;
48
49
/*
50
 * Define whether dictionaries expand automatically when full.  Note that
51
 * if dict_auto_expand is true, dict_put, dict_copy, dict_resize, and
52
 * dict_grow cannot return gs_error_dictfull; however, they can return gs_error_VMerror.
53
 * (dict_find can return gs_error_dictfull even if dict_auto_expand is true.)
54
 */
55
extern bool dict_auto_expand;
56
57
/*
58
 * Create a dictionary.
59
 */
60
int dict_alloc(gs_ref_memory_t *, uint maxlength, ref * pdref);
61
62
#define dict_create(maxlen, pdref)\
63
97.4M
  dict_alloc(iimemory, maxlen, pdref)
64
65
/*
66
 * Return a pointer to a ref that holds the access attributes
67
 * for a dictionary.
68
 */
69
42.7M
#define dict_access_ref(pdref) (&(pdref)->value.pdict->values)
70
/*
71
 * Check a dictionary for read or write permission.
72
 * Note: this does NOT check the type of its operand!
73
 */
74
2.33G
#define check_dict_read(dref) check_read(*dict_access_ref(&dref))
75
1.06G
#define check_dict_write(dref) check_write(*dict_access_ref(&dref))
76
77
/*
78
 * Look up a key in a dictionary.  Store a pointer to the value slot
79
 * where found, or to the (value) slot for inserting.
80
 * The caller is responsible for checking that the dictionary is readable.
81
 * Return 1 if found, 0 if not and there is room for a new entry,
82
 * Failure returns:
83
 *      gs_error_typecheck if the key is null;
84
 *      gs_error_invalidaccess if the key is a string lacking read access;
85
 *      gs_error_VMerror or gs_error_limitcheck if the key is a string and the corresponding
86
 *        error occurs from attempting to convert it to a name;
87
 *      gs_error_dictfull if the dictionary is full and the key is missing.
88
 */
89
int dict_find(const ref * pdref, const ref * key, ref ** ppvalue);
90
91
/* As above, but checks that the value has the requested type */
92
static inline int
93
dict_find_with_type(const ref * pdref, const ref * key, ref ** ppvalue, ref_type type)
94
0
{
95
0
    int code = dict_find(pdref, key, ppvalue);
96
0
    if (code > 0)
97
0
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
98
0
            code = gs_note_error(gs_error_typecheck);
99
0
    return code;
100
0
}
Unexecuted instantiation: imain.c:dict_find_with_type
Unexecuted instantiation: zupath.c:dict_find_with_type
Unexecuted instantiation: zfcid0.c:dict_find_with_type
Unexecuted instantiation: zfcid1.c:dict_find_with_type
Unexecuted instantiation: zchar1.c:dict_find_with_type
Unexecuted instantiation: zcharout.c:dict_find_with_type
Unexecuted instantiation: zfont1.c:dict_find_with_type
Unexecuted instantiation: zmisc1.c:dict_find_with_type
Unexecuted instantiation: zmisc2.c:dict_find_with_type
Unexecuted instantiation: zusparam.c:dict_find_with_type
Unexecuted instantiation: zfont2.c:dict_find_with_type
Unexecuted instantiation: zchar42.c:dict_find_with_type
Unexecuted instantiation: zfont42.c:dict_find_with_type
Unexecuted instantiation: zfrsd.c:dict_find_with_type
Unexecuted instantiation: zcrd.c:dict_find_with_type
Unexecuted instantiation: zfcmap.c:dict_find_with_type
Unexecuted instantiation: zfont0.c:dict_find_with_type
Unexecuted instantiation: zfdcte.c:dict_find_with_type
Unexecuted instantiation: zfdecode.c:dict_find_with_type
Unexecuted instantiation: zfilter2.c:dict_find_with_type
Unexecuted instantiation: zdevice2.c:dict_find_with_type
Unexecuted instantiation: zmedia2.c:dict_find_with_type
Unexecuted instantiation: zpcolor.c:dict_find_with_type
Unexecuted instantiation: idebug.c:dict_find_with_type
Unexecuted instantiation: idict.c:dict_find_with_type
Unexecuted instantiation: idparam.c:dict_find_with_type
Unexecuted instantiation: idstack.c:dict_find_with_type
Unexecuted instantiation: iinit.c:dict_find_with_type
Unexecuted instantiation: interp.c:dict_find_with_type
Unexecuted instantiation: iparam.c:dict_find_with_type
Unexecuted instantiation: iscan.c:dict_find_with_type
Unexecuted instantiation: istack.c:dict_find_with_type
Unexecuted instantiation: iutil.c:dict_find_with_type
Unexecuted instantiation: zdict.c:dict_find_with_type
Unexecuted instantiation: zfile.c:dict_find_with_type
Unexecuted instantiation: zfilter.c:dict_find_with_type
Unexecuted instantiation: zgeneric.c:dict_find_with_type
Unexecuted instantiation: zmisc.c:dict_find_with_type
Unexecuted instantiation: zpacked.c:dict_find_with_type
Unexecuted instantiation: zrelbit.c:dict_find_with_type
Unexecuted instantiation: ztoken.c:dict_find_with_type
Unexecuted instantiation: ztype.c:dict_find_with_type
Unexecuted instantiation: zvmem.c:dict_find_with_type
Unexecuted instantiation: zbfont.c:dict_find_with_type
Unexecuted instantiation: zchar.c:dict_find_with_type
Unexecuted instantiation: zcolor.c:dict_find_with_type
Unexecuted instantiation: zdevice.c:dict_find_with_type
Unexecuted instantiation: zfont.c:dict_find_with_type
Unexecuted instantiation: zgstate.c:dict_find_with_type
Unexecuted instantiation: zimage.c:dict_find_with_type
Unexecuted instantiation: igc.c:dict_find_with_type
Unexecuted instantiation: ilocate.c:dict_find_with_type
Unexecuted instantiation: zdscpars.c:dict_find_with_type
Unexecuted instantiation: zfapi.c:dict_find_with_type
Unexecuted instantiation: zht2.c:dict_find_with_type
Unexecuted instantiation: zfsample.c:dict_find_with_type
Unexecuted instantiation: zfunc4.c:dict_find_with_type
Unexecuted instantiation: zfunc.c:dict_find_with_type
Unexecuted instantiation: zfunc0.c:dict_find_with_type
Unexecuted instantiation: zfimscale.c:dict_find_with_type
Unexecuted instantiation: zform.c:dict_find_with_type
Unexecuted instantiation: zfunc3.c:dict_find_with_type
Unexecuted instantiation: zimage3.c:dict_find_with_type
Unexecuted instantiation: zshade.c:dict_find_with_type
Unexecuted instantiation: zfzlib.c:dict_find_with_type
Unexecuted instantiation: zicc.c:dict_find_with_type
Unexecuted instantiation: ztrans.c:dict_find_with_type
Unexecuted instantiation: zpdfops.c:dict_find_with_type
Unexecuted instantiation: iscanbin.c:dict_find_with_type
Unexecuted instantiation: zcid.c:dict_find_with_type
Unexecuted instantiation: zfcid.c:dict_find_with_type
Unexecuted instantiation: iutil2.c:dict_find_with_type
Unexecuted instantiation: zcie.c:dict_find_with_type
Unexecuted instantiation: icontext.c:dict_find_with_type
101
102
/*
103
 * Look up a (constant) C string in a dictionary.
104
 * Return 1 if found, <= 0 if not.
105
 */
106
int dict_find_string(const ref * pdref, const char *kstr, ref ** ppvalue);
107
108
/* As above, but checks that the value has the requested type */
109
static inline int
110
dict_find_string_with_type(const ref * pdref, const char *kstr, ref ** ppvalue, ref_type type)
111
38.7M
{
112
38.7M
    int code = dict_find_string(pdref, kstr, ppvalue);
113
38.7M
    if (code > 0)
114
38.7M
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
115
0
            code = gs_note_error(gs_error_typecheck);
116
38.7M
    return code;
117
38.7M
}
Unexecuted instantiation: imain.c:dict_find_string_with_type
Unexecuted instantiation: zupath.c:dict_find_string_with_type
Unexecuted instantiation: zfcid0.c:dict_find_string_with_type
Unexecuted instantiation: zfcid1.c:dict_find_string_with_type
Unexecuted instantiation: zchar1.c:dict_find_string_with_type
Unexecuted instantiation: zcharout.c:dict_find_string_with_type
Unexecuted instantiation: zfont1.c:dict_find_string_with_type
Unexecuted instantiation: zmisc1.c:dict_find_string_with_type
Unexecuted instantiation: zmisc2.c:dict_find_string_with_type
Unexecuted instantiation: zusparam.c:dict_find_string_with_type
Unexecuted instantiation: zfont2.c:dict_find_string_with_type
Unexecuted instantiation: zchar42.c:dict_find_string_with_type
Unexecuted instantiation: zfont42.c:dict_find_string_with_type
Unexecuted instantiation: zfrsd.c:dict_find_string_with_type
Unexecuted instantiation: zcrd.c:dict_find_string_with_type
Unexecuted instantiation: zfcmap.c:dict_find_string_with_type
Unexecuted instantiation: zfont0.c:dict_find_string_with_type
Unexecuted instantiation: zfdcte.c:dict_find_string_with_type
Unexecuted instantiation: zfdecode.c:dict_find_string_with_type
Unexecuted instantiation: zfilter2.c:dict_find_string_with_type
Unexecuted instantiation: zdevice2.c:dict_find_string_with_type
Unexecuted instantiation: zmedia2.c:dict_find_string_with_type
Unexecuted instantiation: zpcolor.c:dict_find_string_with_type
Unexecuted instantiation: idebug.c:dict_find_string_with_type
Unexecuted instantiation: idict.c:dict_find_string_with_type
Unexecuted instantiation: idparam.c:dict_find_string_with_type
Unexecuted instantiation: idstack.c:dict_find_string_with_type
Unexecuted instantiation: iinit.c:dict_find_string_with_type
Unexecuted instantiation: interp.c:dict_find_string_with_type
Unexecuted instantiation: iparam.c:dict_find_string_with_type
Unexecuted instantiation: iscan.c:dict_find_string_with_type
Unexecuted instantiation: istack.c:dict_find_string_with_type
Unexecuted instantiation: iutil.c:dict_find_string_with_type
Unexecuted instantiation: zdict.c:dict_find_string_with_type
zfile.c:dict_find_string_with_type
Line
Count
Source
111
33.5M
{
112
33.5M
    int code = dict_find_string(pdref, kstr, ppvalue);
113
33.5M
    if (code > 0)
114
33.5M
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
115
0
            code = gs_note_error(gs_error_typecheck);
116
33.5M
    return code;
117
33.5M
}
Unexecuted instantiation: zfilter.c:dict_find_string_with_type
Unexecuted instantiation: zgeneric.c:dict_find_string_with_type
Unexecuted instantiation: zmisc.c:dict_find_string_with_type
Unexecuted instantiation: zpacked.c:dict_find_string_with_type
Unexecuted instantiation: zrelbit.c:dict_find_string_with_type
Unexecuted instantiation: ztoken.c:dict_find_string_with_type
Unexecuted instantiation: ztype.c:dict_find_string_with_type
Unexecuted instantiation: zvmem.c:dict_find_string_with_type
Unexecuted instantiation: zbfont.c:dict_find_string_with_type
Unexecuted instantiation: zchar.c:dict_find_string_with_type
zcolor.c:dict_find_string_with_type
Line
Count
Source
111
76
{
112
76
    int code = dict_find_string(pdref, kstr, ppvalue);
113
76
    if (code > 0)
114
0
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
115
0
            code = gs_note_error(gs_error_typecheck);
116
76
    return code;
117
76
}
Unexecuted instantiation: zdevice.c:dict_find_string_with_type
Unexecuted instantiation: zfont.c:dict_find_string_with_type
Unexecuted instantiation: zgstate.c:dict_find_string_with_type
Unexecuted instantiation: zimage.c:dict_find_string_with_type
Unexecuted instantiation: igc.c:dict_find_string_with_type
Unexecuted instantiation: ilocate.c:dict_find_string_with_type
Unexecuted instantiation: zdscpars.c:dict_find_string_with_type
zfapi.c:dict_find_string_with_type
Line
Count
Source
111
5.24M
{
112
5.24M
    int code = dict_find_string(pdref, kstr, ppvalue);
113
5.24M
    if (code > 0)
114
5.24M
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
115
0
            code = gs_note_error(gs_error_typecheck);
116
5.24M
    return code;
117
5.24M
}
Unexecuted instantiation: zht2.c:dict_find_string_with_type
Unexecuted instantiation: zfsample.c:dict_find_string_with_type
Unexecuted instantiation: zfunc4.c:dict_find_string_with_type
Unexecuted instantiation: zfunc.c:dict_find_string_with_type
Unexecuted instantiation: zfunc0.c:dict_find_string_with_type
Unexecuted instantiation: zfimscale.c:dict_find_string_with_type
Unexecuted instantiation: zform.c:dict_find_string_with_type
Unexecuted instantiation: zfunc3.c:dict_find_string_with_type
Unexecuted instantiation: zimage3.c:dict_find_string_with_type
Unexecuted instantiation: zshade.c:dict_find_string_with_type
Unexecuted instantiation: zfzlib.c:dict_find_string_with_type
Unexecuted instantiation: zicc.c:dict_find_string_with_type
Unexecuted instantiation: ztrans.c:dict_find_string_with_type
Unexecuted instantiation: zpdfops.c:dict_find_string_with_type
Unexecuted instantiation: iscanbin.c:dict_find_string_with_type
Unexecuted instantiation: zcid.c:dict_find_string_with_type
zfcid.c:dict_find_string_with_type
Line
Count
Source
111
2
{
112
2
    int code = dict_find_string(pdref, kstr, ppvalue);
113
2
    if (code > 0)
114
2
        if ((type == t_array) ? !r_is_array(*ppvalue) : !r_has_type(*ppvalue, type))
115
0
            code = gs_note_error(gs_error_typecheck);
116
2
    return code;
117
2
}
Unexecuted instantiation: iutil2.c:dict_find_string_with_type
Unexecuted instantiation: zcie.c:dict_find_string_with_type
Unexecuted instantiation: icontext.c:dict_find_string_with_type
118
119
120
/*
121
 * Enter a key-value pair in a dictionary.
122
 * The caller is responsible for checking that the dictionary is writable.
123
 * Return 1 if this was a new entry, 0 if this replaced an existing entry.
124
 * Failure returns are as for dict_find, except that gs_error_dictfull doesn't
125
 * occur if the dictionary is full but expandable, plus:
126
 *      gs_error_invalidaccess for an attempt to store a younger key or value into
127
 *        an older dictionary, or as described just below;
128
 *      gs_error_VMerror if a VMerror occurred while trying to expand the
129
 *        dictionary.
130
 * Note that this procedure, and all procedures that may change the
131
 * contents of a dictionary, take a pointer to a dictionary stack,
132
 * so they can update the cached 'top' values and also update the cached
133
 * value pointer in names.  A NULL pointer for the dictionary stack is
134
 * allowed, but in this case, if the dictionary is present on any dictionary
135
 * stack, an gs_error_invalidaccess error will occur if cached values need updating.
136
 * THIS ERROR CHECK IS NOT IMPLEMENTED YET.
137
 */
138
int dict_put(ref * pdref, const ref * key, const ref * pvalue,
139
             dict_stack_t *pds);
140
141
/*
142
 * Enter a key-value pair where the key is a (constant) C string.
143
 */
144
int dict_put_string(ref * pdref, const char *kstr, const ref * pvalue,
145
                    dict_stack_t *pds);
146
147
/*
148
 * Enter a key-value pair where the key is a (transient) C string.
149
 */
150
int dict_put_string_copy(ref * pdref, const char *kstr, const ref * pvalue,
151
                         dict_stack_t *pds);
152
153
/*
154
 * Remove a key-value pair from a dictionary.
155
 * Return any of the same values as dict_put, except for 0 and gs_error_dictfull
156
 * which are converted to gs_error_undefined.
157
 */
158
int dict_undef(ref * pdref, const ref * key, dict_stack_t *pds);
159
160
/*
161
 * Return the number of elements in a dictionary.
162
 */
163
uint dict_length(const ref * pdref);
164
165
/*
166
 * Return the capacity of a dictionary.
167
 */
168
uint dict_maxlength(const ref * pdref);
169
170
/*
171
 * Return the maximum index of a slot within a dictionary.
172
 * Note that this may be greater than maxlength.
173
 */
174
uint dict_max_index(const ref * pdref);
175
176
/*
177
 * Copy one dictionary into another.
178
 * Return 0 or gs_error_dictfull.
179
 * If new_only is true, only copy entries whose keys
180
 * aren't already present in the destination.
181
 */
182
int dict_copy_entries(const ref * dfrom, ref * dto, bool new_only,
183
                      dict_stack_t *pds);
184
185
2.58M
#define dict_copy(dfrom, dto, pds) dict_copy_entries(dfrom, dto, false, pds)
186
221k
#define dict_copy_new(dfrom, dto, pds) dict_copy_entries(dfrom, dto, true, pds)
187
188
/*
189
 * Grow or shrink a dictionary.
190
 * Return 0, gs_error_dictfull, or gs_error_VMerror.
191
 */
192
int dict_resize(ref * pdref, uint newmaxlength, dict_stack_t *pds);
193
194
/*
195
 * Grow a dictionary in the same way as dict_put does.
196
 * We export this for some special-case code in zop_def.
197
 */
198
int dict_grow(ref * pdref, dict_stack_t *pds);
199
200
/*
201
 * Ensure that a dictionary uses the unpacked representation for keys.
202
 * (This is of no interest to ordinary clients.)
203
 */
204
int dict_unpack(ref * pdref, dict_stack_t *pds);
205
206
/*
207
 * Prepare to enumerate a dictionary.
208
 * Return an integer suitable for the first call to dict_next.
209
 */
210
int dict_first(const ref * pdref);
211
212
/*
213
 * Enumerate the next element of a dictionary.
214
 * index is initially the result of a call on dict_first.
215
 * Either store a key and value at eltp[0] and eltp[1]
216
 * and return an updated index, or return -1
217
 * to signal that there are no more elements in the dictionary.
218
 */
219
int dict_next(const ref * pdref, int index, ref * eltp);
220
221
/*
222
 * Given a value pointer return by dict_find, return an index that
223
 * identifies the entry within the dictionary. (This may, but need not,
224
 * be the same as the index returned by dict_next.)
225
 * The index is in the range [0..max_index-1].
226
 */
227
int dict_value_index(const ref * pdref, const ref * pvalue);
228
229
/*
230
 * Given an index in [0..max_index-1], as returned by dict_value_index,
231
 * return the key and value, as returned by dict_next.
232
 * If the index designates an unoccupied entry, return gs_error_undefined.
233
 */
234
int dict_index_entry(const ref * pdref, int index, ref * eltp);
235
236
/*
237
 * The following are some internal details that are used in both the
238
 * implementation and some high-performance clients.
239
 */
240
241
/* On machines with reasonable amounts of memory, we round up dictionary
242
 * sizes to the next power of 2 whenever possible, to allow us to use
243
 * masking rather than division for computing the hash index.
244
 * Unfortunately, if we required this, it would cut the maximum size of a
245
 * dictionary in half.  Therefore, on such machines, we distinguish
246
 * "huge" dictionaries (dictionaries whose size is larger than the largest
247
 * power of 2 less than dict_max_size) as a special case:
248
 *
249
 *      - If the top dictionary on the stack is huge, we set the dtop
250
 *      parameters so that the fast inline lookup will always fail.
251
 *
252
 *      - For general lookup, we use the slower hash_mod algorithm for
253
 *      huge dictionaries.
254
 */
255
58.6G
#define dict_max_non_huge ((uint)(max_array_size / 2 + 1))
256
257
/* Define the hashing function for names. */
258
/* We don't have to scramble the index, because */
259
/* indices are assigned in a scattered order (see name_ref in iname.c). */
260
10.0G
#define dict_name_index_hash(nidx) (nidx)
261
262
/* Hash an arbitrary non-negative or unsigned integer into a dictionary. */
263
0
#define dict_hash_mod_rem(hash, size) ((hash) % (size))
264
41.2G
#define dict_hash_mod_mask(hash, size) ((hash) & ((size) - 1))
265
#define dict_hash_mod_small(hash, size) dict_hash_mod_rem(hash, size)
266
#define dict_hash_mod_inline_small(hash, size) dict_hash_mod_rem(hash, size)
267
#define dict_hash_mod_large(hash, size)\
268
29.2G
  (size > dict_max_non_huge ? dict_hash_mod_rem(hash, size) :\
269
29.2G
   dict_hash_mod_mask(hash, size))
270
11.9G
#define dict_hash_mod_inline_large(hash, size) dict_hash_mod_mask(hash, size)
271
/* Round up the requested size of a dictionary.  Return 0 if too big. */
272
uint dict_round_size_small(uint rsize);
273
uint dict_round_size_large(uint rsize);
274
275
/* Choose the algorithms depending on the size of memory. */
276
#if ARCH_SMALL_MEMORY
277
#  define dict_hash_mod(h, s) dict_hash_mod_small(h, s)
278
#  define dict_hash_mod_inline(h, s) dict_hash_mod_inline_small(h, s)
279
#  define dict_round_size(s) dict_round_size_small(s)
280
#else
281
#  ifdef DEBUG
282
#    define dict_hash_mod(h, s)\
283
       (gs_debug_c('.') ? dict_hash_mod_small(h, s) :\
284
        dict_hash_mod_large(h, s))
285
#    define dict_hash_mod_inline(h, s)\
286
       (gs_debug_c('.') ? dict_hash_mod_inline_small(h, s) :\
287
        dict_hash_mod_inline_large(h, s))
288
#    define dict_round_size(s)\
289
       (gs_debug_c('.') ? dict_round_size_small(s) :\
290
        dict_round_size_large(s))
291
#  else
292
29.2G
#    define dict_hash_mod(h, s) dict_hash_mod_large(h, s)
293
11.9G
#    define dict_hash_mod_inline(h, s) dict_hash_mod_inline_large(h, s)
294
243M
#    define dict_round_size(s) dict_round_size_large(s)
295
#  endif
296
#endif
297
298
#endif /* idict_INCLUDED */