Coverage Report

Created: 2022-10-31 07:00

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