changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/cmd/gs/src/ztype.c

changeset 0: eaccc3e8d226
child: 03b53375c4f5
author: Taru Karttunen <taruti@taruti.net>
date: Wed, 30 Mar 2011 15:46:40 +0300
permissions: -rwxr-xr-x
description: Import sources from 2011-03-30 iso image
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }