Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/psi/zstack.c
Line
Count
Source
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
/* Operand stack operators */
18
#include "memory_.h"
19
#include "ghost.h"
20
#include "ialloc.h"
21
#include "istack.h"
22
#include "oper.h"
23
#include "store.h"
24
25
/* <obj> pop - */
26
int
27
zpop(i_ctx_t *i_ctx_p)
28
186k
{
29
186k
    os_ptr op = osp;
30
31
186k
    check_op(1);
32
186k
    pop(1);
33
186k
    return 0;
34
186k
}
35
36
/* <obj1> <obj2> exch <obj2> <obj1> */
37
int
38
zexch(i_ctx_t *i_ctx_p)
39
9.47k
{
40
9.47k
    os_ptr op = osp;
41
9.47k
    ref next;
42
43
9.47k
    check_op(2);
44
9.47k
    ref_assign_inline(&next, op - 1);
45
9.47k
    ref_assign_inline(op - 1, op);
46
9.47k
    ref_assign_inline(op, &next);
47
9.47k
    return 0;
48
9.47k
}
49
50
/* <obj> dup <obj> <obj> */
51
int
52
zdup(i_ctx_t *i_ctx_p)
53
31
{
54
31
    os_ptr op = osp;
55
56
31
    check_op(1);
57
31
    push(1);
58
31
    ref_assign_inline(op, op - 1);
59
31
    return 0;
60
31
}
61
62
/* <obj_n> ... <obj_0> <n> index <obj_n> ... <obj_0> <obj_n> */
63
int
64
zindex(i_ctx_t *i_ctx_p)
65
3.51G
{
66
3.51G
    os_ptr op = osp;
67
3.51G
    register os_ptr opn;
68
69
3.51G
    check_op(1);
70
3.51G
    check_type(*op, t_integer);
71
3.51G
    if ((ulong)op->value.intval >= (ulong)(op - osbot)) {
72
        /* Might be in an older stack block. */
73
12.5k
        ref *elt;
74
75
12.5k
        if (op->value.intval < 0)
76
12
            return_error(gs_error_rangecheck);
77
12.5k
        elt = ref_stack_index(&o_stack, op->value.intval + 1);
78
12.5k
        if (elt == 0)
79
61
            return_error(gs_error_stackunderflow);
80
12.4k
        ref_assign(op, elt);
81
12.4k
        return 0;
82
12.5k
    }
83
3.51G
    opn = op + ~(int)op->value.intval;
84
3.51G
    ref_assign_inline(op, opn);
85
3.51G
    return 0;
86
3.51G
}
87
88
/* <obj_n> ... <obj_0> <n> .argindex <obj_n> ... <obj_0> <obj_n> */
89
static int
90
zargindex(i_ctx_t *i_ctx_p)
91
302M
{
92
302M
    int code = zindex(i_ctx_p);
93
94
    /*
95
     * Pseudo-operators should use .argindex rather than index to access
96
     * their arguments on the stack, so that if there aren't enough, the
97
     * result will be a stackunderflow rather than a rangecheck.  (This is,
98
     * in fact, the only reason this operator exists.)
99
     */
100
302M
    if (code == gs_error_rangecheck && osp->value.intval >= 0)
101
0
        code = gs_note_error(gs_error_stackunderflow);
102
302M
    return code;
103
302M
}
104
105
/* <obj_n-1> ... <obj_0> <n> <i> roll */
106
/*      <obj_(i-1)_mod_ n> ... <obj_0> <obj_n-1> ... <obj_i_mod_n> */
107
int
108
zroll(i_ctx_t *i_ctx_p)
109
2.14G
{
110
2.14G
    os_ptr op = osp;
111
2.14G
    os_ptr op1 = op - 1;
112
2.14G
    int count, mod;
113
2.14G
    register os_ptr from, to;
114
2.14G
    register int n;
115
116
2.14G
    check_type(*op1, t_integer);
117
2.14G
    check_type(*op, t_integer);
118
2.14G
    if ((uint) op1->value.intval > (uint)(op1 - osbot)) {
119
        /*
120
         * The data might span multiple stack blocks.
121
         * There are efficient ways to handle this situation,
122
         * but they're more complicated than seems worth implementing;
123
         * for now, do something very simple and inefficient.
124
         */
125
289
        int left, i;
126
127
289
        if (op1->value.intval < 0)
128
38
            return_error(gs_error_rangecheck);
129
251
        if (op1->value.intval + 2 > (int)ref_stack_count(&o_stack))
130
108
            return_error(gs_error_stackunderflow);
131
143
        count = op1->value.intval;
132
143
        if (count <= 1) {
133
91
            pop(2);
134
91
            return 0;
135
91
        }
136
52
        mod = op->value.intval;
137
52
        if (mod >= count)
138
0
            mod %= count;
139
52
        else if (mod < 0) {
140
4
            mod %= count;
141
4
            if (mod < 0)
142
4
                mod += count; /* can't assume % means mod! */
143
4
        }
144
        /* Use the chain rotation algorithm mentioned below. */
145
108
        for (i = 0, left = count; left; i++) {
146
56
            ref *elt = ref_stack_index(&o_stack, i + 2);
147
56
            ref save;
148
56
            int j, k;
149
56
            ref *next;
150
151
56
            if (elt == NULL)
152
0
                return_error(gs_error_stackunderflow);
153
56
            save = *elt;
154
7.47k
            for (j = i, left--;; j = k, elt = next, left--) {
155
7.47k
                k = (j + mod) % count;
156
7.47k
                if (k == i)
157
56
                    break;
158
7.41k
                next = ref_stack_index(&o_stack, k + 2);
159
7.41k
                if (next == NULL)
160
0
                    return_error(gs_error_stackunderflow);
161
7.41k
                ref_assign(elt, next);
162
7.41k
            }
163
56
            *elt = save;
164
56
        }
165
52
        pop(2);
166
52
        return 0;
167
52
    }
168
2.14G
    count = op1->value.intval;
169
2.14G
    if (count <= 1) {
170
18.5k
        pop(2);
171
18.5k
        return 0;
172
18.5k
    }
173
2.14G
    mod = op->value.intval;
174
    /*
175
     * The elegant approach, requiring no extra space, would be to
176
     * rotate the elements in chains separated by mod elements.
177
     * Instead, we simply check to make sure there is enough space
178
     * above op to do the roll in two block moves.
179
     * Unfortunately, we can't count on memcpy doing the right thing
180
     * in *either* direction.
181
     */
182
2.14G
    switch (mod) {
183
1.05G
        case 1:   /* common special case */
184
1.05G
            pop(2);
185
1.05G
            op -= 2;
186
1.05G
            {
187
1.05G
                ref top;
188
189
1.05G
                ref_assign_inline(&top, op);
190
3.28G
                for (from = op, n = count; --n; from--)
191
2.23G
                    ref_assign_inline(from, from - 1);
192
1.05G
                ref_assign_inline(from, &top);
193
1.05G
            }
194
1.05G
            return 0;
195
974M
        case -1:    /* common special case */
196
974M
            pop(2);
197
974M
            op -= 2;
198
974M
            {
199
974M
                ref bot;
200
201
974M
                to = op - count + 1;
202
974M
                ref_assign_inline(&bot, to);
203
3.69G
                for (n = count; --n; to++)
204
2.72G
                    ref_assign(to, to + 1);
205
974M
                ref_assign_inline(to, &bot);
206
974M
            }
207
974M
            return 0;
208
2.14G
    }
209
107M
    if (mod < 0) {
210
15.9M
        mod += count;
211
15.9M
        if (mod < 0) {
212
167
            mod %= count;
213
167
            if (mod < 0)
214
101
                mod += count; /* can't assume % means mod! */
215
167
        }
216
91.4M
    } else if (mod >= count)
217
35
        mod %= count;
218
107M
    if (mod <= count >> 1) {
219
        /* Move everything up, then top elements down. */
220
95.6M
        if (mod >= ostop - op) {
221
34
            o_stack.requested = mod;
222
34
            return_error(gs_error_stackoverflow);
223
34
        }
224
95.6M
        pop(2);
225
95.6M
        op -= 2;
226
625M
        for (to = op + mod, from = op, n = count; n--; to--, from--)
227
529M
            ref_assign(to, from);
228
95.6M
        memcpy((char *)(from + 1), (char *)(op + 1), mod * sizeof(ref));
229
95.6M
    } else {
230
        /* Move bottom elements up, then everything down. */
231
11.7M
        mod = count - mod;
232
11.7M
        if (mod >= ostop - op) {
233
6
            o_stack.requested = mod;
234
6
            return_error(gs_error_stackoverflow);
235
6
        }
236
11.7M
        pop(2);
237
11.7M
        op -= 2;
238
11.7M
        to = op - count + 1;
239
11.7M
        memcpy((char *)(op + 1), (char *)to, mod * sizeof(ref));
240
53.9M
        for (from = to + mod, n = count; n--; to++, from++)
241
42.2M
            ref_assign(to, from);
242
11.7M
    }
243
107M
    return 0;
244
107M
}
245
246
/* |- ... clear |- */
247
/* The function name is changed, because the IRIS library has */
248
/* a function called zclear. */
249
static int
250
zclear_stack(i_ctx_t *i_ctx_p)
251
10.4k
{
252
10.4k
    ref_stack_clear(&o_stack);
253
10.4k
    return 0;
254
10.4k
}
255
256
/* |- <obj_n-1> ... <obj_0> count <obj_n-1> ... <obj_0> <n> */
257
static int
258
zcount(i_ctx_t *i_ctx_p)
259
5.89M
{
260
5.89M
    os_ptr op = osp;
261
262
5.89M
    push(1);
263
5.89M
    make_int(op, ref_stack_count(&o_stack) - 1);
264
5.89M
    return 0;
265
5.89M
}
266
267
/* - mark <mark> */
268
static int
269
zmark(i_ctx_t *i_ctx_p)
270
1.07G
{
271
1.07G
    os_ptr op = osp;
272
273
1.07G
    push(1);
274
1.07G
    make_mark(op);
275
1.07G
    return 0;
276
1.07G
}
277
278
/* <mark> ... cleartomark */
279
int
280
zcleartomark(i_ctx_t *i_ctx_p)
281
219M
{
282
219M
    uint count = ref_stack_counttomark(&o_stack);
283
284
219M
    if (count == 0)
285
14
        return_error(gs_error_unmatchedmark);
286
219M
    ref_stack_pop(&o_stack, count);
287
219M
    return 0;
288
219M
}
289
290
/* <mark> <obj_n-1> ... <obj_0> counttomark */
291
/*      <mark> <obj_n-1> ... <obj_0> <n> */
292
static int
293
zcounttomark(i_ctx_t *i_ctx_p)
294
1.04G
{
295
1.04G
    os_ptr op = osp;
296
1.04G
    uint count = ref_stack_counttomark(&o_stack);
297
298
1.04G
    if (count == 0)
299
205
        return_error(gs_error_unmatchedmark);
300
1.04G
    push(1);
301
1.04G
    make_int(op, count - 1);
302
1.04G
    return 0;
303
1.04G
}
304
305
/* ------ Initialization procedure ------ */
306
307
const op_def zstack_op_defs[] =
308
{
309
    {"2.argindex", zargindex},
310
    {"0clear", zclear_stack},
311
    {"0cleartomark", zcleartomark},
312
    {"0count", zcount},
313
    {"0counttomark", zcounttomark},
314
    {"1dup", zdup},
315
    {"2exch", zexch},
316
    {"2index", zindex},
317
    {"0mark", zmark},
318
    {"1pop", zpop},
319
    {"2roll", zroll},
320
    op_def_end(0)
321
};