File: iutil.c

package info (click to toggle)
gs 3.33-7
  • links: PTS
  • area: main
  • in suites: hamm
  • size: 7,436 kB
  • ctags: 15,511
  • sloc: ansic: 92,150; asm: 684; sh: 486; makefile: 91
file content (467 lines) | stat: -rw-r--r-- 13,159 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
/* Copyright (C) 1989, 1992, 1993, 1994 Aladdin Enterprises.  All rights reserved.
  
  This file is part of GNU Ghostscript.
  
  GNU Ghostscript is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility to
  anyone for the consequences of using it or for whether it serves any
  particular purpose or works at all, unless he says so in writing.  Refer
  to the GNU Ghostscript General Public License for full details.
  
*/

/* iutil.c */
/* Utilities for Ghostscript interpreter */
#include "memory_.h"
#include "string_.h"
#include "ghost.h"
#include "errors.h"
#include "idict.h"
#include "imemory.h"
#include "iname.h"
#include "ipacked.h"			/* for array_get */
#include "iutil.h"			/* for checking prototypes */
#include "ivmspace.h"
#include "oper.h"
#include "store.h"
#include "gsmatrix.h"
#include "gsutil.h"

/* ------ Object utilities ------ */

/* Copy refs from one place to another. */
int
refcpy_to_old(ref *aref, uint index, register const ref *from,
  register uint size, client_name_t cname)
{	register ref *to = aref->value.refs + index;
	int code = refs_check_space(from, size, r_space(aref));
	if ( code < 0 )
		return code;
	/* We have to worry about aliasing.... */
	if ( to <= from || from + size <= to )
		while ( size-- )
			ref_assign_old(aref, to, from, cname), to++, from++;
	else
		for ( from += size, to += size; size--; )
			from--, to--, ref_assign_old(aref, to, from, cname);
	return 0;
}
void
refcpy_to_new(register ref *to, register const ref *from, register uint size)
{	while ( size-- )
		ref_assign_new(to, from), to++, from++;
}

/* Fill a new object with nulls. */
void
refset_null(register ref *to, register uint size)
{	while ( size-- ) make_null_new(to), to++;
}

/* Compare two objects for equality.  Return 1 if equal, 0 if not. */
int
obj_eq(register const ref *pref1, register const ref *pref2)
{	ref nref;
	if ( r_type(pref1) != r_type(pref2) )
	   {	/* Only a few cases need be considered here: */
		/* integer/real (and vice versa), name/string */
		/* (and vice versa), and extended operators. */
		switch ( r_type(pref1) )
		   {
		case t_integer:
			return (r_has_type(pref2, t_real) &&
				pref2->value.realval == pref1->value.intval);
		case t_real:
			return (r_has_type(pref2, t_integer) &&
				pref2->value.intval == pref1->value.realval);
		case t_name:
			if ( !r_has_type(pref2, t_string) )
				return 0;
			name_string_ref(pref1, &nref);
			pref1 = &nref;
			break;
		case t_save:
			return (r_has_type(pref2, t_save) &&
				pref2->value.saveid == pref1->value.saveid);
		case t_string:
			if ( !r_has_type(pref2, t_name) )
				return 0;
			name_string_ref(pref2, &nref);
			pref2 = &nref;
			break;
		default:
			if ( r_btype(pref1) != r_btype(pref2) )
				return 0;
		   }
	   }
	/* Now do a type-dependent comparison. */
	/* This would be very simple if we always filled in */
	/* all 8 bytes of a ref, but we currently don't. */
	switch ( r_btype(pref1) )
	   {
	case t_array:
		return (pref1->value.refs == pref2->value.refs &&
			r_size(pref1) == r_size(pref2));
	case t_mixedarray:
	case t_shortarray:
		return (pref1->value.packed == pref2->value.packed &&
			r_size(pref1) == r_size(pref2));
	case t_boolean:
		return (pref1->value.boolval == pref2->value.boolval);
	case t_dictionary:
		return (pref1->value.pdict == pref2->value.pdict);
	case t_file:
		return (pref1->value.pfile == pref2->value.pfile &&
			r_size(pref1) == r_size(pref2));
	case t_integer:
		return (pref1->value.intval == pref2->value.intval);
	case t_mark:
	case t_null:
		return 1;
	case t_name:
		return (pref1->value.pname == pref2->value.pname);
	case t_oparray:
	case t_operator:
		return (op_index(pref1) == op_index(pref2));
	case t_real:
		return (pref1->value.realval == pref2->value.realval);
	case t_string:
		return (!bytes_compare(pref1->value.bytes, r_size(pref1),
				       pref2->value.bytes, r_size(pref2)));
	case t_device:
		return (pref1->value.pdevice == pref2->value.pdevice);
	case t_fontID:
	case t_struct:
	case t_astruct:
		return (pref1->value.pstruct == pref2->value.pstruct);
	   }
	return 0;			/* shouldn't happen! */
}

