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