1 /* Copyright (C) 2001-2009 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zmisc.c 9334 2009-01-08 09:17:18Z ghostgum $ */
15 /* Miscellaneous operators */
16 
17 #include "errno_.h"
18 #include "memory_.h"
19 #include "string_.h"
20 #include "ghost.h"
21 #include "gscdefs.h"		/* for gs_serialnumber */
22 #include "gp.h"
23 #include "oper.h"
24 #include "ialloc.h"
25 #include "idict.h"
26 #include "dstack.h"		/* for name lookup in bind */
27 #include "iname.h"
28 #include "ipacked.h"
29 #include "ivmspace.h"
30 #include "store.h"
31 
32 /**********************************************************************/
33 
34 /* <proc> bind <proc> */
35 static inline bool
r_is_ex_oper(const ref * rp)36 r_is_ex_oper(const ref *rp)
37 {
38     return (r_has_attr(rp, a_executable) &&
39 	    (r_btype(rp) == t_operator || r_type(rp) == t_oparray));
40 }
41 static int
zbind(i_ctx_t * i_ctx_p)42 zbind(i_ctx_t *i_ctx_p)
43 {
44     os_ptr op = osp;
45     uint depth = 1;
46     ref defn;
47     register os_ptr bsp;
48 
49     switch (r_type(op)) {
50 	case t_array:
51 	    if (!r_has_attr(op, a_write)) {
52 		return 0;	/* per PLRM3 */
53 	    }
54 	case t_mixedarray:
55 	case t_shortarray:
56 	    defn = *op;
57 	    break;
58 	case t_oparray:
59 	    defn = *op->value.const_refs;
60 	    break;
61 	default:
62 	    return_op_typecheck(op);
63     }
64     push(1);
65     *op = defn;
66     bsp = op;
67     /*
68      * We must not make the top-level procedure read-only,
69      * but we must bind it even if it is read-only already.
70      *
71      * Here are the invariants for the following loop:
72      *      `depth' elements have been pushed on the ostack;
73      *      For i < depth, p = ref_stack_index(&o_stack, i):
74      *        *p is an array (or packedarray) ref.
75      */
76     while (depth) {
77 	while (r_size(bsp)) {
78 	    ref_packed *const tpp = (ref_packed *)bsp->value.packed; /* break const */
79 
80 	    r_dec_size(bsp, 1);
81 	    if (r_is_packed(tpp)) {
82 		/* Check for a packed executable name */
83 		ushort elt = *tpp;
84 
85 		if (r_packed_is_exec_name(&elt)) {
86 		    ref nref;
87 		    ref *pvalue;
88 
89 		    name_index_ref(imemory, packed_name_index(&elt),
90 				   &nref);
91 		    if ((pvalue = dict_find_name(&nref)) != 0 &&
92 			r_is_ex_oper(pvalue)
93 			) {
94 			store_check_dest(bsp, pvalue);
95 			/*
96 			 * Always save the change, since this can only
97 			 * happen once.
98 			 */
99 			ref_do_save(bsp, tpp, "bind");
100 			*tpp = pt_tag(pt_executable_operator) +
101 			    op_index(pvalue);
102 		    }
103 		}
104 		bsp->value.packed = tpp + 1;
105 	    } else {
106 		ref *const tp = bsp->value.refs++;
107 
108 		switch (r_type(tp)) {
109 		    case t_name:	/* bind the name if an operator */
110 			if (r_has_attr(tp, a_executable)) {
111 			    ref *pvalue;
112 
113 			    if ((pvalue = dict_find_name(tp)) != 0 &&
114 				r_is_ex_oper(pvalue)
115 				) {
116 				store_check_dest(bsp, pvalue);
117 				ref_assign_old(bsp, tp, pvalue, "bind");
118 			    }
119 			}
120 			break;
121 		    case t_array:	/* push into array if writable */
122 			if (!r_has_attr(tp, a_write))
123 			    break;
124 		    case t_mixedarray:
125 		    case t_shortarray:
126 			if (r_has_attr(tp, a_executable)) {
127 			    /* Make reference read-only */
128 			    r_clear_attrs(tp, a_write);
129 			    if (bsp >= ostop) {
130 				/* Push a new stack block. */
131 				ref temp;
132 				int code;
133 
134 				temp = *tp;
135 				osp = bsp;
136 				code = ref_stack_push(&o_stack, 1);
137 				if (code < 0) {
138 				    ref_stack_pop(&o_stack, depth);
139 				    return_error(code);
140 				}
141 				bsp = osp;
142 				*bsp = temp;
143 			    } else
144 				*++bsp = *tp;
145 			    depth++;
146 			}
147 		}
148 	    }
149 	}
150 	bsp--;
151 	depth--;
152 	if (bsp < osbot) {	/* Pop back to the previous stack block. */
153 	    osp = bsp;
154 	    ref_stack_pop_block(&o_stack);
155 	    bsp = osp;
156 	}
157     }
158     osp = bsp;
159     return 0;
160 }
161 
162 /* - serialnumber <int> */
163 static int
zserialnumber(i_ctx_t * i_ctx_p)164 zserialnumber(i_ctx_t *i_ctx_p)
165 {
166     os_ptr op = osp;
167 
168     push(1);
169     make_int(op, gs_serialnumber);
170     return 0;
171 }
172 
173 /* some FTS tests work better if realtime starts from 0 at boot time */
174 static long    real_time_0[2];
175 
176 static int
zmisc_init_realtime(i_ctx_t * i_ctx_p)177 zmisc_init_realtime(i_ctx_t * i_ctx_p)
178 {
179     gp_get_realtime(real_time_0);
180     return 0;
181 }
182 
183 /* - realtime <int> */
184 static int
zrealtime(i_ctx_t * i_ctx_p)185 zrealtime(i_ctx_t *i_ctx_p)
186 {
187     os_ptr op = osp;
188     long secs_ns[2];
189 
190     gp_get_realtime(secs_ns);
191     secs_ns[1] -= real_time_0[1];
192     secs_ns[0] -= real_time_0[0];
193     push(1);
194     make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
195     return 0;
196 }
197 
198 /* - usertime <int> */
199 static int
zusertime(i_ctx_t * i_ctx_p)200 zusertime(i_ctx_t *i_ctx_p)
201 {
202     os_ptr op = osp;
203     long secs_ns[2];
204 
205     gp_get_usertime(secs_ns);
206     push(1);
207     make_int(op, secs_ns[0] * 1000 + secs_ns[1] / 1000000);
208     return 0;
209 }
210 
211 /* ---------------- Non-standard operators ---------------- */
212 
213 /* <string> getenv <value_string> true */
214 /* <string> getenv false */
215 static int
zgetenv(i_ctx_t * i_ctx_p)216 zgetenv(i_ctx_t *i_ctx_p)
217 {
218     os_ptr op = osp;
219     char *str;
220     byte *value;
221     int len = 0;
222 
223     check_read_type(*op, t_string);
224     str = ref_to_string(op, imemory, "getenv key");
225     if (str == 0)
226 	return_error(e_VMerror);
227     if (gp_getenv(str, (char *)0, &len) > 0) {	/* key missing */
228 	ifree_string((byte *) str, r_size(op) + 1, "getenv key");
229 	make_false(op);
230 	return 0;
231     }
232     value = ialloc_string(len, "getenv value");
233     if (value == 0) {
234 	ifree_string((byte *) str, r_size(op) + 1, "getenv key");
235 	return_error(e_VMerror);
236     }
237     DISCARD(gp_getenv(str, (char *)value, &len));	/* can't fail */
238     ifree_string((byte *) str, r_size(op) + 1, "getenv key");
239     /* Delete the stupid C string terminator. */
240     value = iresize_string(value, len, len - 1,
241 			   "getenv value");	/* can't fail */
242     push(1);
243     make_string(op - 1, a_all | icurrent_space, len - 1, value);
244     make_true(op);
245     return 0;
246 }
247 
248 /* - .defaultpapersize <string> true */
249 /* - .defaultpapersize false */
250 static int
zdefaultpapersize(i_ctx_t * i_ctx_p)251 zdefaultpapersize(i_ctx_t *i_ctx_p)
252 {
253     os_ptr op = osp;
254     byte *value;
255     int len = 0;
256 
257     if (gp_defaultpapersize((char *)0, &len) > 0) {
258 	/* no default paper size */
259         push(1);
260 	make_false(op);
261 	return 0;
262     }
263 
264     value = ialloc_string(len, "defaultpapersize value");
265     if (value == 0) {
266 	return_error(e_VMerror);
267     }
268     DISCARD(gp_defaultpapersize((char *)value, &len));	/* can't fail */
269     /* Delete the stupid C string terminator. */
270     value = iresize_string(value, len, len - 1,
271 			   "defaultpapersize value");	/* can't fail */
272     push(2);
273     make_string(op - 1, a_all | icurrent_space, len - 1, value);
274     make_true(op);
275     return 0;
276 }
277 
278 /* <name> <proc> .makeoperator <oper> */
279 static int
zmakeoperator(i_ctx_t * i_ctx_p)280 zmakeoperator(i_ctx_t *i_ctx_p)
281 {
282     os_ptr op = osp;
283     op_array_table *opt;
284     uint count;
285     ref *tab;
286 
287     check_type(op[-1], t_name);
288     check_proc(*op);
289     switch (r_space(op)) {
290 	case avm_global:
291 	    opt = &op_array_table_global;
292 	    break;
293 	case avm_local:
294 	    opt = &op_array_table_local;
295 	    break;
296 	default:
297 	    return_error(e_invalidaccess);
298     }
299     count = opt->count;
300     tab = opt->table.value.refs;
301     /*
302      * restore doesn't reset op_array_table.count, but it does
303      * remove entries from op_array_table.table.  Since we fill
304      * the table in order, we can detect that a restore has occurred
305      * by checking whether what should be the most recent entry
306      * is occupied.  If not, we scan backwards over the vacated entries
307      * to find the true end of the table.
308      */
309     while (count > 0 && r_has_type(&tab[count - 1], t_null))
310 	--count;
311     if (count == r_size(&opt->table))
312 	return_error(e_limitcheck);
313     ref_assign_old(&opt->table, &tab[count], op, "makeoperator");
314     opt->nx_table[count] = name_index(imemory, op - 1);
315     op_index_ref(opt->base_index + count, op - 1);
316     opt->count = count + 1;
317     pop(1);
318     return 0;
319 }
320 
321 /* - .oserrno <int> */
322 static int
zoserrno(i_ctx_t * i_ctx_p)323 zoserrno(i_ctx_t *i_ctx_p)
324 {
325     os_ptr op = osp;
326 
327     push(1);
328     make_int(op, errno);
329     return 0;
330 }
331 
332 /* <int> .setoserrno - */
333 static int
zsetoserrno(i_ctx_t * i_ctx_p)334 zsetoserrno(i_ctx_t *i_ctx_p)
335 {
336     os_ptr op = osp;
337 
338     check_type(*op, t_integer);
339     errno = op->value.intval;
340     pop(1);
341     return 0;
342 }
343 
344 /* <int> .oserrorstring <string> true */
345 /* <int> .oserrorstring false */
346 static int
zoserrorstring(i_ctx_t * i_ctx_p)347 zoserrorstring(i_ctx_t *i_ctx_p)
348 {
349     os_ptr op = osp;
350     const char *str;
351     int code;
352     uint len;
353     byte ch;
354 
355     check_type(*op, t_integer);
356     str = gp_strerror((int)op->value.intval);
357     if (str == 0 || (len = strlen(str)) == 0) {
358 	make_false(op);
359 	return 0;
360     }
361     check_ostack(1);
362     code = string_to_ref(str, op, iimemory, ".oserrorstring");
363     if (code < 0)
364 	return code;
365     /* Strip trailing end-of-line characters. */
366     while ((len = r_size(op)) != 0 &&
367 	   ((ch = op->value.bytes[--len]) == '\r' || ch == '\n')
368 	)
369 	r_dec_size(op, 1);
370     push(1);
371     make_true(op);
372     return 0;
373 }
374 
375 /* <string> <bool> .setdebug - */
376 static int
zsetdebug(i_ctx_t * i_ctx_p)377 zsetdebug(i_ctx_t *i_ctx_p)
378 {
379     os_ptr op = osp;
380     check_read_type(op[-1], t_string);
381     check_type(*op, t_boolean);
382     {
383 	int i;
384 
385 	for (i = 0; i < r_size(op - 1); i++)
386 	    gs_debug[op[-1].value.bytes[i] & 127] =
387 		op->value.boolval;
388     }
389     pop(2);
390     return 0;
391 }
392 
393 /* There are a few cases where a customer/user might want CPSI behavior
394  * instead of the GS default behavior. cmyk_to_rgb and Type 1 char fill
395  * method are two that have come up so far. This operator allows a PS
396  * program to control the behavior without needing to recompile
397  *
398  * While this would better if it were in some context 'state', we use
399  * a global, which we don't really like, but at least it is better
400  * than a compile time #define, as in #USE_ADOBE_CMYK_RGB and allows
401  * us to easily test with/without and not require recompilation.
402  */
403 extern bool CPSI_mode;		/* not worth polluting a header file */
404 
405 /* <bool> .setCPSImode - */
406 static int
zsetCPSImode(i_ctx_t * i_ctx_p)407 zsetCPSImode(i_ctx_t *i_ctx_p)
408 {
409     os_ptr op = osp;
410     check_type(*op, t_boolean);
411     CPSI_mode = op->value.boolval;
412     pop(1);
413     return 0;
414 }
415 
416 /* - .getCPSImode <bool> */
417 static int
zgetCPSImode(i_ctx_t * i_ctx_p)418 zgetCPSImode(i_ctx_t *i_ctx_p)
419 {
420     os_ptr op = osp;
421 
422     push(1);
423     make_bool(op, CPSI_mode);
424     return 0;
425 }
426 
427 /* ------ gs persistent cache operators ------ */
428 /* these are for testing only. they're disabled in the normal build
429  * to prevent access to the cache by malicious postscript files
430  *
431  * use something like this:
432  *   (value) (key) .pcacheinsert
433  *   (key) .pcachequery { (\n) concatstrings print } if
434  */
435 
436 #ifdef DEBUG_CACHE
437 
438 /* <string> <string> .pcacheinsert */
439 static int
zpcacheinsert(i_ctx_t * i_ctx_p)440 zpcacheinsert(i_ctx_t *i_ctx_p)
441 {
442     os_ptr op = osp;
443     char *key, *buffer;
444     int keylen, buflen;
445     int code = 0;
446 
447     check_read_type(*op, t_string);
448     keylen = r_size(op);
449     key = op->value.bytes;
450     check_read_type(*(op - 1), t_string);
451     buflen = r_size(op - 1);
452     buffer = (op - 1)->value.bytes;
453 
454     code = gp_cache_insert(0, key, keylen, buffer, buflen);
455     if (code < 0)
456 		return code;
457 
458 	pop(2);
459 
460     return code;
461 }
462 
463 /* allocation callback for query result */
464 static void *
pcache_alloc_callback(void * userdata,int bytes)465 pcache_alloc_callback(void *userdata, int bytes)
466 {
467     i_ctx_t *i_ctx_p = (i_ctx_t*)userdata;
468     return ialloc_string(bytes, "pcache buffer");
469 }
470 
471 /* <string> .pcachequery <string> true */
472 /* <string> .pcachequery false */
473 static int
zpcachequery(i_ctx_t * i_ctx_p)474 zpcachequery(i_ctx_t *i_ctx_p)
475 {
476 	os_ptr op = osp;
477 	int len;
478 	char *key;
479 	byte *string;
480 	int code = 0;
481 
482 	check_read_type(*op, t_string);
483 	len = r_size(op);
484 	key = op->value.bytes;
485 	len = gp_cache_query(GP_CACHE_TYPE_TEST, key, len, (void**)&string, &pcache_alloc_callback, i_ctx_p);
486 	if (len < 0) {
487 		make_false(op);
488 		return 0;
489 	}
490 	if (string == NULL)
491 		return_error(e_VMerror);
492 	make_string(op, a_all | icurrent_space, len, string);
493 
494 	push(1);
495 	make_true(op);
496 
497 	return code;
498 }
499 
500 #endif /* DEBUG_CACHE */
501 
502 /* ------ Initialization procedure ------ */
503 
504 const op_def zmisc_op_defs[] =
505 {
506     {"1bind", zbind},
507     {"1getenv", zgetenv},
508     {"0.defaultpapersize", zdefaultpapersize},
509     {"2.makeoperator", zmakeoperator},
510     {"0.oserrno", zoserrno},
511     {"1.oserrorstring", zoserrorstring},
512     {"0realtime", zrealtime},
513     {"1serialnumber", zserialnumber},
514     {"2.setdebug", zsetdebug},
515     {"1.setoserrno", zsetoserrno},
516     {"0usertime", zusertime},
517     {"1.setCPSImode", zsetCPSImode},
518     {"0.getCPSImode", zgetCPSImode},
519 #ifdef DEBUG_CACHE
520 	/* pcache test */
521     {"2.pcacheinsert", zpcacheinsert},
522     {"1.pcachequery", zpcachequery},
523 #endif
524     op_def_end(zmisc_init_realtime)
525 };
526