Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}