2 |
- |
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 *
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|