Coverage Report

Created: 2025-06-10 07:26

/src/ghostpdl/psi/zdevice2.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
/* Level 2 device operators */
18
#include "math_.h"
19
#include "memory_.h"
20
#include "ghost.h"
21
#include "oper.h"
22
#include "dstack.h"   /* for dict_find_name */
23
#include "estack.h"
24
#include "idict.h"
25
#include "idparam.h"
26
#include "igstate.h"
27
#include "iname.h"
28
#include "iutil.h"
29
#include "isave.h"
30
#include "store.h"
31
#include "gxdevice.h"
32
#include "gsstate.h"
33
34
/* Exported for zfunc4.c */
35
int z2copy(i_ctx_t *);
36
37
/* Forward references */
38
static int z2copy_gstate(i_ctx_t *);
39
static int push_callout(i_ctx_t *, const char *);
40
41
/* Extend the `copy' operator to deal with gstates. */
42
/* This is done with a hack -- we know that gstates are the only */
43
/* t_astruct subtype that implements copy. */
44
/* We export this for recognition in FunctionType 4 functions. */
45
int
46
z2copy(i_ctx_t *i_ctx_p)
47
25.4M
{
48
25.4M
    os_ptr op = osp;
49
25.4M
    int code = zcopy(i_ctx_p);
50
51
25.4M
    if (code >= 0)
52
25.4M
        return code;
53
0
    if (!r_has_type(op, t_astruct))
54
0
        return code;
55
0
    return z2copy_gstate(i_ctx_p);
56
0
}
57
58
/* - .currentshowpagecount <count> true */
59
/* - .currentshowpagecount false */
60
static int
61
zcurrentshowpagecount(i_ctx_t *i_ctx_p)
62
109k
{
63
109k
    os_ptr op = osp;
64
109k
    gx_device *dev1, *dev = gs_currentdevice(igs);
65
66
109k
    if ((*dev_proc(dev, get_page_device))(dev) == 0) {
67
0
        push(1);
68
0
        make_false(op);
69
109k
    } else {
70
109k
        dev1 = (*dev_proc(dev, get_page_device))(dev);
71
109k
        push(2);
72
109k
        make_int(op - 1, dev1->ShowpageCount);
73
109k
        make_true(op);
74
109k
    }
75
109k
    return 0;
76
109k
}
77
78
/* - .currentpagedevice <dict> <bool> */
79
static int
80
zcurrentpagedevice(i_ctx_t *i_ctx_p)
81
299k
{
82
299k
    os_ptr op = osp;
83
299k
    gx_device *dev = gs_currentdevice(igs);
84
85
299k
    push(2);
86
299k
    if ((*dev_proc(dev, get_page_device))(dev) != 0) {
87
299k
        op[-1] = istate->pagedevice;
88
299k
        make_true(op);
89
299k
    } else {
90
0
        make_null(op - 1);
91
0
        make_false(op);
92
0
    }
93
299k
    return 0;
94
299k
}
95
96
/* <local_dict|null> .setpagedevice - */
97
static int
98
zsetpagedevice(i_ctx_t *i_ctx_p)
99
130k
{
100
130k
    os_ptr op = osp;
101
130k
    int code;
102
103
130k
    check_op(1);
104
/******
105
    if ( igs->in_cachedevice )
106
        return_error(gs_error_undefined);
107
 ******/
108
130k
    if (r_has_type(op, t_dictionary)) {
109
130k
        check_dict_read(*op);
110
#if 0 /****************/
111
        /*
112
         * In order to avoid invalidaccess errors on setpagedevice,
113
         * the dictionary must be allocated in local VM.
114
         */
115
        if (!(r_is_local(op)))
116
            return_error(gs_error_invalidaccess);
117
#endif  /****************/
118
        /* Make the dictionary read-only. */
119
130k
        code = zreadonly(i_ctx_p);
120
130k
        if (code < 0)
121
0
            return code;
122
130k
    } else {
123
0
        check_type(*op, t_null);
124
0
    }
125
130k
    istate->pagedevice = *op;
126
130k
    pop(1);
127
130k
    return 0;
128
130k
}
129
130
/* Default Install/BeginPage/EndPage procedures */
131
/* that just call the procedure in the device. */
132
133
/* - .callinstall - */
134
static int
135
zcallinstall(i_ctx_t *i_ctx_p)
136
31.6k
{
137
31.6k
    gx_device *dev = gs_currentdevice(igs);
138
139
31.6k
    if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
140
31.6k
        int code = (*dev->page_procs.install) (dev, igs);
141
142
31.6k
        if (code < 0)
143
0
            return code;
144
31.6k
    }
145
31.6k
    return 0;
146
31.6k
}
147
148
/* <showpage_count> .callbeginpage - */
149
static int
150
zcallbeginpage(i_ctx_t *i_ctx_p)
151
50.2k
{
152
50.2k
    os_ptr op = osp;
153
50.2k
    gx_device *dev = gs_currentdevice(igs);
154
155
50.2k
    check_op(1);
156
50.2k
    check_type(*op, t_integer);
157
50.2k
    if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
158
50.2k
        int code = (*dev->page_procs.begin_page)(dev, igs);
159
160
50.2k
        if (code < 0)
161
0
            return code;
162
50.2k
    }
163
50.2k
    pop(1);
164
50.2k
    return 0;
165
50.2k
}
166
167
/* <showpage_count> <reason_int> .callendpage <flush_bool> */
168
static int
169
zcallendpage(i_ctx_t *i_ctx_p)
170
59.5k
{
171
59.5k
    os_ptr op = osp;
172
59.5k
    gx_device *dev = gs_currentdevice(igs);
173
59.5k
    int code;
174
175
59.5k
    check_op(2);
176
59.5k
    check_type(op[-1], t_integer);
177
59.5k
    check_type(*op, t_integer);
178
59.5k
    if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
179
59.5k
        code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
180
59.5k
        if (code < 0)
181
0
            return code;
182
59.5k
        if (code > 1)
183
0
            return_error(gs_error_rangecheck);
184
59.5k
    } else {
185
0
        code = (op->value.intval == 2 ? 0 : 1);
186
0
    }
187
59.5k
    make_bool(op - 1, code);
188
59.5k
    pop(1);
189
59.5k
    return 0;
