Coverage Report

Created: 2022-10-31 07:00

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