xref: /plan9/sys/src/cmd/gs/src/iutil.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 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: iutil.c,v 1.11 2004/08/19 19:33:09 stefan Exp $ */
18 /* Utilities for Ghostscript interpreter */
19 #include "math_.h"		/* for fabs */
20 #include "memory_.h"
21 #include "string_.h"
22 #include "ghost.h"
23 #include "ierrors.h"
24 #include "gsccode.h"		/* for gxfont.h */
25 #include "gsmatrix.h"
26 #include "gsutil.h"
27 #include "gxfont.h"
28 #include "strimpl.h"
29 #include "sstring.h"
30 #include "idict.h"
31 #include "imemory.h"
32 #include "iname.h"
33 #include "ipacked.h"		/* for array_get */
34 #include "iutil.h"		/* for checking prototypes */
35 #include "ivmspace.h"
36 #include "oper.h"
37 #include "store.h"
38 
39 /*
40  * By design choice, none of the procedures in this file take a context
41  * pointer (i_ctx_p).  Since a number of them require a gs_dual_memory_t
42  * for store checking or save bookkeeping, we need to #undef idmemory.
43  */
44 #undef idmemory
45 
46 /* ------ Object utilities ------ */
47 
48 /* Define the table of ref type properties. */
49 const byte ref_type_properties[] = {
50     REF_TYPE_PROPERTIES_DATA
51 };
52 
53 /* Copy refs from one place to another. */
54 int
refcpy_to_old(ref * aref,uint index,const ref * from,uint size,gs_dual_memory_t * idmemory,client_name_t cname)55 refcpy_to_old(ref * aref, uint index, const ref * from,
56 	      uint size, gs_dual_memory_t *idmemory, client_name_t cname)
57 {
58     ref *to = aref->value.refs + index;
59     int code = refs_check_space(from, size, r_space(aref));
60 
61     if (code < 0)
62 	return code;
63     /* We have to worry about aliasing.... */
64     if (to <= from || from + size <= to)
65 	while (size--)
66 	    ref_assign_old(aref, to, from, cname), to++, from++;
67     else
68 	for (from += size, to += size; size--;)
69 	    from--, to--, ref_assign_old(aref, to, from, cname);
70     return 0;
71 }
72 void
refcpy_to_new(ref * to,const ref * from,uint size,gs_dual_memory_t * idmemory)73 refcpy_to_new(ref * to, const ref * from, uint size,
74 	      gs_dual_memory_t *idmemory)
75 {
76     while (size--)
77 	ref_assign_new(to, from), to++, from++;
78 }
79 
80 /* Fill a new object with nulls. */
81 void
refset_null_new(ref * to,uint size,uint new_mask)82 refset_null_new(ref * to, uint size, uint new_mask)
83 {
84     for (; size--; ++to)
85 	make_ta(to, t_null, new_mask);
86 }
87 
88 /* Compare two objects for equality. */
89 bool
obj_eq(const gs_memory_t * mem,const ref * pref1,const ref * pref2)90 obj_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2)
91 {
92     ref nref;
93 
94     if (r_type(pref1) != r_type(pref2)) {
95 	/*
96 	 * Only a few cases need be considered here:
97 	 * integer/real (and vice versa), name/string (and vice versa),
98 	 * arrays, and extended operators.
99 	 */
100 	switch (r_type(pref1)) {
101 	    case t_integer:
102 		return (r_has_type(pref2, t_real) &&
103 			pref2->value.realval == pref1->value.intval);
104 	    case t_real:
105 		return (r_has_type(pref2, t_integer) &&
106 			pref2->value.intval == pref1->value.realval);
107 	    case t_name:
108 		if (!r_has_type(pref2, t_string))
109 		    return false;
110 		name_string_ref(mem, pref1, &nref);
111 		pref1 = &nref;
112 		break;
113 	    case t_string:
114 		if (!r_has_type(pref2, t_name))
115 		    return false;
116 		name_string_ref(mem, pref2, &nref);
117 		pref2 = &nref;
118 		break;
119 
120 		/* differing array types can match if length is 0 */
121 	    case t_array:
122 	    case t_mixedarray:
123 	    case t_shortarray:
124 		return r_is_array(pref2) &&
125 		       r_size(pref1) == 0 && r_size(pref2) == 0;
126 	    default:
127 		if (r_btype(pref1) != r_btype(pref2))
128 		    return false;
129 	}
130     }
131     /*
132      * Now do a type-dependent comparison.  This would be very simple if we
133      * always filled in all the bytes of a ref, but we currently don't.
134      */
135     switch (r_btype(pref1)) {
136 	case t_array:
137 	    return ((pref1->value.refs == pref2->value.refs ||
138 	             r_size(pref1) == 0) &&
139 		    r_size(pref1) == r_size(pref2));
140 	case t_mixedarray:
141 	case t_shortarray:
142 	    return ((pref1->value.packed == pref2->value.packed ||
143 	             r_size(pref1) == 0) &&
144 		    r_size(pref1) == r_size(pref2));
145 	case t_boolean:
146 	    return (pref1->value.boolval == pref2->value.boolval);
147 	case t_dictionary:
148 	    return (pref1->value.pdict == pref2->value.pdict);
149 	case t_file:
150 	    return (pref1->value.pfile == pref2->value.pfile &&
151 		    r_size(pref1) == r_size(pref2));
152 	case t_integer:
153 	    return (pref1->value.intval == pref2->value.intval);
154 	case t_mark:
155 	case t_null:
156 	    return true;
157 	case t_name:
158 	    return (pref1->value.pname == pref2->value.pname);
159 	case t_oparray:
160 	case t_operator:
161 	    return (op_index(pref1) == op_index(pref2));
162 	case t_real:
163 	    return (pref1->value.realval == pref2->value.realval);
164 	case t_save:
165 	    return (pref2->value.saveid == pref1->value.saveid);
166 	case t_string:
167 	    return (!bytes_compare(pref1->value.bytes, r_size(pref1),
168 				   pref2->value.bytes, r_size(pref2)));
169 	case t_device:
170 	    return (pref1->value.pdevice == pref2->value.pdevice);
171 	case t_struct:
172 	case t_astruct:
173 	    return (pref1->value.pstruct == pref2->value.pstruct);
174 	case t_fontID:
175 	    {	/*
176 		 * In the Adobe implementations, different scalings of a
177 		 * font have "equal" FIDs, so we do the same.
178 		 */
179 		const gs_font *pfont1 = r_ptr(pref1, gs_font);
180 		const gs_font *pfont2 = r_ptr(pref2, gs_font);
181 
182 		while (pfont1->base != pfont1)
183 		    pfont1 = pfont1->base;
184 		while (pfont2->base != pfont2)
185 		    pfont2 = pfont2->base;
186 		return (pfont1 == pfont2);
187 	    }
188     }
189     return false;		/* shouldn't happen! */
190 }
191 
192 /* Compare two objects for identity. */
193 bool
obj_ident_eq(const gs_memory_t * mem,const ref * pref1,const ref * pref2)194 obj_ident_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2)
195 {
196     if (r_type(pref1) != r_type(pref2))
197 	return false;
198     if (r_has_type(pref1, t_string))
199 	return (pref1->value.bytes == pref2->value.bytes &&
200 		r_size(pref1) == r_size(pref2));
201     return obj_eq(mem, pref1, pref2);
202 }
203 
204 /*
205  * Set *pchars and *plen to point to the data of a name or string, and
206  * return 0.  If the object isn't a name or string, return e_typecheck.
207  * If the object is a string without read access, return e_invalidaccess.
208  */
209 int
obj_string_data(const gs_memory_t * mem,const ref * op,const byte ** pchars,uint * plen)210 obj_string_data(const gs_memory_t *mem, const ref *op, const byte **pchars, uint *plen)
211 {
212     switch (r_type(op)) {
213     case t_name: {
214 	ref nref;
215 
216 	name_string_ref(mem, op, &nref);
217 	*pchars = nref.value.bytes;
218 	*plen = r_size(&nref);
219 	return 0;
220     }
221     case t_string:
222 	check_read(*op);
223 	*pchars = op->value.bytes;
224 	*plen = r_size(op);
225 	return 0;
226     default:
227 	return_error(e_typecheck);
228     }
229 }
230 
231 /*
232  * Create a printable representation of an object, a la cvs and =
233  * (full_print = 0), == (full_print = 1), or === (full_print = 2).  Return 0
234  * if OK, 1 if the destination wasn't large enough, e_invalidaccess if the
235  * object's contents weren't readable.  If the return value is 0 or 1,
236  * *prlen contains the amount of data returned.  start_pos is the starting
237  * output position -- the first start_pos bytes of output are discarded.
238  *
239  * The mem argument is only used for getting the type of structures,
240  * not for allocating; if it is NULL and full_print != 0, structures will
241  * print as --(struct)--.
242  *
243  * This rather complex API is needed so that a client can call obj_cvp
244  * repeatedly to print on a stream, which may require suspending at any
245  * point to handle stream callouts.
246  */
247 private void ensure_dot(char *);
248 int
obj_cvp(const ref * op,byte * str,uint len,uint * prlen,int full_print,uint start_pos,const gs_memory_t * mem)249 obj_cvp(const ref * op, byte * str, uint len, uint * prlen,
250 	int full_print, uint start_pos, const gs_memory_t *mem)
251 {
252     char buf[50];  /* big enough for any float, double, or struct name */
253     const byte *data = (const byte *)buf;
254     uint size;
255     int code;
256     ref nref;
257 
258     if (full_print) {
259 	static const char * const type_strings[] = { REF_TYPE_PRINT_STRINGS };
260 
261 	switch (r_btype(op)) {
262 	case t_boolean:
263 	case t_integer:
264 	    break;
265 	case t_real: {
266 	    /*
267 	     * To get fully accurate output results for IEEE
268 	     * single-precision floats (24 bits of mantissa), the ANSI %g
269 	     * default of 6 digits is not enough; 9 are needed.
270 	     * Unfortunately, using %.9g for floats (as opposed to doubles)
271 	     * produces unfortunate artifacts such as 0.01 5 mul printing as
272 	     * 0.049999997.  Therefore, we print using %g, and if the result
273 	     * isn't accurate enough, print again using %.9g.
274 	     * Unfortunately, a few PostScript programs 'know' that the
275 	     * printed representation of floats fits into 6 digits (e.g.,
276 	     * with cvs).  We resolve this by letting cvs, cvrs, and = do
277 	     * what the Adobe interpreters appear to do (use %g), and only
278 	     * produce accurate output for ==, for which there is no
279 	     * analogue of cvs.  What a hack!
280 	     */
281 	    float value = op->value.realval;
282 	    float scanned;
283 
284 	    sprintf(buf, "%g", value);
285 	    sscanf(buf, "%f", &scanned);
286 	    if (scanned != value)
287 		sprintf(buf, "%.9g", value);
288 	    ensure_dot(buf);
289 	    goto rs;
290 	}
291 	case t_operator:
292 	case t_oparray:
293 	    code = obj_cvp(op, (byte *)buf + 2, sizeof(buf) - 4, &size, 0, 0, mem);
294 	    if (code < 0)
295 		return code;
296 	    buf[0] = buf[1] = buf[size + 2] = buf[size + 3] = '-';
297 	    size += 4;
298 	    goto nl;
299 	case t_name:
300 	    if (r_has_attr(op, a_executable)) {
301 		code = obj_string_data(mem, op, &data, &size);
302 		if (code < 0)
303 		    return code;
304 		goto nl;
305 	    }
306 	    if (start_pos > 0)
307 		return obj_cvp(op, str, len, prlen, 0, start_pos - 1, mem);
308 	    if (len < 1)
309 		return_error(e_rangecheck);
310 	    code = obj_cvp(op, str + 1, len - 1, prlen, 0, 0, mem);
311 	    if (code < 0)
312 		return code;
313 	    str[0] = '/';
314 	    ++*prlen;
315 	    return code;
316 	case t_null:
317 	    data = (const byte *)"null";
318 	    goto rs;
319 	case t_string:
320 	    if (!r_has_attr(op, a_read))
321 		goto other;
322 	    size = r_size(op);
323 	    {
324 		bool truncate = (full_print == 1 && size > CVP_MAX_STRING);
325 		stream_cursor_read r;
326 		stream_cursor_write w;
327 		uint skip;
328 		byte *wstr;
329 		uint len1;
330 		int status = 1;
331 
332 		if (start_pos == 0) {
333 		    if (len < 1)
334 			return_error(e_rangecheck);
335 		    str[0] = '(';
336 		    skip = 0;
337 		    wstr = str + 1;
338 		} else {
339 		    skip = start_pos - 1;
340 		    wstr = str;
341 		}
342 		len1 = len + (str - wstr);
343 		r.ptr = op->value.const_bytes - 1;
344 		r.limit = r.ptr + (truncate ? CVP_MAX_STRING : size);
345 		while (skip && status == 1) {
346 		    uint written;
347 
348 		    w.ptr = (byte *)buf - 1;
349 		    w.limit = w.ptr + min(skip + len1, sizeof(buf));
350 		    status = s_PSSE_template.process(NULL, &r, &w, false);
351 		    written = w.ptr - ((byte *)buf - 1);
352 		    if (written > skip) {
353 			written -= skip;
354 			memcpy(wstr, buf + skip, written);
355 			wstr += written;
356 			skip = 0;
357 			break;
358 		    }
359 		    skip -= written;
360 		}
361 		/*
362 		 * We can reach here with status == 0 (and skip != 0) if
363 		 * start_pos lies within the trailing ")" or  "...)".
364 		 */
365 		if (status == 0) {
366 #ifdef DEBUG
367 		    if (skip > (truncate ? 4 : 1)) {
368 			return_error(e_Fatal);
369 		    }
370 #endif
371 		}
372 		w.ptr = wstr - 1;
373 		w.limit = str - 1 + len;
374 		if (status == 1)
375 		    status = s_PSSE_template.process(NULL, &r, &w, false);
376 		*prlen = w.ptr - (str - 1);
377 		if (status != 0)
378 		    return 1;
379 		if (truncate) {
380 		    if (len - *prlen < 4 - skip)
381 			return 1;
382 		    memcpy(w.ptr + 1, "...)" + skip, 4 - skip);
383 		    *prlen += 4 - skip;
384 		} else {
385 		    if (len - *prlen < 1 - skip)
386 			return 1;
387 		    memcpy(w.ptr + 1, ")" + skip, 1 - skip);
388 		    *prlen += 1 - skip;
389 		}
390 	    }
391 	    return 0;
392 	case t_astruct:
393 	case t_struct:
394 	    if (r_is_foreign(op)) {
395 		/* gs_object_type may not work. */
396 		data = (const byte *)"-foreign-struct-";
397 		goto rs;
398 	    }
399 	    if (!mem) {
400 		data = (const byte *)"-(struct)-";
401 		goto rs;
402 	    }
403 	    data = (const byte *)
404 		gs_struct_type_name_string(
405 		     gs_object_type((gs_memory_t *)mem,
406 				    (const obj_header_t *)op->value.pstruct));
407 	    size = strlen((const char *)data);
408 	    if (size > 4 && !memcmp(data + size - 4, "type", 4))
409 		size -= 4;
410 	    if (size > sizeof(buf) - 2)
411 		return_error(e_rangecheck);
412 	    buf[0] = '-';
413 	    memcpy(buf + 1, data, size);
414 	    buf[size + 1] = '-';
415 	    size += 2;
416 	    data = (const byte *)buf;
417 	    goto nl;
418 	default:
419 other:
420 	    {
421 		int rtype = r_btype(op);
422 
423 		if (rtype > countof(type_strings))
424 		    return_error(e_rangecheck);
425 		data = (const byte *)type_strings[rtype];
426 		if (data == 0)
427 		    return_error(e_rangecheck);
428 	    }
429 	    goto rs;
430 	}
431     }
432     /* full_print = 0 */
433     switch (r_btype(op)) {
434     case t_boolean:
435 	data = (const byte *)(op->value.boolval ? "true" : "false");
436 	break;
437     case t_integer:
438 	sprintf(buf, "%ld", op->value.intval);
439 	break;
440     case t_string:
441 	check_read(*op);
442 	/* falls through */
443     case t_name:
444 	code = obj_string_data(mem, op, &data, &size);
445 	if (code < 0)
446 	    return code;
447 	goto nl;
448     case t_oparray: {
449 	uint index = op_index(op);
450 	const op_array_table *opt = op_index_op_array_table(index);
451 
452 	name_index_ref(mem, opt->nx_table[index - opt->base_index], &nref);
453 	name_string_ref(mem, &nref, &nref);
454 	code = obj_string_data(mem, &nref, &data, &size);
455 	if (code < 0)
456 	    return code;
457 	goto nl;
458     }
459     case t_operator: {
460 	/* Recover the name from the initialization table. */
461 	uint index = op_index(op);
462 
463 	/*
464 	 * Check the validity of the index.  (An out-of-bounds index
465 	 * is only possible when examining an invalid object using
466 	 * the debugger.)
467 	 */
468 	if (index > 0 && index < op_def_count) {
469 	    data = (const byte *)(op_index_def(index)->oname + 1);
470 	    break;
471 	}
472 	/* Internal operator, no name. */
473 	sprintf(buf, "@0x%lx", (ulong) op->value.opproc);
474 	break;
475     }
476     case t_real:
477 	sprintf(buf, "%g", op->value.realval);
478 	ensure_dot(buf);
479 	break;
480     default:
481 	data = (const byte *)"--nostringval--";
482     }
483 rs: size = strlen((const char *)data);
484 nl: if (size < start_pos)
485 	return_error(e_rangecheck);
486     size -= start_pos;
487     *prlen = min(size, len);
488     memmove(str, data + start_pos, *prlen);
489     return (size > len);
490 }
491 /*
492  * Make sure the converted form of a real number has a decimal point.  This
493  * is needed for compatibility with Adobe (and other) interpreters.
494  */
495 private void
ensure_dot(char * buf)496 ensure_dot(char *buf)
497 {
498     if (strchr(buf, '.') == NULL) {
499 	char *ept = strchr(buf, 'e');
500 
501 	if (ept == NULL)
502 	    strcat(buf, ".0");
503 	else {
504 	    /* Insert the .0 before the exponent.  What a nuisance! */
505 	    char buf1[30];
506 
507 	    strcpy(buf1, ept);
508 	    strcpy(ept, ".0");
509 	    strcat(ept, buf1);
510 	}
511     }
512 }
513 
514 /*
515  * Create a printable representation of an object, a la cvs and =.  Return 0
516  * if OK, e_rangecheck if the destination wasn't large enough,
517  * e_invalidaccess if the object's contents weren't readable.  If pchars !=
518  * NULL, then if the object was a string or name, store a pointer to its
519  * characters in *pchars even if it was too large; otherwise, set *pchars =
520  * str.  In any case, store the length in *prlen.
521  */
522 int
obj_cvs(const gs_memory_t * mem,const ref * op,byte * str,uint len,uint * prlen,const byte ** pchars)523 obj_cvs(const gs_memory_t *mem, const ref * op, byte * str, uint len, uint * prlen,
524 	const byte ** pchars)
525 {
526     int code = obj_cvp(op, str, len, prlen, 0, 0, mem);  /* NB: NULL memptr */
527 
528     if (code != 1 && pchars) {
529 	*pchars = str;
530 	return code;
531     }
532     obj_string_data(mem, op, pchars, prlen);
533     return gs_note_error(e_rangecheck);
534 }
535 
536 /* Find the index of an operator that doesn't have one stored in it. */
537 ushort
op_find_index(const ref * pref)538 op_find_index(const ref * pref /* t_operator */ )
539 {
540     op_proc_t proc = real_opproc(pref);
541     const op_def *const *opp = op_defs_all;
542     const op_def *const *opend = opp + (op_def_count / OP_DEFS_MAX_SIZE);
543 
544     for (; opp < opend; ++opp) {
545 	const op_def *def = *opp;
546 
547 	for (; def->oname != 0; ++def)
548 	    if (def->proc == proc)
549 		return (opp - op_defs_all) * OP_DEFS_MAX_SIZE + (def - *opp);
550     }
551     /* Lookup failed!  This isn't possible.... */
552     return 0;
553 }
554 
555 /*
556  * Convert an operator index to an operator or oparray ref.
557  * This is only used for debugging and for 'get' from packed arrays,
558  * so it doesn't have to be very fast.
559  */
560 void
op_index_ref(uint index,ref * pref)561 op_index_ref(uint index, ref * pref)
562 {
563     const op_array_table *opt;
564 
565     if (op_index_is_operator(index)) {
566 	make_oper(pref, index, op_index_proc(index));
567 	return;
568     }
569     opt = op_index_op_array_table(index);
570     make_tasv(pref, t_oparray, opt->attrs, index,
571 	      const_refs, (opt->table.value.const_refs
572 			   + index - opt->base_index));
573 }
574 
575 /* Get an element from an array of some kind. */
576 /* This is also used to index into Encoding vectors, */
577 /* the error name vector, etc. */
578 int
array_get(const gs_memory_t * mem,const ref * aref,long index_long,ref * pref)579 array_get(const gs_memory_t *mem, const ref * aref, long index_long, ref * pref)
580 {
581     if ((ulong)index_long >= r_size(aref))
582 	return_error(e_rangecheck);
583     switch (r_type(aref)) {
584 	case t_array:
585 	    {
586 		const ref *pvalue = aref->value.refs + index_long;
587 
588 		ref_assign(pref, pvalue);
589 	    }
590 	    break;
591 	case t_mixedarray:
592 	    {
593 		const ref_packed *packed = aref->value.packed;
594 		uint index = (uint)index_long;
595 
596 		for (; index--;)
597 		    packed = packed_next(packed);
598 		packed_get(mem, packed, pref);
599 	    }
600 	    break;
601 	case t_shortarray:
602 	    {
603 		const ref_packed *packed = aref->value.packed + index_long;
604 
605 		packed_get(mem, packed, pref);
606 	    }
607 	    break;
608 	default:
609 	    return_error(e_typecheck);
610     }
611     return 0;
612 }
613 
614 /* Get an element from a packed array. */
615 /* (This works for ordinary arrays too.) */
616 /* Source and destination are allowed to overlap if the source is packed, */
617 /* or if they are identical. */
618 void
packed_get(const gs_memory_t * mem,const ref_packed * packed,ref * pref)619 packed_get(const gs_memory_t *mem, const ref_packed * packed, ref * pref)
620 {
621     const ref_packed elt = *packed;
622     uint value = elt & packed_value_mask;
623 
624     switch (elt >> r_packed_type_shift) {
625 	default:		/* (shouldn't happen) */
626 	    make_null(pref);
627 	    break;
628 	case pt_executable_operator:
629 	    op_index_ref(value, pref);
630 	    break;
631 	case pt_integer:
632 	    make_int(pref, (int)value + packed_min_intval);
633 	    break;
634 	case pt_literal_name:
635 	    name_index_ref(mem, value, pref);
636 	    break;
637 	case pt_executable_name:
638 	    name_index_ref(mem, value, pref);
639 	    r_set_attrs(pref, a_executable);
640 	    break;
641 	case pt_full_ref:
642 	case pt_full_ref + 1:
643 	    ref_assign(pref, (const ref *)packed);
644     }
645 }
646 
647 /* Check to make sure an interval contains no object references */
648 /* to a space younger than a given one. */
649 /* Return 0 or e_invalidaccess. */
650 int
refs_check_space(const ref * bot,uint size,uint space)651 refs_check_space(const ref * bot, uint size, uint space)
652 {
653     for (; size--; bot++)
654 	store_check_space(space, bot);
655     return 0;
656 }
657 
658 /* ------ String utilities ------ */
659 
660 /* Convert a C string to a Ghostscript string */
661 int
string_to_ref(const char * cstr,ref * pref,gs_ref_memory_t * mem,client_name_t cname)662 string_to_ref(const char *cstr, ref * pref, gs_ref_memory_t * mem,
663 	      client_name_t cname)
664 {
665     uint size = strlen(cstr);
666     int code = gs_alloc_string_ref(mem, pref, a_all, size, cname);
667 
668     if (code < 0)
669 	return code;
670     memcpy(pref->value.bytes, cstr, size);
671     return 0;
672 }
673 
674 /* Convert a Ghostscript string to a C string. */
675 /* Return 0 iff the buffer can't be allocated. */
676 char *
ref_to_string(const ref * pref,gs_memory_t * mem,client_name_t cname)677 ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname)
678 {
679     uint size = r_size(pref);
680     char *str = (char *)gs_alloc_string(mem, size + 1, cname);
681 
682     if (str == 0)
683 	return 0;
684     memcpy(str, (const char *)pref->value.bytes, size);
685     str[size] = 0;
686     return str;
687 }
688 
689 /* ------ Operand utilities ------ */
690 
691 /* Get N numeric operands from the stack or an array. */
692 /* Return a bit-mask indicating which ones are integers, */
693 /* or a (negative) error indication. */
694 /* The 1-bit in the bit-mask refers to the first operand. */
695 /* Store float versions of the operands at pval. */
696 /* The stack underflow check (check for t__invalid) is harmless */
697 /* if the operands come from somewhere other than the stack. */
698 int
num_params(const ref * op,int count,double * pval)699 num_params(const ref * op, int count, double *pval)
700 {
701     int mask = 0;
702 
703     pval += count;
704     while (--count >= 0) {
705 	mask <<= 1;
706 	switch (r_type(op)) {
707 	    case t_real:
708 		*--pval = op->value.realval;
709 		break;
710 	    case t_integer:
711 		*--pval = op->value.intval;
712 		mask++;
713 		break;
714 	    case t__invalid:
715 		return_error(e_stackunderflow);
716 	    default:
717 		return_error(e_typecheck);
718 	}
719 	op--;
720     }
721     /* If count is very large, mask might overflow. */
722     /* In this case we clearly don't care about the value of mask. */
723     return (mask < 0 ? 0 : mask);
724 }
725 /* float_params doesn't bother to keep track of the mask. */
726 int
float_params(const ref * op,int count,float * pval)727 float_params(const ref * op, int count, float *pval)
728 {
729     for (pval += count; --count >= 0; --op)
730 	switch (r_type(op)) {
731 	    case t_real:
732 		*--pval = op->value.realval;
733 		break;
734 	    case t_integer:
735 		*--pval = (float)op->value.intval;
736 		break;
737 	    case t__invalid:
738 		return_error(e_stackunderflow);
739 	    default:
740 		return_error(e_typecheck);
741 	}
742     return 0;
743 }
744 
745 /* Get N numeric parameters (as floating point numbers) from an array */
746 int
process_float_array(const gs_memory_t * mem,const ref * parray,int count,float * pval)747 process_float_array(const gs_memory_t *mem, const ref * parray, int count, float * pval)
748 {
749     int         code = 0, indx0 = 0;
750 
751     /* we assume parray is an array of some type, of adequate length */
752     if (r_has_type(parray, t_array))
753         return float_params(parray->value.refs + count - 1, count, pval);
754 
755     /* short/mixed array; convert the entries to refs */
756     while (count > 0 && code >= 0) {
757         int     i, subcount;
758         ref     ref_buff[20];   /* 20 is arbitrary */
759 
760         subcount = (count > countof(ref_buff) ? countof(ref_buff) : count);
761         for (i = 0; i < subcount && code >= 0; i++)
762             code = array_get(mem, parray, (long)(i + indx0), &ref_buff[i]);
763         if (code >= 0)
764             code = float_params(ref_buff + subcount - 1, subcount, pval);
765         count -= subcount;
766         pval += subcount;
767         indx0 += subcount;
768     }
769 
770     return code;
771 }
772 
773 /* Get a single real parameter. */
774 /* The only possible error is e_typecheck. */
775 /* If an error is returned, the return value is not updated. */
776 int
real_param(const ref * op,double * pparam)777 real_param(const ref * op, double *pparam)
778 {
779     switch (r_type(op)) {
780 	case t_integer:
781 	    *pparam = op->value.intval;
782 	    break;
783 	case t_real:
784 	    *pparam = op->value.realval;
785 	    break;
786 	default:
787 	    return_error(e_typecheck);
788     }
789     return 0;
790 }
791 int
float_param(const ref * op,float * pparam)792 float_param(const ref * op, float *pparam)
793 {
794     double dval;
795     int code = real_param(op, &dval);
796 
797     if (code >= 0)
798 	*pparam = (float)dval;	/* can't overflow */
799     return code;
800 }
801 
802 /* Get an integer parameter in a given range. */
803 int
int_param(const ref * op,int max_value,int * pparam)804 int_param(const ref * op, int max_value, int *pparam)
805 {
806     check_int_leu(*op, max_value);
807     *pparam = (int)op->value.intval;
808     return 0;
809 }
810 
811 /* Make real values on the operand stack. */
812 int
make_reals(ref * op,const double * pval,int count)813 make_reals(ref * op, const double *pval, int count)
814 {
815     /* This should return e_limitcheck if any real is too large */
816     /* to fit into a float on the stack. */
817     for (; count--; op++, pval++)
818 	make_real(op, *pval);
819     return 0;
820 }
821 int
make_floats(ref * op,const float * pval,int count)822 make_floats(ref * op, const float *pval, int count)
823 {
824     /* This should return e_undefinedresult for infinities. */
825     for (; count--; op++, pval++)
826 	make_real(op, *pval);
827     return 0;
828 }
829 
830 /* Compute the error code when check_proc fails. */
831 /* Note that the client, not this procedure, uses return_error. */
832 /* The stack underflow check is harmless in the off-stack case. */
833 int
check_proc_failed(const ref * pref)834 check_proc_failed(const ref * pref)
835 {
836     return (r_is_array(pref) ? e_invalidaccess :
837 	    r_has_type(pref, t__invalid) ? e_stackunderflow :
838 	    e_typecheck);
839 }
840 
841 /* Compute the error code when a type check on the stack fails. */
842 /* Note that the client, not this procedure, uses return_error. */
843 int
check_type_failed(const ref * op)844 check_type_failed(const ref * op)
845 {
846     return (r_has_type(op, t__invalid) ? e_stackunderflow : e_typecheck);
847 }
848 
849 /* ------ Matrix utilities ------ */
850 
851 /* Read a matrix operand. */
852 /* Return 0 if OK, error code if not. */
853 int
read_matrix(const gs_memory_t * mem,const ref * op,gs_matrix * pmat)854 read_matrix(const gs_memory_t *mem, const ref * op, gs_matrix * pmat)
855 {
856     int code;
857     ref values[6];
858     const ref *pvalues;
859 
860     if (r_has_type(op, t_array))
861 	pvalues = op->value.refs;
862     else {
863 	int i;
864 
865 	for (i = 0; i < 6; ++i) {
866 	    code = array_get(mem, op, (long)i, &values[i]);
867 	    if (code < 0)
868 		return code;
869 	}
870 	pvalues = values;
871     }
872     check_read(*op);
873     if (r_size(op) != 6)
874 	return_error(e_rangecheck);
875     code = float_params(pvalues + 5, 6, (float *)pmat);
876     return (code < 0 ? code : 0);
877 }
878 
879 /* Write a matrix operand. */
880 /* Return 0 if OK, error code if not. */
881 int
write_matrix_in(ref * op,const gs_matrix * pmat,gs_dual_memory_t * idmemory,gs_ref_memory_t * imem)882 write_matrix_in(ref * op, const gs_matrix * pmat, gs_dual_memory_t *idmemory,
883 		gs_ref_memory_t *imem)
884 {
885     ref *aptr;
886     const float *pel;
887     int i;
888 
889     check_write_type(*op, t_array);
890     if (r_size(op) != 6)
891 	return_error(e_rangecheck);
892     aptr = op->value.refs;
893     pel = (const float *)pmat;
894     for (i = 5; i >= 0; i--, aptr++, pel++) {
895 	if (idmemory) {
896 	    ref_save(op, aptr, "write_matrix");
897 	    make_real_new(aptr, *pel);
898 	} else {
899 	    make_tav(aptr, t_real, imemory_new_mask(imem), realval, *pel);
900 	}
901     }
902     return 0;
903 }
904