xref: /plan9/sys/src/cmd/gs/src/ztype.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: ztype.c,v 1.8 2004/08/04 19:36:13 stefan Exp $ */
18 /* Type, attribute, and conversion operators */
19 #include "math_.h"
20 #include "memory_.h"
21 #include "string_.h"
22 #include "gsexit.h"
23 #include "ghost.h"
24 #include "oper.h"
25 #include "imemory.h"		/* for register_ref_root */
26 #include "idict.h"
27 #include "iname.h"
28 #include "stream.h"		/* for iscan.h */
29 #include "strimpl.h"		/* for sfilter.h for picky compilers */
30 #include "sfilter.h"		/* ditto */
31 #include "iscan.h"
32 #include "iutil.h"
33 #include "dstack.h"		/* for dict_set_top */
34 #include "store.h"
35 
36 /*
37  * Some of the procedures in this file are public only so they can be
38  * called from the FunctionType 4 interpreter (zfunc4.c).
39  */
40 
41 /* Forward references */
42 private int access_check(i_ctx_t *, int, bool);
43 private int convert_to_string(const gs_memory_t *mem, os_ptr, os_ptr);
44 
45 /*
46  * Max and min integer values expressed as reals.
47  * Note that these are biased by 1 to allow for truncation.
48  * They should be #defines rather than static consts, but
49  * several of the SCO Unix compilers apparently can't handle this.
50  * On the other hand, the DEC compiler can't handle casts in
51  * constant expressions, so we can't use min_long and max_long.
52  * What a nuisance!
53  */
54 #define ALT_MIN_LONG (-1L << (arch_sizeof_long * 8 - 1))
55 #define ALT_MAX_LONG (~(ALT_MIN_LONG))
56 private const double min_int_real = (ALT_MIN_LONG * 1.0 - 1);
57 private const double max_int_real = (ALT_MAX_LONG * 1.0 + 1);
58 
59 #define REAL_CAN_BE_INT(v)\
60   ((v) > min_int_real && (v) < max_int_real)
61 
62 /* Get the pointer to the access flags for a ref. */
63 #define ACCESS_REF(opp)\
64   (r_has_type(opp, t_dictionary) ? dict_access_ref(opp) : opp)
65 
66 /* <obj> <typenames> .type <name> */
67 private int
ztype(i_ctx_t * i_ctx_p)68 ztype(i_ctx_t *i_ctx_p)
69 {
70     os_ptr op = osp;
71     ref tnref;
72     int code = array_get(imemory, op, (long)r_btype(op - 1), &tnref);
73 
74     if (code < 0)
75 	return code;
76     if (!r_has_type(&tnref, t_name)) {
77 	/* Must be either a stack underflow or a t_[a]struct. */
78 	check_op(2);
79 	{			/* Get the type name from the structure. */
80 	    const char *sname =
81 		gs_struct_type_name_string(gs_object_type(imemory,
82 							  op[-1].value.pstruct));
83 	    int code = name_ref(imemory, (const byte *)sname, strlen(sname),
84 				(ref *) (op - 1), 0);
85 
86 	    if (code < 0)
87 		return code;
88 	}
89 	r_set_attrs(op - 1, a_executable);
90     } else {
91 	ref_assign(op - 1, &tnref);
92     }
93     pop(1);
94     return 0;
95 }
96 
97 /* - .typenames <name1|null> ... <nameN|null> */
98 private int
ztypenames(i_ctx_t * i_ctx_p)99 ztypenames(i_ctx_t *i_ctx_p)
100 {
101     os_ptr op = osp;
102     static const char *const tnames[] = { REF_TYPE_NAME_STRINGS };
103     int i;
104 
105     check_ostack(t_next_index);
106     for (i = 0; i < t_next_index; i++) {
107 	ref *const rtnp = op + 1 + i;
108 
109 	if (i >= countof(tnames) || tnames[i] == 0)
110 	    make_null(rtnp);
111 	else {
112 	    int code = name_enter_string(imemory, tnames[i], rtnp);
113 
114 	    if (code < 0)
115 		return code;
116 	    r_set_attrs(rtnp, a_executable);
117 	}
118     }
119     osp += t_next_index;
120     return 0;
121 }
122 
123 /* <obj> cvlit <obj> */
124 private int
zcvlit(i_ctx_t * i_ctx_p)125 zcvlit(i_ctx_t *i_ctx_p)
126 {
127     os_ptr op = osp;
128     ref *aop;
129 
130     check_op(1);
131     aop = ACCESS_REF(op);
132     r_clear_attrs(aop, a_executable);
133     return 0;
134 }
135 
136 /* <obj> cvx <obj> */
137 int
zcvx(i_ctx_t * i_ctx_p)138 zcvx(i_ctx_t *i_ctx_p)
139 {
140     os_ptr op = osp;
141     ref *aop;
142     uint opidx;
143 
144     check_op(1);
145     /*
146      * If the object is an internal operator, we can't allow it to
147      * exist in executable form anywhere outside the e-stack.
148      */
149     if (r_has_type(op, t_operator) &&
150 	((opidx = op_index(op)) == 0 ||
151 	 op_def_is_internal(op_index_def(opidx)))
152 	)
153 	return_error(e_rangecheck);
154     aop = ACCESS_REF(op);
155     r_set_attrs(aop, a_executable);
156     return 0;
157 }
158 
159 /* <obj> xcheck <bool> */
160 private int
zxcheck(i_ctx_t * i_ctx_p)161 zxcheck(i_ctx_t *i_ctx_p)
162 {
163     os_ptr op = osp;
164 
165     check_op(1);
166     make_bool(op, (r_has_attr(ACCESS_REF(op), a_executable) ? 1 : 0));
167     return 0;
168 }
169 
170 /* <obj:array|packedarray|file|string> executeonly <obj> */
171 private int
zexecuteonly(i_ctx_t * i_ctx_p)172 zexecuteonly(i_ctx_t *i_ctx_p)
173 {
174     os_ptr op = osp;
175 
176     check_op(1);
177     if (r_has_type(op, t_dictionary))
178 	return_error(e_typecheck);
179     return access_check(i_ctx_p, a_execute, true);
180 }
181 
182 /* <obj:array|packedarray|dict|file|string> noaccess <obj> */
183 private int
znoaccess(i_ctx_t * i_ctx_p)184 znoaccess(i_ctx_t *i_ctx_p)
185 {
186     os_ptr op = osp;
187 
188     check_op(1);
189     if (r_has_type(op, t_dictionary)) {
190 	/*
191 	 * Setting noaccess on a read-only dictionary is an attempt to
192 	 * change its value, which is forbidden (this is a subtle
193 	 * point confirmed with Adobe).  Also, don't allow removing
194 	 * read access to permanent dictionaries.
195 	 */
196 	if (dict_is_permanent_on_dstack(op) ||
197 	    !r_has_attr(dict_access_ref(op), a_write)
198 	    )
199 	    return_error(e_invalidaccess);
200     }
201     return access_check(i_ctx_p, 0, true);
202 }
203 
204 /* <obj:array|packedarray|dict|file|string> readonly <obj> */
205 int
zreadonly(i_ctx_t * i_ctx_p)206 zreadonly(i_ctx_t *i_ctx_p)
207 {
208     return access_check(i_ctx_p, a_readonly, true);
209 }
210 
211 /* <array|packedarray|dict|file|string> rcheck <bool> */
212 private int
zrcheck(i_ctx_t * i_ctx_p)213 zrcheck(i_ctx_t *i_ctx_p)
214 {
215     os_ptr op = osp;
216     int code = access_check(i_ctx_p, a_read, false);
217 
218     if (code >= 0)
219 	make_bool(op, code), code = 0;
220     return code;
221 }
222 
223 /* <array|packedarray|dict|file|string> wcheck <bool> */
224 private int
zwcheck(i_ctx_t * i_ctx_p)225 zwcheck(i_ctx_t *i_ctx_p)
226 {
227     os_ptr op = osp;
228     int code = access_check(i_ctx_p, a_write, false);
229 
230     if (code >= 0)
231 	make_bool(op, code), code = 0;
232     return code;
233 }
234 
235 /* <num> cvi <int> */
236 /* <string> cvi <int> */
237 int
zcvi(i_ctx_t * i_ctx_p)238 zcvi(i_ctx_t *i_ctx_p)
239 {
240     os_ptr op = osp;
241     float fval;
242 
243     switch (r_type(op)) {
244 	case t_integer:
245 	    return 0;
246 	case t_real:
247 	    fval = op->value.realval;
248 	    break;
249 	default:
250 	    return_op_typecheck(op);
251 	case t_string:
252 	    {
253 		ref str, token;
254 		int code;
255 
256 		ref_assign(&str, op);
257 		code = scan_string_token(i_ctx_p, &str, &token);
258 		if (code > 0)	/* anything other than a plain token */
259 		    code = gs_note_error(e_syntaxerror);
260 		if (code < 0)
261 		    return code;
262 		switch (r_type(&token)) {
263 		    case t_integer:
264 			*op = token;
265 			return 0;
266 		    case t_real:
267 			fval = token.value.realval;
268 			break;
269 		    default:
270 			return_error(e_typecheck);
271 		}
272 	    }
273     }
274     if (!REAL_CAN_BE_INT(fval))
275 	return_error(e_rangecheck);
276     make_int(op, (long)fval);	/* truncates towards 0 */
277     return 0;
278 }
279 
280 /* <string> cvn <name> */
281 private int
zcvn(i_ctx_t * i_ctx_p)282 zcvn(i_ctx_t *i_ctx_p)
283 {
284     os_ptr op = osp;
285 
286     check_read_type(*op, t_string);
287     return name_from_string(imemory, op, op);
288 }
289 
290 /* <num> cvr <real> */
291 /* <string> cvr <real> */
292 int
zcvr(i_ctx_t * i_ctx_p)293 zcvr(i_ctx_t *i_ctx_p)
294 {
295     os_ptr op = osp;
296 
297     switch (r_type(op)) {
298 	case t_integer:
299 	    make_real(op, (float)op->value.intval);
300 	case t_real:
301 	    return 0;
302 	default:
303 	    return_op_typecheck(op);
304 	case t_string:
305 	    {
306 		ref str, token;
307 		int code;
308 
309 		ref_assign(&str, op);
310 		code = scan_string_token(i_ctx_p, &str, &token);
311 		if (code > 0)	/* anything other than a plain token */
312 		    code = gs_note_error(e_syntaxerror);
313 		if (code < 0)
314 		    return code;
315 		switch (r_type(&token)) {
316 		    case t_integer:
317 			make_real(op, (float)token.value.intval);
318 			return 0;
319 		    case t_real:
320 			*op = token;
321 			return 0;
322 		    default:
323 			return_error(e_typecheck);
324 		}
325 	    }
326     }
327 }
328 
329 /* <num> <radix_int> <string> cvrs <substring> */
330 private int
zcvrs(i_ctx_t * i_ctx_p)331 zcvrs(i_ctx_t *i_ctx_p)
332 {
333     os_ptr op = osp;
334     int radix;
335 
336     check_type(op[-1], t_integer);
337     if (op[-1].value.intval < 2 || op[-1].value.intval > 36)
338 	return_error(e_rangecheck);
339     radix = op[-1].value.intval;
340     check_write_type(*op, t_string);
341     if (radix == 10) {
342 	switch (r_type(op - 2)) {
343 	    case t_integer:
344 	    case t_real:
345 		{
346 		    int code = convert_to_string(imemory, op - 2, op);
347 
348 		    if (code < 0)
349 			return code;
350 		    pop(2);
351 		    return 0;
352 		}
353 	    default:
354 		return_op_typecheck(op - 2);
355 	}
356     } else {
357 	ulong ival;
358 	byte digits[sizeof(ulong) * 8];
359 	byte *endp = &digits[countof(digits)];
360 	byte *dp = endp;
361 
362 	switch (r_type(op - 2)) {
363 	    case t_integer:
364 		ival = (ulong) op[-2].value.intval;
365 		break;
366 	    case t_real:
367 		{
368 		    float fval = op[-2].value.realval;
369 
370 		    if (!REAL_CAN_BE_INT(fval))
371 			return_error(e_rangecheck);
372 		    ival = (ulong) (long)fval;
373 		} break;
374 	    default:
375 		return_op_typecheck(op - 2);
376 	}
377 	do {
378 	    int dit = ival % radix;
379 
380 	    *--dp = dit + (dit < 10 ? '0' : ('A' - 10));
381 	    ival /= radix;
382 	}
383 	while (ival);
384 	if (endp - dp > r_size(op))
385 	    return_error(e_rangecheck);
386 	memcpy(op->value.bytes, dp, (uint) (endp - dp));
387 	r_set_size(op, endp - dp);
388     }
389     op[-2] = *op;
390     pop(2);
391     return 0;
392 }
393 
394 /* <any> <string> cvs <substring> */
395 private int
zcvs(i_ctx_t * i_ctx_p)396 zcvs(i_ctx_t *i_ctx_p)
397 {
398     os_ptr op = osp;
399     int code;
400 
401     check_op(2);
402     check_write_type(*op, t_string);
403     code = convert_to_string(imemory, op - 1, op);
404     if (code >= 0)
405 	pop(1);
406     return code;
407 }
408 
409 /* ------ Initialization procedure ------ */
410 
411 const op_def ztype_op_defs[] =
412 {
413     {"1cvi", zcvi},
414     {"1cvlit", zcvlit},
415     {"1cvn", zcvn},
416     {"1cvr", zcvr},
417     {"3cvrs", zcvrs},
418     {"2cvs", zcvs},
419     {"1cvx", zcvx},
420     {"1executeonly", zexecuteonly},
421     {"1noaccess", znoaccess},
422     {"1rcheck", zrcheck},
423     {"1readonly", zreadonly},
424     {"2.type", ztype},
425     {"0.typenames", ztypenames},
426     {"1wcheck", zwcheck},
427     {"1xcheck", zxcheck},
428     op_def_end(0)
429 };
430 
431 /* ------ Internal routines ------ */
432 
433 /* Test or modify the access of an object. */
434 /* If modify = true, restrict to the selected access and return 0; */
435 /* if modify = false, do not change the access, and return 1 */
436 /* if the object had the access. */
437 /* Return an error code if the object is not of appropriate type, */
438 /* or if the object did not have the access already when modify=1. */
439 private int
access_check(i_ctx_t * i_ctx_p,int access,bool modify)440 access_check(i_ctx_t *i_ctx_p,
441 	     int access,	/* mask for attrs */
442 	     bool modify)	/* if true, reduce access */
443 {
444     os_ptr op = osp;
445     ref *aop;
446 
447     switch (r_type(op)) {
448 	case t_dictionary:
449 	    aop = dict_access_ref(op);
450 	    if (modify) {
451 		if (!r_has_attrs(aop, access))
452 		    return_error(e_invalidaccess);
453 		ref_save(op, aop, "access_check(modify)");
454 		r_clear_attrs(aop, a_all);
455 		r_set_attrs(aop, access);
456 		dict_set_top();
457 		return 0;
458 	    }
459 	    break;
460 	case t_array:
461 	case t_file:
462 	case t_string:
463 	case t_mixedarray:
464 	case t_shortarray:
465 	case t_astruct:
466 	case t_device:;
467 	    if (modify) {
468 		if (!r_has_attrs(op, access))
469 		    return_error(e_invalidaccess);
470 		r_clear_attrs(op, a_all);
471 		r_set_attrs(op, access);
472 		return 0;
473 	    }
474 	    aop = op;
475 	    break;
476 	default:
477 	    return_op_typecheck(op);
478     }
479     return (r_has_attrs(aop, access) ? 1 : 0);
480 }
481 
482 /* Do all the work of cvs.  The destination has been checked, but not */
483 /* the source.  This is a separate procedure so that */
484 /* cvrs can use it when the radix is 10. */
485 private int
convert_to_string(const gs_memory_t * mem,os_ptr op1,os_ptr op)486 convert_to_string(const gs_memory_t *mem, os_ptr op1, os_ptr op)
487 {
488     uint len;
489     const byte *pstr = 0;
490     int code = obj_cvs(mem, op1, op->value.bytes, r_size(op), &len, &pstr);
491 
492     if (code < 0) {
493 	/*
494 	 * Some common downloaded error handlers assume that
495 	 * operator names don't exceed a certain fixed size.
496 	 * To work around this bit of bad design, we implement
497 	 * a special hack here: if we got a rangecheck, and
498 	 * the object is an operator whose name begins with
499 	 * %, ., or @, we just truncate the name.
500 	 */
501 	if (code == e_rangecheck)
502 	    switch (r_btype(op1)) {
503 		case t_oparray:
504 		case t_operator:
505 		    if (pstr != 0)
506 			switch (*pstr) {
507 			    case '%':
508 			    case '.':
509 			    case '@':
510 				len = r_size(op);
511 				memcpy(op->value.bytes, pstr, len);
512 				goto ok;
513 			}
514 	    }
515 	return code;
516     }
517 ok:
518     *op1 = *op;
519     r_set_size(op1, len);
520     return 0;
521 }
522