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