1 /* Copyright (C) 2001-2019 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
z2copy(i_ctx_t * i_ctx_p)46 z2copy(i_ctx_t *i_ctx_p)
47 {
48     os_ptr op = osp;
49     int code = zcopy(i_ctx_p);
50 
51     if (code >= 0)
52         return code;
53     if (!r_has_type(op, t_astruct))
54         return code;
55     return z2copy_gstate(i_ctx_p);
56 }
57 
58 /* - .currentshowpagecount <count> true */
59 /* - .currentshowpagecount false */
60 static int
zcurrentshowpagecount(i_ctx_t * i_ctx_p)61 zcurrentshowpagecount(i_ctx_t *i_ctx_p)
62 {
63     os_ptr op = osp;
64     gx_device *dev1, *dev = gs_currentdevice(igs);
65 
66     if ((*dev_proc(dev, get_page_device))(dev) == 0) {
67         push(1);
68         make_false(op);
69     } else {
70         dev1 = (*dev_proc(dev, get_page_device))(dev);
71         push(2);
72         make_int(op - 1, dev1->ShowpageCount);
73         make_true(op);
74     }
75     return 0;
76 }
77 
78 /* - .currentpagedevice <dict> <bool> */
79 static int
zcurrentpagedevice(i_ctx_t * i_ctx_p)80 zcurrentpagedevice(i_ctx_t *i_ctx_p)
81 {
82     os_ptr op = osp;
83     gx_device *dev = gs_currentdevice(igs);
84 
85     push(2);
86     if ((*dev_proc(dev, get_page_device))(dev) != 0) {
87         op[-1] = istate->pagedevice;
88         make_true(op);
89     } else {
90         make_null(op - 1);
91         make_false(op);
92     }
93     return 0;
94 }
95 
96 /* <local_dict|null> .setpagedevice - */
97 static int
zsetpagedevice(i_ctx_t * i_ctx_p)98 zsetpagedevice(i_ctx_t *i_ctx_p)
99 {
100     os_ptr op = osp;
101     int code;
102 
103 /******
104     if ( igs->in_cachedevice )
105         return_error(gs_error_undefined);
106  ******/
107     if (r_has_type(op, t_dictionary)) {
108         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         code = zreadonly(i_ctx_p);
119         if (code < 0)
120             return code;
121     } else {
122         check_type(*op, t_null);
123     }
124     istate->pagedevice = *op;
125     pop(1);
126     return 0;
127 }
128 
129 /* Default Install/BeginPage/EndPage procedures */
130 /* that just call the procedure in the device. */
131 
132 /* - .callinstall - */
133 static int
zcallinstall(i_ctx_t * i_ctx_p)134 zcallinstall(i_ctx_t *i_ctx_p)
135 {
136     gx_device *dev = gs_currentdevice(igs);
137 
138     if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
139         int code = (*dev->page_procs.install) (dev, igs);
140 
141         if (code < 0)
142             return code;
143     }
144     return 0;
145 }
146 
147 /* <showpage_count> .callbeginpage - */
148 static int
zcallbeginpage(i_ctx_t * i_ctx_p)149 zcallbeginpage(i_ctx_t *i_ctx_p)
150 {
151     os_ptr op = osp;
152     gx_device *dev = gs_currentdevice(igs);
153 
154     check_type(*op, t_integer);
155     if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
156         int code = (*dev->page_procs.begin_page)(dev, igs);
157 
158         if (code < 0)
159             return code;
160     }
161     pop(1);
162     return 0;
163 }
164 
165 /* <showpage_count> <reason_int> .callendpage <flush_bool> */
166 static int
zcallendpage(i_ctx_t * i_ctx_p)167 zcallendpage(i_ctx_t *i_ctx_p)
168 {
169     os_ptr op = osp;
170     gx_device *dev = gs_currentdevice(igs);
171     int code;
172 
173     check_type(op[-1], t_integer);
174     check_type(*op, t_integer);
175     if ((dev = (*dev_proc(dev, get_page_device))(dev)) != 0) {
176         code = (*dev->page_procs.end_page)(dev, (int)op->value.intval, igs);
177         if (code < 0)
178             return code;
179         if (code > 1)
180             return_error(gs_error_rangecheck);
181     } else {
182         code = (op->value.intval == 2 ? 0 : 1);
183     }
184     make_bool(op - 1, code);
185     pop(1);
186     return 0;
187 }
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
save_page_device(gs_gstate * pgs)199 save_page_device(gs_gstate *pgs)
200 {
201     return
202         (r_has_type(&gs_int_gstate(pgs)->pagedevice, t_null) &&
203          (*dev_proc(gs_currentdevice(pgs), get_page_device))(gs_currentdevice(pgs)) != 0);
204 }
205 
206 /* - gsave - */
207 static int
z2gsave(i_ctx_t * i_ctx_p)208 z2gsave(i_ctx_t *i_ctx_p)
209 {
210     if (!save_page_device(igs))
211         return gs_gsave(igs);
212     return push_callout(i_ctx_p, "%gsavepagedevice");
213 }
214 
215 /* - save - */
216 static int
z2save(i_ctx_t * i_ctx_p)217 z2save(i_ctx_t *i_ctx_p)
218 {
219     if (!save_page_device(igs))
220         return zsave(i_ctx_p);
221     return push_callout(i_ctx_p, "%savepagedevice");
222 }
223 
224 /* - gstate <gstate> */
225 static int
z2gstate(i_ctx_t * i_ctx_p)226 z2gstate(i_ctx_t *i_ctx_p)
227 {
228     if (!save_page_device(igs))
229         return zgstate(i_ctx_p);
230     return push_callout(i_ctx_p, "%gstatepagedevice");
231 }
232 
233 /* <gstate1> <gstate2> copy <gstate2> */
234 static int
z2copy_gstate(i_ctx_t * i_ctx_p)235 z2copy_gstate(i_ctx_t *i_ctx_p)
236 {
237     if (!save_page_device(igs))
238         return zcopy_gstate(i_ctx_p);
239     return push_callout(i_ctx_p, "%copygstatepagedevice");
240 }
241 
242 /* <gstate> currentgstate <gstate> */
243 static int
z2currentgstate(i_ctx_t * i_ctx_p)244 z2currentgstate(i_ctx_t *i_ctx_p)
245 {
246     if (!save_page_device(igs))
247         return zcurrentgstate(i_ctx_p);
248     return push_callout(i_ctx_p, "%currentgstatepagedevice");
249 }
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
restore_page_device(i_ctx_t * i_ctx_p,const gs_gstate * pgs_old,const gs_gstate * pgs_new)255 restore_page_device(i_ctx_t *i_ctx_p, const gs_gstate * pgs_old, const gs_gstate * pgs_new)
256 {
257     gx_device *dev_old = gs_currentdevice(pgs_old);
258     gx_device *dev_new;
259     gx_device *dev_t1;
260     gx_device *dev_t2;
261     bool samepagedevice = obj_eq(dev_old->memory, &gs_int_gstate(pgs_old)->pagedevice,
262         &gs_int_gstate(pgs_new)->pagedevice);
263     bool LockSafetyParams = dev_old->LockSafetyParams;
264 
265     if ((dev_t1 = (*dev_proc(dev_old, get_page_device)) (dev_old)) == 0)
266         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     if (!samepagedevice)
271         dev_old->LockSafetyParams = false;
272     dev_new = gs_currentdevice(pgs_new);
273     if (dev_old != dev_new) {
274         if ((dev_t2 = (*dev_proc(dev_new, get_page_device)) (dev_new)) == 0)
275             samepagedevice = true;
276         else if (dev_t1 != dev_t2)
277             samepagedevice = false;
278     }
279 
280     if (LockSafetyParams) {
281         const int required_ops = 512;
282         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         if (required_ops + ref_stack_count(&o_stack) >= ref_stack_max_count(&o_stack)) {
293            gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
294            return_error(gs_error_stackoverflow);
295         }
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         if (required_es + ref_stack_count(&e_stack) >= ref_stack_max_count(&e_stack)) {
300            gs_currentdevice(pgs_old)->LockSafetyParams = LockSafetyParams;
301            return_error(gs_error_execstackoverflow);
302         }
303     }
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     return samepagedevice ? 0 : 1;
310 }
311 
312 /* - grestore - */
313 static int
z2grestore(i_ctx_t * i_ctx_p)314 z2grestore(i_ctx_t *i_ctx_p)
315 {
316     int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
317     if (code < 0) return code;
318 
319     if (code == 0)
320         return gs_grestore(igs);
321     return push_callout(i_ctx_p, "%grestorepagedevice");
322 }
323 
324 /* - grestoreall - */
325 static int
z2grestoreall(i_ctx_t * i_ctx_p)326 z2grestoreall(i_ctx_t *i_ctx_p)
327 {
328     for (;;) {
329         int code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
330         if (code < 0) return code;
331         if (code == 0) {
332             bool done = !gs_gstate_saved(gs_gstate_saved(igs));
333 
334             gs_grestore(igs);
335             if (done)
336                 break;
337         } else
338             return push_callout(i_ctx_p, "%grestoreallpagedevice");
339     }
340     return 0;
341 }
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
z2restore(i_ctx_t * i_ctx_p)353 z2restore(i_ctx_t *i_ctx_p)
354 {
355     alloc_save_t *asave;
356     bool saveLockSafety = gs_currentdevice_inline(igs)->LockSafetyParams;
357     int code = restore_check_save(i_ctx_p, &asave);
358 
359     if (code < 0) return code;
360 
361     while (gs_gstate_saved(gs_gstate_saved(igs))) {
362         code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
363         if (code < 0) return code;
364         if (code > 0)
365             return push_callout(i_ctx_p, "%restore1pagedevice");
366         gs_grestore(igs);
367     }
368     code = restore_page_device(i_ctx_p, igs, gs_gstate_saved(igs));
369     if (code < 0) return code;
370     if (code > 0)
371         return push_callout(i_ctx_p, "%restorepagedevice");
372 
373     code = dorestore(i_ctx_p, asave);
374 
375     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         gs_currentdevice_inline(igs)->LockSafetyParams = saveLockSafety;
384     }
385     return code;
386 }
387 
388 /* <gstate> setgstate - */
389 static int
z2setgstate(i_ctx_t * i_ctx_p)390 z2setgstate(i_ctx_t *i_ctx_p)
391 {
392     os_ptr op = osp;
393     int code;
394 
395     check_stype(*op, st_igstate_obj);
396     code = restore_page_device(i_ctx_p, igs, igstate_ptr(op));
397     if (code < 0) return code;
398     if (code == 0)
399         return zsetgstate(i_ctx_p);
400     return push_callout(i_ctx_p, "%setgstatepagedevice");
401 }
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
push_callout(i_ctx_t * i_ctx_p,const char * callout_name)434 push_callout(i_ctx_t *i_ctx_p, const char *callout_name)
435 {
436     int code;
437 
438     check_estack(1);
439     code = name_enter_string(imemory, callout_name, esp + 1);
440     if (code < 0)
441         return code;
442     ++esp;
443     r_set_attrs(esp, a_executable);
444     return o_push_estack;
445 }
446