Coverage Report

Created: 2025-06-10 06:49

/src/ghostpdl/psi/zmisc2.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
/* Miscellaneous Level 2 operators */
18
#include "memory_.h"
19
#include "string_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "estack.h"
23
#include "iddict.h"
24
#include "idparam.h"
25
#include "iparam.h"
26
#include "dstack.h"
27
#include "ilevel.h"
28
#include "iname.h"
29
#include "iutil2.h"
30
#include "ivmspace.h"
31
#include "store.h"
32
33
/* Forward references */
34
static int set_language_level(i_ctx_t *, int);
35
36
/* ------ Language level operators ------ */
37
38
/* - .languagelevel <int> */
39
static int
40
zlanguagelevel(i_ctx_t *i_ctx_p)
41
16.9k
{
42
16.9k
    os_ptr op = osp;
43
44
16.9k
    push(1);
45
16.9k
    make_int(op, LANGUAGE_LEVEL);
46
16.9k
    return 0;
47
16.9k
}
48
49
/* <int> .setlanguagelevel - */
50
static int
51
zsetlanguagelevel(i_ctx_t *i_ctx_p)
52
322k
{
53
322k
    os_ptr op = osp;
54
322k
    int code = 0;
55
56
322k
    check_op(1);
57
322k
    check_type(*op, t_integer);
58
322k
    if (op->value.intval != LANGUAGE_LEVEL) {
59
244k
        code = set_language_level(i_ctx_p, (int)op->value.intval);
60
244k
        if (code < 0)
61
0
            return code;
62
244k
    }
63
322k
    LANGUAGE_LEVEL = op->value.intval;
64
322k
    pop(1);
65
322k
    return code;
66
322k
}
67
68
/* ------ Initialization procedure ------ */
69
70
/* The level setting ops are recognized even in Level 1 mode. */
71
const op_def zmisc2_op_defs[] =
72
{
73
    {"0.languagelevel", zlanguagelevel},
74
    {"1.setlanguagelevel", zsetlanguagelevel},
75
    op_def_end(0)
76
};
77
78
/* ------ Internal procedures ------ */
79
80
/*
81
 * Adjust the interpreter for a change in language level.
82
 * This is used for the .setlanguagelevel operator,
83
 * and (perhaps someday) after a restore.
84
 */
85
static int swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name);
86
static int swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict,
87
                       ref * pdict2);
88
static int
89
set_language_level(i_ctx_t *i_ctx_p, int new_level)
90
244k
{
91
244k
    int old_level = LANGUAGE_LEVEL;
92
244k
    ref *pgdict =   /* globaldict, if present */
93
244k
        ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
94
244k
    ref *level2dict;
95
244k
    int code = 0;
96
97
244k
    if (new_level < 1 ||
98
244k
        new_level >
99
244k
        (dict_find_string(systemdict, "ll3dict", &level2dict) > 0 ? 3 : 2)
100
244k
        )
101
0
        return_error(gs_error_rangecheck);
102
244k
    if (dict_find_string(systemdict, "level2dict", &level2dict) <= 0)
103
0
        return_error(gs_error_undefined);
104
    /*
105
     * As noted in dstack.h, we allocate the extra d-stack entry for
106
     * globaldict even in Level 1 mode; in Level 1 mode, this entry
107
     * holds an extra copy of systemdict, and [count]dictstack omit the
108
     * very bottommost entry.
109
     */
110
366k
    while (new_level != old_level) {
111
244k
        switch (old_level) {
112
122k
            case 1: {   /* 1 => 2 or 3 */
113
                                /* Put globaldict in the dictionary stack. */
114
122k
                ref *pdict;
115
116
                /*
117
                 * This might be called so early in initialization that
118
                 * globaldict hasn't been defined yet.  If so, just skip
119
                 * this step.
120
                 */
121
122k
                code = dict_find_string(level2dict, "globaldict", &pdict);
122
122k
                if (code > 0) {
123
113k
                    if (!r_has_type(pdict, t_dictionary))
124
0
                        return_error(gs_error_typecheck);
125
113k
                    if (pgdict == NULL)
126
0
                        return_error(gs_error_stackunderflow);
127
113k
                    *pgdict = *pdict;
128
113k
                }
129
                /* Set other flags for Level 2 operation. */
130
122k
                imemory->gs_lib_ctx->dict_auto_expand = true;
131
122k
                }
132
0
                code = swap_level_dict(i_ctx_p, "level2dict");
133
122k
                if (code < 0)
134
0
                    return code;
135
122k
                ++old_level;
136
122k
                continue;
137
0
            case 3:   /* 3 => 1 or 2 */
138
0
                code = swap_level_dict(i_ctx_p, "ll3dict");
139
0
                if (code < 0)
140
0
                    return code;
141
0
                --old_level;
142
0
                continue;
143
122k
            default:    /* 2 => 1 or 3 */
144
122k
                break;
145
244k
        }
146
122k
        switch (new_level) {
147
113k
            case 1: {   /* 2 => 1 */
148
                /*
149
                 * Clear the cached definition pointers of all names defined
150
                 * in globaldict.  This will slow down future lookups, but
151
                 * we don't care.
152
                 */
153
113k
                int index = 0;
154
113k
                ref elt[2];
155
156
113k
                if (pgdict == NULL)
157
0
                    return_error(gs_error_stackunderflow);
158
113k
                index = dict_first(pgdict);
159
160
6.67M
                while ((index = dict_next(pgdict, index, &elt[0])) >= 0)
161
6.56M
                    if (r_has_type(&elt[0], t_name))
162
6.56M
                        name_invalidate_value_cache(imemory, &elt[0]);
163
                /* Overwrite globaldict in the dictionary stack. */
164
113k
                *pgdict = *systemdict;
165
                /* Set other flags for Level 1 operation. */
166
113k
                imemory->gs_lib_ctx->dict_auto_expand = false;
167
113k
                }
168
0
                code = swap_level_dict(i_ctx_p, "level2dict");
169
113k
                break;
170
8.71k
            case 3:   /* 2 => 3 */
171
8.71k
                code = swap_level_dict(i_ctx_p, "ll3dict");
172
8.71k
                break;
173
0
            default:    /* not possible */
174
0
                return_error(gs_error_Fatal);
175
122k
        }
176
122k
        break;
177
122k
    }
178
244k
    dict_set_top();   /* reload dict stack cache */
179
244k
    return code;
180
244k
}
181
182
/*
183
 * Swap the contents of a level dictionary (level2dict or ll3dict) and
184
 * systemdict.  If a value in the level dictionary is itself a dictionary,
185
 * and it contains a key/value pair referring to itself, swap its contents
186
 * with the contents of the same dictionary in systemdict.  (This is a hack
187
 * to swap the contents of statusdict.)
188
 */