/* Create a printable representation of an object, a la cvs. */
/* Return 0 if OK, <0 if the destination wasn't large enough or */
/* the object's contents weren't readable. */
/* If the object was a string or name, store a pointer to its characters */
/* even if it was too large. */
int
obj_cvs(const ref *op, byte *str, uint len, uint *prlen, byte **pchars)
{	char buf[30];			/* big enough for any float */
	byte *pstr = (byte *)buf;
	uint plen;
	ref nref;
	switch ( r_btype(op) )
	   {
	case t_boolean:
		pstr = (byte *)(op->value.boolval ? "true" : "false");
		break;
	case t_integer:
		sprintf(buf, "%ld", op->value.intval);
		break;
	case t_name:
		name_string_ref(op, &nref);	/* name string */
cvname:		pstr = nref.value.bytes;
		plen = r_size(&nref);
		if ( pchars != 0 )
			*pchars = pstr;
		goto nl;
	case t_oparray:
		{ uint index = op_index(op);
		  const op_array_table *opt = op_index_op_array_table(index);
		  name_index_ref(opt->nx_table[index - opt->base_index], &nref);
		}
		name_string_ref(&nref, &nref);
		goto cvname;
	case t_operator:
	   {	/* Recover the name from the initialization table. */
		uint index = op_index(op);
		/* Check the validity of the index.  (An out-of-bounds */
		/* index is only possible when examining an invalid */
		/* object using the debugger.) */
		if ( index > 0 && index < op_def_count )
		   {	pstr = (byte *)(op_def_table[index]->oname + 1);
			break;
		   }
	   }
		/* Internal operator, no name. */
		sprintf(buf, "operator_0x%lx", (ulong)op->value.opproc);
		break;
	case t_real:
		sprintf(buf, "%g", op->value.realval);
		/* Make sure the output has a decimal point. */
		/* This is needed for compatibility with */
		/* Adobe (and other) interpreters. */
		/* Old Borland compilers require &buf[0], not just buf. */
		if ( strchr(&buf[0], '.') != NULL ) break;
		{	char *ept = strchr(&buf[0], 'e');
			if ( ept == NULL )
				strcat(buf, ".0");
			else
			{	/* Insert the .0 before the exponent. */
				/* What a nuisance! */
				char buf1[30];
				strcpy(&buf1[0], ept);
				strcpy(ept, ".0");
				strcat(&buf[0], &buf1[0]);
			}
		}
		break;
	case t_string:
		check_read(*op);
		pstr = op->value.bytes;
		plen = r_size(op);
		if ( pchars != 0 )
			*pchars = pstr;
		goto nl;
	default:
		pstr = (byte *)"--nostringval--";
	   }
	plen = strlen((char *)pstr);
nl:	*prlen = plen;
	if ( plen > len )
		return_error(e_rangecheck);
	memcpy(str, pstr, plen);
	return 0;
}

/* Find the index of an operator that doesn't have one stored in it. */
ushort
op_find_index(const ref *pref /* t_operator */)
{	op_proc_p proc = real_opproc(pref);
	register const op_def_ptr *opp = op_def_table;
	register const op_def_ptr *opend = opp + op_def_count;
	for ( ; ++opp < opend; )
	{	if ( (*opp)->proc == proc )
			return opp - op_def_table;
	}
	/* Lookup failed!  This isn't possible.... */
	return 0;
}

/*
 * Convert an operator index to an operator or oparray ref.
 * This is only used for debugging and for 'get' from packed arrays,
 * so it doesn't have to be very fast.
 */
void
op_index_ref(uint index, ref *pref)
{	const op_array_table *opt;
	if ( op_index_is_operator(index) )
	  {	make_oper(pref, index, op_index_proc(index));
		return;
	  }
	opt = op_index_op_array_table(index);
	make_tasv(pref, t_oparray, opt->attrs, index,
                  const_refs, (opt->table.value.const_refs
                               + index - opt->base_index));
}

/* Get an element from an array of some kind. */
/* This is also used to index into Encoding vectors, */
/* the error name vector, etc. */
int
array_get(const ref *aref, long index_long, ref *pref)
{	if ( (ulong)index_long >= r_size(aref) )
		return_error(e_rangecheck);
	switch ( r_type(aref) )
	   {
	case t_array:
	   {	const ref *pvalue =
		   aref->value.refs + (uint)index_long;
		ref_assign(pref, pvalue);
	   }	return 0;
	case t_mixedarray:
	   {	const ref_packed *packed = aref->value.packed;
		uint index = (uint)index_long;
		for ( ; index--; ) packed = packed_next(packed);
		packed_get(packed, pref);
	   }	return 0;
	case t_shortarray:
	   {	const ref_packed *packed =
		   aref->value.packed + (uint)index_long;
		packed_get(packed, pref);
	   }	return 0;
	default:
		return_error(e_typecheck);
	   }
}

