Coverage Report

Created: 2022-10-31 07:00

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