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