189
static int
190
swap_level_dict(i_ctx_t *i_ctx_p, const char *dict_name)
191
244k
{
192
244k
    ref *pleveldict;
193
244k
    ref rleveldict;
194
244k
    int index;
195
244k
    ref elt[2];     /* key, value */
196
244k
    ref *psubdict;
197
198
    /*
199
     * We have to copy the refs for leveldict and subdict, since they may
200
     * move if their containing dictionary is resized.
201
     */
202
244k
    if (dict_find_string(systemdict, dict_name, &pleveldict) <= 0)
203
0
        return_error(gs_error_undefined);
204
244k
    rleveldict = *pleveldict;
205
244k
    index = dict_first(&rleveldict);
206
39.6M
    while ((index = dict_next(&rleveldict, index, &elt[0])) >= 0)
207
39.3M
        if (r_has_type(&elt[1], t_dictionary) &&
208
39.3M
            dict_find(&elt[1], &elt[0], &psubdict) > 0 &&
209
39.3M
            obj_eq(imemory, &elt[1], psubdict)
210
39.3M
            ) {
211
            /* elt[1] is the 2nd-level sub-dictionary */
212
217k
            int isub = dict_first(&elt[1]);
213
217k
            ref subelt[2];
214
217k
            int found = dict_find(systemdict, &elt[0], &psubdict);
215
217k
            ref rsubdict;
216
217
217k
            if (found <= 0)
218
0
                continue;
219
217k
            rsubdict = *psubdict;
220
4.79M
            while ((isub = dict_next(&elt[1], isub, &subelt[0])) >= 0)
221
4.57M
                if (!obj_eq(imemory, &subelt[0], &elt[0])) {
222
                    /* don't swap dict itself */
223
4.35M
                    int code = swap_entry(i_ctx_p, subelt, &rsubdict, &elt[1]);
224
225
4.35M
                    if (code < 0)
226
0
                        return code;
227
4.35M
                }
228
39.1M
        } else {
229
39.1M
            int code = swap_entry(i_ctx_p, elt, systemdict, &rleveldict);
230
231
39.1M
            if (code < 0)
232
0
                return code;
233
39.1M
        }
234
244k
    return 0;
235
244k
}
236
237
/*
238
 * Swap an entry from a higher level dictionary into a base dictionary.
239
 * elt[0] is the key, elt[1] is the current value in the Level 2 dictionary
240
 * (*pdict2).
241
 */
242
static int
243
swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict, ref * pdict2)
244
43.5M
{
245
43.5M
    ref *pvalue;
246
43.5M
#ifdef PACIFY_VALGRIND
247
43.5M
    ref old_value = { 0 };    /* current value in *pdict */
248
#else
249
    ref old_value;    /* current value in *pdict */
250
#endif
251
43.5M
    int found = dict_find(pdict, &elt[0], &pvalue);
252
253
43.5M
    switch (found) {
254
0
        default:    /* <0, error */
255
            /*
256
             * The only possible error here is a dictfull error, which is
257
             * harmless.
258
             */
259
            /* fall through */
260
18.0M
        case 0:   /* missing */
261
18.0M
            make_null(&old_value);
262
18.0M
            break;
263
25.5M
        case 1:   /* present */
264
25.5M
            old_value = *pvalue;
265
43.5M
    }
266
    /*
267
     * Temporarily flag the dictionaries as local, so that we don't
268
     * get invalidaccess errors.  (We know that they are both
269
     * referenced from systemdict, so they are allowed to reference
270
     * local objects even if they are global.)
271
     */
272
43.5M
    {
273
43.5M
        uint space2 = r_space(pdict2);
274
43.5M
        int code;
275
276
43.5M
        r_set_space(pdict2, avm_local);
277
43.5M
        idict_put(pdict2, &elt[0], &old_value);
278
43.5M
        if (r_has_type(&elt[1], t_null)) {
279
16.4M
            code = idict_undef(pdict, &elt[0]);
280
16.4M
            if (code == gs_error_undefined &&
281
16.4M
                r_has_type(&old_value, t_null)
282
16.4M
                )
283
0
                code = 0;
284
27.1M
        } else {
285
27.1M
            uint space = r_space(pdict);
286
287
27.1M
            r_set_space(pdict, avm_local);
288
27.1M
            code = idict_put(pdict, &elt[0], &elt[1]);
289
27.1M
            r_set_space(pdict, space);
290
27.1M
        }
291
43.5M
        r_set_space(pdict2, space2);
292
43.5M
        return code;
293
43.5M
    }
294
43.5M
}