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