/* Get an element from a packed array. */
/* (This works for ordinary arrays too.) */
/* Source and destination are allowed to overlap if the source is packed, */
/* or if they are identical. */
void
packed_get(const ref_packed *packed, ref *pref)
{	const ref_packed elt = *packed;
	uint value = elt & packed_value_mask;
	switch ( elt >> r_packed_type_shift )
	{
	default:			/* (shouldn't happen) */
		make_null(pref);
		break;
	case pt_executable_operator:
		op_index_ref(value, pref);
		break;
	case pt_integer:
		make_int(pref, (int)value + packed_min_intval);
		break;
	case pt_literal_name:
		name_index_ref(value, pref);
		break;
	case pt_executable_name:
		name_index_ref(value, pref);
		r_set_attrs(pref, a_executable);
		break;
	case pt_full_ref:
	case pt_full_ref+1:
		ref_assign(pref, (const ref *)packed);
	}
}

/* Check to make sure an interval contains no object references */
/* to a space younger than a given one. */
/* Return 0 or e_invalidaccess. */
int
refs_check_space(register const ref *bot, register uint size, uint space)
{	for ( ; size--; bot++ )
	  store_check_space(space, bot);
	return 0;
}

/* ------ String utilities ------ */

/* Convert a C string to a Ghostscript string */
int
string_to_ref(const char *cstr, ref *pref, gs_ref_memory_t *mem,
  client_name_t cname)
{	uint size = strlen(cstr);
	int code = gs_alloc_string_ref(mem, pref, a_all, size, cname);
	if ( code < 0 )
	  return code;
	memcpy(pref->value.bytes, cstr, size);
	return 0;
}

/* Convert a Ghostscript string to a C string. */
/* Return 0 iff the buffer can't be allocated. */
char *
ref_to_string(const ref *pref, gs_memory_t *mem, client_name_t cname)
{	uint size = r_size(pref);
	char *str = (char *)gs_alloc_string(mem, size + 1, cname);
	if ( str == 0 )
		return 0;
	memcpy(str, (const char *)pref->value.bytes, size);
	str[size] = 0;
	return str;
}

/* ------ Operand utilities ------ */

/* Get N numeric operands from the stack or an array. */
/* Return a bit-mask indicating which ones are integers, */
/* or a (negative) error indication. */
/* The 1-bit in the bit-mask refers to the first operand. */
/* Store float versions of the operands at pval. */
/* The stack underflow check (check for t__invalid) is harmless */
/* if the operands come from somewhere other than the stack. */
int
num_params(const ref *op, int count, float *pval)
{	int mask = 0;
	pval += count;
	while ( --count >= 0 )
	   {	mask <<= 1;
		switch ( r_type(op) )
		   {
		case t_real:
			*--pval = op->value.realval;
			break;
		case t_integer:
			*--pval = op->value.intval;
			mask++;
			break;
		case t__invalid:
			return_error(e_stackunderflow);
		default:
			return_error(e_typecheck);
		   }
		op--;
	   }
	/* If count is very large, mask might overflow. */
	/* In this case we clearly don't care about the value of mask. */
	return (mask < 0 ? 0 : mask);
}

/* Get a single real parameter. */
/* The only possible error is e_typecheck. */
/* If an error is returned, the return value is not updated. */
int
real_param(const ref *op, float *pparam)
{	switch ( r_type(op) )
	   {
	case t_integer:
		*pparam = op->value.intval;
		break;
	case t_real:
		*pparam = op->value.realval;
		break;
	default:
		return_error(e_typecheck);
	   }
	return 0;
}

/* Make real values on the operand stack. */
void
make_reals(ref *op, const float *pval, int count)
{	for ( ; count--; op++, pval++ )
		make_real(op, *pval);
}

/* Compute the error code when check_proc fails. */
/* Note that the client, not this procedure, uses return_error. */
/* The stack underflow check is harmless in the off-stack case. */
int
check_proc_failed(const ref *pref)
{	return (r_is_array(pref) ? e_invalidaccess :
		r_has_type(pref, t__invalid) ? e_stackunderflow :
		e_typecheck);
}

/* Compute the error code when a type check on the stack fails. */
/* Note that the client, not this procedure, uses return_error. */
int
check_type_failed(const ref *op)
{	return (r_has_type(op, t__invalid) ? e_stackunderflow : e_typecheck);
}

/* ------ Matrix utilities ------ */

/* Read a matrix operand. */
/* Return 0 if OK, error code if not. */
int
read_matrix(const ref *op, gs_matrix *pmat)
{	int code;
	check_read_type(*op, t_array);
	if ( r_size(op) != 6 )
		return_error(e_rangecheck);
	code = num_params(op->value.refs + 5, 6, (float *)pmat);
	return (code < 0 ? code : 0);
}

/* Write a matrix operand. */
/* Return 0 if OK, error code if not. */
int
write_matrix(register ref *op, const gs_matrix *pmat)
{	ref *aptr;
	const float *pel;
	int i;
	check_write_type(*op, t_array);
	if ( r_size(op) != 6 )
		return_error(e_rangecheck);
	aptr = op->value.refs;
	pel = (float *)pmat;
	for ( i = 5; i >= 0; i--, aptr++, pel++ )
	{	ref_save(op, aptr, "write_matrix");
		make_real_new(aptr, *pel);
	}
	return 0;
}