190
59.5k
}
191
192
/* ------ Wrappers for operators that save the graphics state. ------ */
193
194
/* When saving the state with the current device a page device, */
195
/* we need to make sure that the page device dictionary exists */
196
/* so that grestore can use it to reset the device parameters. */
197
/* This may have significant performance consequences, but we don't see */
198
/* any way around it. */
199
200
/* Check whether we need to call out to create the page device dictionary. */
201
static bool
202
save_page_device(gs_gstate *pgs)
203
46.1k
{
204
46.1k
    return
205
46.1k
        (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
206
46.1k
         (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
207
46.1k
}
208
209
/* - gsave - */
210
static int
211
z2gsave(i_ctx_t *i_ctx_p)
212
18.4k
{
213
18.4k
    if (!save_page_device(igs))
214
9.22k
        return gs_gsave(igs);
215
9.22k
    return push_callout(i_ctx_p, "%gsavepagedevice");
216
18.4k
}
217
218
/* - save - */
219
static int
220
z2save(i_ctx_t *i_ctx_p)
221
27.6k
{
222
27.6k
    if (!save_page_device(igs))
223
18.4k
        return zsave(i_ctx_p);
224
9.22k
    return push_callout(i_ctx_p, "%savepagedevice");
225
27.6k
}
226
227
/* - gstate <gstate> */
228
static int
229
z2gstate(i_ctx_t *i_ctx_p)
230
0
{
231
0
    if (!save_page_device(igs))
232
0
        return zgstate(i_ctx_p);
233
0
    return push_callout(i_ctx_p, "%gstatepagedevice");
234
0
}
235
236
/* <gstate1> <gstate2> copy <gstate2> */
237
static int
238
z2copy_gstate(i_ctx_t *i_ctx_p)
239
0
{
240
0
    os_ptr op = osp;
241
0
    check_op(2);
242
0
    if (!save_page_device(igs))
243
0
        return zcopy_gstate(i_ctx_p);
244
0
    return push_callout(i_ctx_p, "%copygstatepagedevice");
245
0
}
246
247
/* <gstate> currentgstate <gstate> */
248
static int
249
z2currentgstate(i_ctx_t *i_ctx_p)
250
0
{
251
0
    os_ptr op = osp;
252
0
    check_op(1);
253
0
    if (!save_page_device(igs))
254
0
        return zcurrentgstate(i_ctx_p);
255
0
    return push_callout(i_ctx_p, "%currentgstatepagedevice");
256
0
}
257
258
/* ------ Wrappers for operators that reset the graphics state. ------ */
259
260
/* Check whether we need to call out to restore the page device. */
261
static int
262
restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate * pgs_new)
263
16.6k
{
264
16.6k
    gx_device *dev_old = gs_currentdevice(pgs_old);
265
16.6k
    gx_device *dev_new;
266
16.6k
    gx_device *dev_t1;
267
16.6k
    gx_device *dev_t2;
268
16.6k
    bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
269
16.6k
        &gs_int_gstate(pgs_new)->pagedevice);
270
16.6k
    bool LockSafetyParams = dev_old->LockSafetyParams;
271
272
16.6k
    if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
273
7.46k
        return 0;
274
    /* If we are going to putdeviceparams in a callout, we need to */
275
    /* unlock temporarily.  The device will be re-locked as needed */
276
    /* by putdeviceparams from the pgs_old->pagedevice dict state. */
277
9.17k
    if (!samepagedevice)
278
7.46k
        dev_old->LockSafetyParams = false;
279
9.17k
    dev_new = gs_currentdevice(pgs_new);
280
9.17k
    if (dev_old != dev_new) {
281
0
        if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
282
0
            samepagedevice = true;
283
0
        else if (dev_t1 != dev_t2)
284
0
            samepagedevice = false;
285
0
    }
286
287
9.17k
    if (LockSafetyParams) {
288
0
        const int required_ops = 512;
289
0
        const int required_es = 32;
290
291
        /* The %grestorepagedevice must complete: the biggest danger
292
           is operand stack overflow. As we use get/putdeviceparams
293
           that means pushing all the device params onto the stack,
294
           pdfwrite having by far the largest number of parameters
295
           at (currently) 212 key/value pairs - thus needing (currently)
296
           424 entries on the op stack. Allowing for working stack
297
           space, and safety margin.....
298
         */
299
0
        if (required_ops + ref_stack_count(&o_stack) >= ref_stack_max_count(&o_stack)) {
300
0
           gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
301
0
           return_error(gs_error_stackoverflow);
302
0
        }
303
        /* We also want enough exec stack space - 32 is an overestimate of
304
           what we need to complete the Postscript call out.
305
         */
306
0
        if (required_es + ref_stack_count(&e_stack) >= ref_stack_max_count(&e_stack)) {
307
0
           gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
308
0
           return_error(gs_error_execstackoverflow);
309
0
        }
310
0
    }
311
    /*
312
     * The current implementation of setpagedevice just sets new
313
     * parameters in the same device object, so we have to check
314
     * whether the page device dictionaries are the same.
315
     */
316
9.17k
    return samepagedevice ? 0 : 1;
317
9.17k
}
318
319
/* - grestore - */
320
static int
321
z2grestore(i_ctx_t *i_ctx_p)
322
0
{
323
0
    int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
324
0
    if (code < 0) return code;
325
326
0
    if (code == 0)
327
0
        return gs_grestore(igs);
328
0
    return push_callout(i_ctx_p, "%grestorepagedevice");
329
0
}
330
331
/* - grestoreall - */
332
static int
333
z2grestoreall(i_ctx_t *i_ctx_p)
334
0
{
335
0
    for (;;) {
336
0
        int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
337
0
        if (code < 0) return code;
338
0
        if (code == 0) {
339
0
            bool done = !gs_gstate_saved(gs_gstate_saved(igs));
340
341
0
            gs_grestore(igs);
342
0
            if (done)
343
0
                break;
344
0
        } else
345
0
            return push_callout(i_ctx_p, "%grestoreallpagedevice");
346
0
    }
347
0
    return 0;
348
0
}
349
/* This is the Level 2+ variant of restore - which adds restoring
350
   of the page device to the Level 1 variant in zvmem.c.
351
   Previous this restored the device state before calling zrestore.c
352
   which validated operands etc, meaning a restore could error out
353
   partially complete.
354
   The operand checking, and actual VM restore are now in two functions
355
   so they can called separately thus, here, we can do as much
356
   checking as possible, before embarking on actual changes
357
 */
