Coverage Report

Created: 2025-06-24 07:01

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