Coverage Report

Created: 2025-06-10 07:17

/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
120k
{
42
120k
    os_ptr op = osp;
43
44
120k
    push(1);
45
120k
    make_int(op, LANGUAGE_LEVEL);
46
120k
    return 0;
47
120k
}
48
49
/* <int> .setlanguagelevel - */
50
static int
51
zsetlanguagelevel(i_ctx_t *i_ctx_p)
52
353k
{
53
353k
    os_ptr op = osp;
54
353k
    int code = 0;
55
56
353k
    check_op(1);
57
353k
    check_type(*op, t_integer);
58
353k
    if (op->value.intval != LANGUAGE_LEVEL) {
59
267k
        code = set_language_level(i_ctx_p, (int)op->value.intval);
60
267k
        if (code < 0)
61
0
            return code;
62
267k
    }
63
353k
    LANGUAGE_LEVEL = op->value.intval;
64
353k
    pop(1);
65
353k
    return code;
66
353k
}
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
267k
{
91
267k
    int old_level = LANGUAGE_LEVEL;
92
267k
    ref *pgdict =   /* globaldict, if present */
93
267k
        ref_stack_index(&d_stack, ref_stack_count(&d_stack) - 2);
94
267k
    ref *level2dict;
95
267k
    int code = 0;
96
97
267k
    if (new_level < 1 ||
98
267k
        new_level >
99
267k
        (dict_find_string(systemdict, "ll3dict", &level2dict) > 0 ? 3 : 2)
100
267k
        )
101
0
        return_error(gs_error_rangecheck);
102
267k
    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
401k
    while (new_level != old_level) {
111
267k
        switch (old_level) {
112
133k
            case 1: {   /* 1 => 2 or 3 */
113
                                /* Put globaldict in the dictionary stack. */
114
133k
                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
133k
                code = dict_find_string(level2dict, "globaldict", &pdict);
122
133k
                if (code > 0) {
123
124k
                    if (!r_has_type(pdict, t_dictionary))
124
0
                        return_error(gs_error_typecheck);
125
124k
                    if (pgdict == NULL)
126
0
                        return_error(gs_error_stackunderflow);
127
124k
                    *pgdict = *pdict;
128
124k
                }
129
                /* Set other flags for Level 2 operation. */
130
133k
                imemory->gs_lib_ctx->dict_auto_expand = true;
131
133k
                }
132
0
                code = swap_level_dict(i_ctx_p, "level2dict");
133
133k
                if (code < 0)
134
0
                    return code;
135
133k
                ++old_level;
136
133k
                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
133k
            default:    /* 2 => 1 or 3 */
144
133k
                break;
145
267k
        }
146
133k
        switch (new_level) {
147
124k
            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
124k
                int index = 0;
154
124k
                ref elt[2];
155
156
124k
                if (pgdict == NULL)
157
0
                    return_error(gs_error_stackunderflow);
158
124k
                index = dict_first(pgdict);
159
160
7.32M
                while ((index = dict_next(pgdict, index, &elt[0])) >= 0)
161
7.20M
                    if (r_has_type(&elt[0], t_name))
162
7.20M
                        name_invalidate_value_cache(imemory, &elt[0]);
163
                /* Overwrite globaldict in the dictionary stack. */
164
124k
                *pgdict = *systemdict;
165
                /* Set other flags for Level 1 operation. */
166
124k
                imemory->gs_lib_ctx->dict_auto_expand = false;
167
124k
                }
168
0
                code = swap_level_dict(i_ctx_p, "level2dict");
169
124k
                break;
170
9.56k
            case 3:   /* 2 => 3 */
171
9.56k
                code = swap_level_dict(i_ctx_p, "ll3dict");
172
9.56k
                break;
173
0
            default:    /* not possible */
174
0
                return_error(gs_error_Fatal);
175
133k
        }
176
133k
        break;
177
133k
    }
178
267k
    dict_set_top();   /* reload dict stack cache */
179
267k
    return code;
180
267k
}
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
267k
{
192
267k
    ref *pleveldict;
193
267k
    ref rleveldict;
194
267k
    int index;
195
267k
    ref elt[2];     /* key, value */
196
267k
    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
267k
    if (dict_find_string(systemdict, dict_name, &pleveldict) <= 0)
203
0
        return_error(gs_error_undefined);
204
267k
    rleveldict = *pleveldict;
205
267k
    index = dict_first(&rleveldict);
206
43.4M
    while ((index = dict_next(&rleveldict, index, &elt[0])) >= 0)
207
43.2M
        if (r_has_type(&elt[1], t_dictionary) &&
208
43.2M
            dict_find(&elt[1], &elt[0], &psubdict) > 0 &&
209
43.2M
            obj_eq(imemory, &elt[1], psubdict)
210
43.2M
            ) {
211
            /* elt[1] is the 2nd-level sub-dictionary */
212
239k
            int isub = dict_first(&elt[1]);
213
239k
            ref subelt[2];
214
239k
            int found = dict_find(systemdict, &elt[0], &psubdict);
215
239k
            ref rsubdict;
216
217
239k
            if (found <= 0)
218
0
                continue;
219
239k
            rsubdict = *psubdict;
220
5.26M
            while ((isub = dict_next(&elt[1], isub, &subelt[0])) >= 0)
221
5.02M
                if (!obj_eq(imemory, &subelt[0], &elt[0])) {
222
                    /* don't swap dict itself */
223
4.78M
                    int code = swap_entry(i_ctx_p, subelt, &rsubdict, &elt[1]);
224
225
4.78M
                    if (code < 0)
226
0
                        return code;
227
4.78M
                }
228
42.9M
        } else {
229
42.9M
            int code = swap_entry(i_ctx_p, elt, systemdict, &rleveldict);
230
231
42.9M
            if (code < 0)
232
0
                return code;
233
42.9M
        }
234
267k
    return 0;
235
267k
}
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
47.7M
{
245
47.7M
    ref *pvalue;
246
47.7M
#ifdef PACIFY_VALGRIND
247
47.7M
    ref old_value = { 0 };    /* current value in *pdict */
248
#else
249
    ref old_value;    /* current value in *pdict */
250
#endif
251
47.7M
    int found = dict_find(pdict, &elt[0], &pvalue);
252
253
47.7M
    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
19.7M
        case 0:   /* missing */
261
19.7M
            make_null(&old_value);
262
19.7M
            break;
263
28.0M
        case 1:   /* present */
264
28.0M
            old_value = *pvalue;
265
47.7M
    }
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
47.7M
    {
273
47.7M
        uint space2 = r_space(pdict2);
274
47.7M
        int code;
275
276
47.7M
        r_set_space(pdict2, avm_local);
277
47.7M
        idict_put(pdict2, &elt[0], &old_value);
278
47.7M
        if (r_has_type(&elt[1], t_null)) {
279
18.0M
            code = idict_undef(pdict, &elt[0]);
280
18.0M
            if (code == gs_error_undefined &&
281
18.0M
                r_has_type(&old_value, t_null)
282
18.0M
                )
283
0
                code = 0;
284
29.7M
        } else {
285
29.7M
            uint space = r_space(pdict);
286
287
29.7M
            r_set_space(pdict, avm_local);
288
29.7M
            code = idict_put(pdict, &elt[0], &elt[1]);
289
29.7M
            r_set_space(pdict, space);
290
29.7M
        }
291
47.7M
        r_set_space(pdict2, space2);
292
47.7M
        return code;
293
47.7M
    }
294
47.7M
}