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