358
/* <save> restore - */
359
static int
360
z2restore(i_ctx_t *i_ctx_p)
361
16.6k
{
362
16.6k
    alloc_save_t *asave;
363
16.6k
    bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams;
364
16.6k
    int code = restore_check_save(i_ctx_p, &asave);
365
366
16.6k
    if (code < 0) return code;
367
368
16.6k
    while (gs_gstate_saved(gs_gstate_saved(igs))) {
369
0
        code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
370
0
        if (code < 0) return code;
371
0
        if (code > 0)
372
0
            return push_callout(i_ctx_p, "%restore1pagedevice");
373
0
        gs_grestore(igs);
374
0
    }
375
16.6k
    code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
376
16.6k
    if (code < 0) return code;
377
16.6k
    if (code > 0)
378
7.46k
        return push_callout(i_ctx_p, "%restorepagedevice");
379
380
9.17k
    code = dorestore(i_ctx_p, asave);
381
382
9.17k
    if (code < 0) {
383
        /* An error here is basically fatal, but....
384
           restore_page_device() has to set LockSafetyParams false so it can
385
           configure the restored device correctly - in normal operation, that
386
           gets reset by that configuration. If we hit an error, though, that
387
           may not happen -  at least ensure we keep the setting through the
388
           error.
389
         */
390
0
        gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety;
391
0
    }
392
9.17k
    return code;
393
16.6k
}
394
395
/* <gstate> setgstate - */
396
static int
397
z2setgstate(i_ctx_t *i_ctx_p)
398
0
{
399
0
    os_ptr op = osp;
400
0
    int code;
401
402
0
    check_op(1);
403
0
    check_stype(*op, st_igstate_obj);
404
0
    code = restore_page_device(i_ctx_p, igs, igstate_ptr(op));
405
0
    if (code < 0) return code;
406
0
    if (code == 0)
407
0
        return zsetgstate(i_ctx_p);
408
0
    return push_callout(i_ctx_p, "%setgstatepagedevice");
409
0
}
410
411
/* ------ Initialization procedure ------ */
412
413
const op_def zdevice2_l2_op_defs[] =
414
{
415
    op_def_begin_level2(),
416
    {"0.currentshowpagecount", zcurrentshowpagecount},
417
    {"0.currentpagedevice", zcurrentpagedevice},
418
    {"1.setpagedevice", zsetpagedevice},
419
                /* Note that the following replace prior definitions */
420
                /* in the indicated files: */
421
    {"1copy", z2copy},    /* zdps1.c */
422
    {"0gsave", z2gsave},  /* zgstate.c */
423
    {"0save", z2save},    /* zvmem.c */
424
    {"0gstate", z2gstate},  /* zdps1.c */
425
    {"1currentgstate", z2currentgstate},  /* zdps1.c */
426
    {"0grestore", z2grestore},  /* zgstate.c */
427
    {"0grestoreall", z2grestoreall},  /* zgstate.c */
428
    {"1restore", z2restore},  /* zvmem.c */
429
    {"1setgstate", z2setgstate},  /* zdps1.c */
430
                /* Default Install/BeginPage/EndPage procedures */
431
                /* that just call the procedure in the device. */
432
    {"0.callinstall", zcallinstall},
433
    {"1.callbeginpage", zcallbeginpage},
434
    {"2.callendpage", zcallendpage},
435
    op_def_end(0)
436
};
437
438
/* ------ Internal routines ------ */
439
440
/* Call out to a PostScript procedure. */
441
static int
442
push_callout(i_ctx_t *i_ctx_p, const char *callout_name)
443
25.9k
{
444
25.9k
    int code;
445
446
25.9k
    check_estack(1);
447
25.9k
    code = name_enter_string(imemory, callout_name, esp + 1);
448
25.9k
    if (code < 0)
449
0
        return code;
450
25.9k
    ++esp;
451
25.9k
    r_set_attrs(esp, a_executable);
452
25.9k
    return o_push_estack;
453
25.9k
}