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