/src/ghostpdl/psi/iutil.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2024 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Utilities for Ghostscript interpreter */ |
18 | | #include "math_.h" /* for fabs */ |
19 | | #include "memory_.h" |
20 | | #include "string_.h" |
21 | | #include "ghost.h" |
22 | | #include "ierrors.h" |
23 | | #include "gsccode.h" /* for gxfont.h */ |
24 | | #include "gsmatrix.h" |
25 | | #include "gsutil.h" |
26 | | #include "gxfont.h" |
27 | | #include "strimpl.h" |
28 | | #include "sstring.h" |
29 | | #include "idict.h" |
30 | | #include "ifont.h" /* for FontID equality */ |
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 | 712M | { |
58 | 712M | ref *to = aref->value.refs + index; |
59 | 712M | int code = refs_check_space(from, size, r_space(aref)); |
60 | | |
61 | 712M | if (code < 0) |
62 | 0 | return code; |
63 | | /* We have to worry about aliasing.... */ |
64 | 712M | if (to <= from || from + size <= to) |
65 | 1.99G | while (size--) |
66 | 1.27G | ref_assign_old(aref, to, from, cname), to++, from++; |
67 | 0 | else |
68 | 0 | for (from += size, to += size; size--;) |
69 | 0 | from--, to--, ref_assign_old(aref, to, from, cname); |
70 | 712M | return 0; |
71 | 712M | } |
72 | | void |
73 | | refcpy_to_new(ref * to, const ref * from, uint size, |
74 | | gs_dual_memory_t *idmemory) |
75 | 0 | { |
76 | 0 | while (size--) |
77 | 0 | ref_assign_new(to, from), to++, from++; |
78 | 0 | } |
79 | | |
80 | | /* Fill a new object with nulls. */ |
81 | | void |
82 | | refset_null_new(ref * to, uint size, uint new_mask) |
83 | 988M | { |
84 | 28.8G | for (; size--; ++to) |
85 | 27.8G | make_ta(to, t_null, new_mask); |
86 | 988M | } |
87 | | |
88 | | /* Compare two objects for equality. */ |
89 | | static bool fid_eq(const gs_memory_t *mem, const gs_font *pfont1, |
90 | | const gs_font *pfont2); |
91 | | bool |
92 | | obj_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2) |
93 | 6.96G | { |
94 | 6.96G | ref nref; |
95 | | |
96 | 6.96G | 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 | | * arrays, and extended operators. |
101 | | */ |
102 | 1.62G | switch (r_type(pref1)) { |
103 | 1.66M | case t_integer: |
104 | 1.66M | return (r_has_type(pref2, t_real) && |
105 | 1.66M | pref2->value.realval == pref1->value.intval); |
106 | 13.3M | case t_real: |
107 | 13.3M | return (r_has_type(pref2, t_integer) && |
108 | 13.3M | pref2->value.intval == pref1->value.realval); |
109 | 1.46G | case t_name: |
110 | 1.46G | if (!r_has_type(pref2, t_string)) |
111 | 1.44G | return false; |
112 | 15.8M | name_string_ref(mem, pref1, &nref); |
113 | 15.8M | pref1 = &nref; |
114 | 15.8M | break; |
115 | 19.0M | case t_string: |
116 | 19.0M | if (!r_has_type(pref2, t_name)) |
117 | 2.23M | return false; |
118 | 16.7M | name_string_ref(mem, pref2, &nref); |
119 | 16.7M | pref2 = &nref; |
120 | 16.7M | break; |
121 | | /* |
122 | | * Differing implementations of packedarray can be eq, |
123 | | * if the length is zero, but an array is never eq to a |
124 | | * packedarray. |
125 | | */ |
126 | 931k | case t_mixedarray: |
127 | 931k | case t_shortarray: |
128 | | /* |
129 | | * Since r_type(pref1) is one of the above, this is a |
130 | | * clever fast check for r_type(pref2) being the other. |
131 | | */ |
132 | 931k | return ((int)r_type(pref1) + (int)r_type(pref2) == |
133 | 931k | t_mixedarray + t_shortarray) && |
134 | 931k | r_size(pref1) == 0 && r_size(pref2) == 0; |
135 | 124M | default: |
136 | 124M | if (r_btype(pref1) != r_btype(pref2)) |
137 | 124M | return false; |
138 | 1.62G | } |
139 | 1.62G | } |
140 | | /* |
141 | | * Now do a type-dependent comparison. This would be very simple if we |
142 | | * always filled in all the bytes of a ref, but we currently don't. |
143 | | */ |
144 | 5.37G | switch (r_btype(pref1)) { |
145 | 5.92M | case t_array: |
146 | 5.92M | return ((pref1->value.refs == pref2->value.refs || |
147 | 5.92M | r_size(pref1) == 0) && |
148 | 5.92M | r_size(pref1) == r_size(pref2)); |
149 | 3 | case t_mixedarray: |
150 | 159k | case t_shortarray: |
151 | 159k | return ((pref1->value.packed == pref2->value.packed || |
152 | 159k | r_size(pref1) == 0) && |
153 | 159k | r_size(pref1) == r_size(pref2)); |
154 | 18.5M | case t_boolean: |
155 | 18.5M | return (pref1->value.boolval == pref2->value.boolval); |
156 | 117M | case t_dictionary: |
157 | 117M | return (pref1->value.pdict == pref2->value.pdict); |
158 | 241k | case t_file: |
159 | 241k | return (pref1->value.pfile == pref2->value.pfile && |
160 | 241k | r_size(pref1) == r_size(pref2)); |
161 | 2.04G | case t_integer: |
162 | 2.04G | return (pref1->value.intval == pref2->value.intval); |
163 | 407k | case t_mark: |
164 | 123M | case t_null: |
165 | 123M | return true; |
166 | 2.74G | case t_name: |
167 | 2.74G | return (pref1->value.pname == pref2->value.pname); |
168 | 0 | case t_oparray: |
169 | 93 | case t_operator: |
170 | 93 | return (op_index(pref1) == op_index(pref2)); |
171 | 1.97M | case t_real: |
172 | 1.97M | return (pref1->value.realval == pref2->value.realval); |
173 | 192M | case t_save: |
174 | 192M | return (pref2->value.saveid == pref1->value.saveid); |
175 | 131M | case t_string: |
176 | 131M | return (!bytes_compare(pref1->value.bytes, r_size(pref1), |
177 | 131M | pref2->value.bytes, r_size(pref2))); |
178 | 0 | case t_device: |
179 | 0 | return (pref1->value.pdevice->device == pref2->value.pdevice->device); |
180 | 0 | case t_struct: |
181 | 4 | case t_astruct: |
182 | 4 | case t_pdfctx: |
183 | 4 | return (pref1->value.pstruct == pref2->value.pstruct); |
184 | 0 | case t_fontID: |
185 | | /* This is complicated enough to deserve a separate procedure. */ |
186 | 0 | return fid_eq(mem, r_ptr(pref1, gs_font), r_ptr(pref2, gs_font)); |
187 | 5.37G | } |
188 | 0 | return false; /* shouldn't happen! */ |
189 | 5.37G | } |
190 | | |
191 | | /* |
192 | | * Compare two FontIDs for equality. In the Adobe implementations, |
193 | | * different scalings of a font have "equal" FIDs, so we do the same. |
194 | | * Furthermore, in more recent Adobe interpreters, different *copies* of a |
195 | | * font have equal FIDs -- at least for Type 1 and Type 3 fonts -- as long |
196 | | * as the "contents" of the font are the same. We aren't sure that the |
197 | | * following matches the Adobe algorithm, but it's close enough to pass the |
198 | | * Genoa CET. |
199 | | */ |
200 | | /* (This is a single-use procedure, for clearer code.) */ |
201 | | static bool |
202 | | fid_eq(const gs_memory_t *mem, const gs_font *pfont1, const gs_font *pfont2) |
203 | 0 | { |
204 | 0 | while (pfont1->base != pfont1) |
205 | 0 | pfont1 = pfont1->base; |
206 | 0 | while (pfont2->base != pfont2) |
207 | 0 | pfont2 = pfont2->base; |
208 | 0 | if (pfont1 == pfont2) |
209 | 0 | return true; |
210 | 0 | switch (pfont1->FontType) { |
211 | 0 | case 1: case 3: |
212 | 0 | if (pfont1->FontType == pfont2->FontType) |
213 | 0 | break; |
214 | 0 | default: |
215 | 0 | return false; |
216 | 0 | } |
217 | | /* The following, while peculiar, appears to match CPSI. */ |
218 | 0 | { |
219 | 0 | const gs_uid *puid1 = &((const gs_font_base *)pfont1)->UID; |
220 | 0 | const gs_uid *puid2 = &((const gs_font_base *)pfont2)->UID; |
221 | 0 | if (uid_is_UniqueID(puid1) || uid_is_UniqueID(puid2) || |
222 | 0 | ((uid_is_XUID(puid1) || uid_is_XUID(puid2)) && |
223 | 0 | !uid_equal(puid1, puid2))) |
224 | 0 | return false; |
225 | 0 | } |
226 | 0 | { |
227 | 0 | const font_data *pfd1 = (const font_data *)pfont1->client_data; |
228 | 0 | const font_data *pfd2 = (const font_data *)pfont2->client_data; |
229 | |
|
230 | 0 | if (!(obj_eq(mem, &pfd1->BuildChar, &pfd2->BuildChar) && |
231 | 0 | obj_eq(mem, &pfd1->BuildGlyph, &pfd2->BuildGlyph) && |
232 | 0 | obj_eq(mem, &pfd1->Encoding, &pfd2->Encoding) && |
233 | 0 | obj_eq(mem, &pfd1->CharStrings, &pfd2->CharStrings))) |
234 | 0 | return false; |
235 | 0 | if (pfont1->FontType == 1) { |
236 | 0 | ref *ppd1, *ppd2; |
237 | |
|
238 | 0 | if (dict_find_string(&pfd1->dict, "Private", &ppd1) > 0 && |
239 | 0 | dict_find_string(&pfd2->dict, "Private", &ppd2) > 0 && |
240 | 0 | !obj_eq(mem, ppd1, ppd2)) |
241 | 0 | return false; |
242 | 0 | } |
243 | 0 | } |
244 | 0 | return true; |
245 | 0 | } |
246 | | |
247 | | /* Compare two objects for identity. */ |
248 | | bool |
249 | | obj_ident_eq(const gs_memory_t *mem, const ref * pref1, const ref * pref2) |
250 | 0 | { |
251 | 0 | if (r_type(pref1) != r_type(pref2)) |
252 | 0 | return false; |
253 | 0 | if (r_has_type(pref1, t_string)) |
254 | 0 | return (pref1->value.bytes == pref2->value.bytes && |
255 | 0 | r_size(pref1) == r_size(pref2)); |
256 | 0 | return obj_eq(mem, pref1, pref2); |
257 | 0 | } |
258 | | |
259 | | /* |
260 | | * Set *pchars and *plen to point to the data of a name or string, and |
261 | | * return 0. If the object isn't a name or string, return gs_error_typecheck. |
262 | | * If the object is a string without read access, return gs_error_invalidaccess. |
263 | | */ |
264 | | int |
265 | | obj_string_data(const gs_memory_t *mem, const ref *op, const byte **pchars, uint *plen) |
266 | 326M | { |
267 | 326M | switch (r_type(op)) { |
268 | 219M | case t_name: { |
269 | 219M | ref nref; |
270 | | |
271 | 219M | name_string_ref(mem, op, &nref); |
272 | 219M | *pchars = nref.value.bytes; |
273 | 219M | *plen = r_size(&nref); |
274 | 219M | return 0; |
275 | 0 | } |
276 | 107M | case t_string: |
277 | 107M | check_read(*op); |
278 | 107M | *pchars = op->value.bytes; |
279 | 107M | *plen = r_size(op); |
280 | 107M | return 0; |
281 | 0 | default: |
282 | 0 | return_error(gs_error_typecheck); |
283 | 326M | } |
284 | 326M | } |
285 | | |
286 | | /* |
287 | | * Create a printable representation of an object, a la cvs and = |
288 | | * (full_print = 0), == (full_print = 1), or === (full_print = 2). Return 0 |
289 | | * if OK, 1 if the destination wasn't large enough, gs_error_invalidaccess if the |
290 | | * object's contents weren't readable. If the return value is 0 or 1, |
291 | | * *prlen contains the amount of data returned. start_pos is the starting |
292 | | * output position -- the first start_pos bytes of output are discarded. |
293 | | * |
294 | | * When (restart = false) return gs_error_rangecheck the when destination wasn't |
295 | | * large enough without modifying the destination. This is needed for |
296 | | * compatibility with Adobe implementation of cvs and cvrs, which don't |
297 | | * change the destination string on failure. |
298 | | * |
299 | | * The mem argument is only used for getting the type of structures, |
300 | | * not for allocating; if it is NULL and full_print != 0, structures will |
301 | | * print as --(struct)--. |
302 | | * |
303 | | * This rather complex API is needed so that a client can call obj_cvp |
304 | | * repeatedly to print on a stream, which may require suspending at any |
305 | | * point to handle stream callouts. |
306 | | */ |
307 | | static void ensure_dot(char *, size_t); |
308 | | int |
309 | | obj_cvp(const ref * op, byte * str, uint len, uint * prlen, |
310 | | int full_print, uint start_pos, const gs_memory_t *mem, bool restart) |
311 | 377M | { |
312 | 377M | char buf[256]; /* big enough for any float, double, or struct name */ |
313 | 377M | const byte *data = (const byte *)buf; |
314 | 377M | uint size; |
315 | 377M | int code; |
316 | 377M | ref nref; |
317 | | |
318 | 377M | if (full_print) { |
319 | 13.5M | static const char * const type_strings[] = { REF_TYPE_PRINT_STRINGS }; |
320 | | |
321 | 13.5M | switch (r_btype(op)) { |
322 | 28 | case t_boolean: |
323 | 42.1k | case t_integer: |
324 | 42.1k | break; |
325 | 643 | case t_real: { |
326 | | /* |
327 | | * To get fully accurate output results for IEEE |
328 | | * single-precision floats (24 bits of mantissa), the ANSI %g |
329 | | * default of 6 digits is not enough; 9 are needed. |
330 | | * Unfortunately, using %.9g for floats (as opposed to doubles) |
331 | | * produces unfortunate artifacts such as 0.01 5 mul printing as |
332 | | * 0.049999997. Therefore, we print using %g, and if the result |
333 | | * isn't accurate enough, print again using %.9g. |
334 | | * Unfortunately, a few PostScript programs 'know' that the |
335 | | * printed representation of floats fits into 6 digits (e.g., |
336 | | * with cvs). We resolve this by letting cvs, cvrs, and = do |
337 | | * what the Adobe interpreters appear to do (use %g), and only |
338 | | * produce accurate output for ==, for which there is no |
339 | | * analogue of cvs. What a hack! |
340 | | */ |
341 | 643 | float value = op->value.realval; |
342 | 643 | float scanned; |
343 | 643 | code = gs_snprintf(buf, sizeof(buf), "%g", value); |
344 | 643 | if (code <= 0) |
345 | 0 | return_error(gs_error_undefinedresult); |
346 | 643 | code = sscanf(buf, "%f", &scanned); |
347 | 643 | if (code <= 0) |
348 | 8 | return_error(gs_error_undefinedresult); |
349 | 635 | if (scanned != value) |
350 | 314 | gs_snprintf(buf, sizeof(buf), "%.9g", value); |
351 | 635 | ensure_dot(buf, 256); |
352 | 635 | goto rs; |
353 | 643 | } |
354 | 5.72k | case t_operator: |
355 | 7.84k | case t_oparray: |
356 | 7.84k | code = obj_cvp(op, (byte *)buf + 2, sizeof(buf) - 4, &size, 0, 0, mem, restart); |
357 | 7.84k | if (code < 0) |
358 | 0 | return code; |
359 | 7.84k | buf[0] = buf[1] = buf[size + 2] = buf[size + 3] = '-'; |
360 | 7.84k | size += 4; |
361 | 7.84k | goto nl; |
362 | 79.3k | case t_name: |
363 | 79.3k | if (r_has_attr(op, a_executable)) { |
364 | 20.1k | code = obj_string_data(mem, op, &data, &size); |
365 | 20.1k | if (code < 0) |
366 | 0 | return code; |
367 | 20.1k | goto nl; |
368 | 20.1k | } |
369 | 59.1k | if (start_pos > 0) |
370 | 0 | return obj_cvp(op, str, len, prlen, 0, start_pos - 1, mem, restart); |
371 | 59.1k | if (len < 1) |
372 | 0 | return_error(gs_error_rangecheck); |
373 | 59.1k | code = obj_cvp(op, str + 1, len - 1, prlen, 0, 0, mem, restart); |
374 | 59.1k | if (code < 0) |
375 | 0 | return code; |
376 | 59.1k | str[0] = '/'; |
377 | 59.1k | ++*prlen; |
378 | 59.1k | return code; |
379 | 0 | case t_null: |
380 | 0 | data = (const byte *)"null"; |
381 | 0 | goto rs; |
382 | 13.4M | case t_string: |
383 | 13.4M | if (!r_has_attr(op, a_read)) |
384 | 13 | goto other; |
385 | 13.4M | size = r_size(op); |
386 | 13.4M | { |
387 | 13.4M | bool truncate = (full_print == 1 && size > CVP_MAX_STRING); |
388 | 13.4M | stream_cursor_read r; |
389 | 13.4M | stream_cursor_write w; |
390 | 13.4M | uint skip; |
391 | 13.4M | byte *wstr; |
392 | 13.4M | uint len1; |
393 | 13.4M | int status = 1; |
394 | | |
395 | 13.4M | if (start_pos == 0) { |
396 | 11.0M | if (len < 1) |
397 | 0 | return_error(gs_error_rangecheck); |
398 | 11.0M | str[0] = '('; |
399 | 11.0M | skip = 0; |
400 | 11.0M | wstr = str + 1; |
401 | 11.0M | } else { |
402 | 2.38M | skip = start_pos - 1; |
403 | 2.38M | wstr = str; |
404 | 2.38M | } |
405 | 13.4M | len1 = len + (str - wstr); |
406 | 13.4M | stream_cursor_read_init(&r, op->value.const_bytes, truncate ? CVP_MAX_STRING : size); |
407 | | |
408 | 15.1M | while (skip && status == 1) { |
409 | 4.11M | uint written; |
410 | | |
411 | 4.11M | stream_cursor_write_init(&w, (byte *)buf, min(skip + len1, sizeof(buf))); |
412 | 4.11M | status = s_PSSE_template.process(NULL, &r, &w, false); |
413 | | /* +1 accounts for crazy w.ptr initialisation - see stream_cursor_write_init() */ |
414 | 4.11M | written = (w.ptr - ((byte *)buf)) + 1; |
415 | 4.11M | if (written > skip) { |
416 | 2.36M | written -= skip; |
417 | 2.36M | memcpy(wstr, buf + skip, written); |
418 | 2.36M | wstr += written; |
419 | 2.36M | skip = 0; |
420 | 2.36M | break; |
421 | 2.36M | } |
422 | 1.75M | skip -= written; |
423 | 1.75M | } |
424 | | /* |
425 | | * We can reach here with status == 0 (and skip != 0) if |
426 | | * start_pos lies within the trailing ")" or "...)". |
427 | | */ |
428 | 13.4M | if (status == 0) { |
429 | | #ifdef DEBUG |
430 | | if (skip > (truncate ? 4 : 1)) { |
431 | | return_error(gs_error_Fatal); |
432 | | } |
433 | | #endif |
434 | 671k | } |
435 | 13.4M | stream_cursor_write_init(&w, (byte *)wstr, (size_t)((str + len) - wstr)); |
436 | 13.4M | if (status == 1) |
437 | 12.7M | status = s_PSSE_template.process(NULL, &r, &w, false); |
438 | 13.4M | *prlen = w.ptr - (str - 1); |
439 | 13.4M | if (status != 0) |
440 | 2.36M | return 1; |
441 | 11.0M | if (truncate) { |
442 | 167k | if (len - *prlen < 4 - skip) |
443 | 106 | return 1; |
444 | 167k | memcpy(w.ptr + 1, &"...)"[skip], 4 - skip); |
445 | 167k | *prlen += 4 - skip; |
446 | 10.9M | } else { |
447 | 10.9M | if (len - *prlen < 1 - skip) |
448 | 22.9k | return 1; |
449 | 10.8M | if (!skip) { |
450 | 10.8M | w.ptr[1] = ')'; |
451 | 10.8M | *prlen += 1; |
452 | 10.8M | } |
453 | 10.8M | } |
454 | 11.0M | } |
455 | 11.0M | return 0; |
456 | 0 | case t_astruct: |
457 | 0 | case t_struct: |
458 | 0 | if (r_is_foreign(op)) { |
459 | | /* gs_object_type may not work. */ |
460 | 0 | data = (const byte *)"-foreign-struct-"; |
461 | 0 | goto rs; |
462 | 0 | } |
463 | 0 | if (!mem) { |
464 | 0 | data = (const byte *)"-(struct)-"; |
465 | 0 | goto rs; |
466 | 0 | } |
467 | 0 | data = (const byte *) |
468 | 0 | gs_struct_type_name_string( |
469 | 0 | gs_object_type(mem, |
470 | 0 | (const obj_header_t *)op->value.pstruct)); |
471 | 0 | size = strlen((const char *)data); |
472 | 0 | if (size > 4 && !memcmp(data + size - 4, "type", 4)) |
473 | 0 | size -= 4; |
474 | 0 | if (size > sizeof(buf) - 3) |
475 | 0 | return_error(gs_error_rangecheck); |
476 | 0 | buf[0] = '-'; |
477 | 0 | memcpy(buf + 1, data, size); |
478 | 0 | buf[size + 1] = '-'; |
479 | 0 | size += 2; |
480 | 0 | data = (const byte *)buf; |
481 | 0 | goto nl; |
482 | 0 | case t_pdfctx: |
483 | 0 | data = (const byte *)"-pdfcontext-"; |
484 | 0 | goto rs; |
485 | 6.38k | default: |
486 | 6.40k | other: |
487 | 6.40k | { |
488 | 6.40k | int rtype = r_btype(op); |
489 | | |
490 | 6.40k | if (rtype >= countof(type_strings)) |
491 | 0 | return_error(gs_error_rangecheck); |
492 | 6.40k | data = (const byte *)type_strings[rtype]; |
493 | 6.40k | if (data == 0) |
494 | 0 | return_error(gs_error_rangecheck); |
495 | 6.40k | } |
496 | 6.40k | goto rs; |
497 | 13.5M | } |
498 | 13.5M | } |
499 | | /* full_print = 0 */ |
500 | 363M | switch (r_btype(op)) { |
501 | 51.1k | case t_boolean: |
502 | 51.1k | data = (const byte *)(op->value.boolval ? "true" : "false"); |
503 | 51.1k | break; |
504 | 19.7M | case t_integer: |
505 | 19.7M | gs_snprintf(buf, sizeof(buf), "%"PRIpsint, op->value.intval); |
506 | 19.7M | break; |
507 | 2.47M | case t_string: |
508 | 2.47M | check_read(*op); |
509 | | /* falls through */ |
510 | 221M | case t_name: |
511 | 221M | code = obj_string_data(mem, op, &data, &size); |
512 | 221M | if (code < 0) |
513 | 0 | return code; |
514 | 221M | goto nl; |
515 | 221M | case t_oparray: { |
516 | 104M | uint index = op_index(op); |
517 | 104M | const op_array_table *opt = get_op_array(mem, index); |
518 | | |
519 | 104M | name_index_ref(mem, opt->nx_table[index - opt->base_index], &nref); |
520 | 104M | name_string_ref(mem, &nref, &nref); |
521 | 104M | code = obj_string_data(mem, &nref, &data, &size); |
522 | 104M | if (code < 0) |
523 | 0 | return code; |
524 | 104M | goto nl; |
525 | 104M | } |
526 | 104M | case t_operator: { |
527 | | /* Recover the name from the initialization table. */ |
528 | 2.84M | uint index = op_index(op); |
529 | | |
530 | | /* |
531 | | * Check the validity of the index. (An out-of-bounds index |
532 | | * is only possible when examining an invalid object using |
533 | | * the debugger.) |
534 | | */ |
535 | 2.84M | if (index > 0 && index < op_def_count) { |
536 | 2.84M | data = (const byte *)(op_index_def(index)->oname + 1); |
537 | 2.84M | break; |
538 | 2.84M | } |
539 | | /* Internal operator, no name. */ |
540 | | #if defined(DEBUG) && DEBUG != 0 |
541 | | gs_snprintf(buf, sizeof(buf), "@"PRI_INTPTR, (intptr_t) op->value.opproc); |
542 | | #else |
543 | 111 | gs_snprintf(buf, sizeof(buf), "@anonymous_operator", (intptr_t) op->value.opproc); |
544 | 111 | #endif |
545 | 111 | break; |
546 | 2.84M | } |
547 | 2.40M | case t_real: |
548 | | /* |
549 | | * The value 0.0001 is a boundary case that the Adobe interpreters |
550 | | * print in f-format but at least some gs versions print in |
551 | | * e-format, presumably because of differences in the underlying C |
552 | | * library implementation. Work around this here. |
553 | | */ |
554 | 2.40M | if (op->value.realval == (float)0.0001) { |
555 | 34 | strncpy(buf, "0.0001", 256); |
556 | 2.40M | } else { |
557 | 2.40M | gs_snprintf(buf, sizeof(buf), "%g", op->value.realval); |
558 | 2.40M | } |
559 | 2.40M | ensure_dot(buf, 256); |
560 | 2.40M | break; |
561 | 11.8M | default: |
562 | 11.8M | data = (const byte *)"--nostringval--"; |
563 | 363M | } |
564 | 36.9M | rs: size = strlen((const char *)data); |
565 | 363M | nl: if (size < start_pos) |
566 | 0 | return_error(gs_error_rangecheck); |
567 | 363M | if (!restart && size > len) |
568 | 4 | return_error(gs_error_rangecheck); |
569 | 363M | size -= start_pos; |
570 | 363M | *prlen = min(size, len); |
571 | 363M | memmove(str, data + start_pos, *prlen); |
572 | 363M | return (size > len); |
573 | 363M | } |
574 | | /* |
575 | | * Make sure the converted form of a real number has at least one of an 'e' |
576 | | * or a decimal point, so it won't be mistaken for an integer. |
577 | | * Re-format the exponent to satisfy Genoa CET test. |
578 | | */ |
579 | | static void |
580 | | ensure_dot(char *buf, size_t buflen) |
581 | 2.40M | { |
582 | 2.40M | char *pe = strchr(buf, 'e'); |
583 | 2.40M | if (pe) { |
584 | 505k | int i; |
585 | 505k | (void)sscanf(pe + 1, "%d", &i); |
586 | 505k | buflen -= (size_t)(pe - buf); |
587 | | /* MSVC .net 2005 express doesn't support "%+02d" */ |
588 | 505k | if (i >= 0) |
589 | 133k | gs_snprintf(pe + 1, buflen, "+%02d", i); |
590 | 372k | else |
591 | 372k | gs_snprintf(pe + 1, buflen, "-%02d", -i); |
592 | 1.89M | } else if (strchr(buf, '.') == NULL) { |
593 | 1.51M | strcat(buf, ".0"); |
594 | 1.51M | } |
595 | 2.40M | } |
596 | | |
597 | | /* |
598 | | * Create a printable representation of an object, a la cvs and =. Return 0 |
599 | | * if OK, gs_error_rangecheck if the destination wasn't large enough, |
600 | | * gs_error_invalidaccess if the object's contents weren't readable. If pchars != |
601 | | * NULL, then if the object was a string or name, store a pointer to its |
602 | | * characters in *pchars even if it was too large; otherwise, set *pchars = |
603 | | * str. In any case, store the length in *prlen. |
604 | | */ |
605 | | int |
606 | | obj_cvs(const gs_memory_t *mem, const ref * op, byte * str, uint len, uint * prlen, |
607 | | const byte ** pchars) |
608 | 337M | { |
609 | 337M | int code = obj_cvp(op, str, len, prlen, 0, 0, mem, false); /* NB: NULL memptr */ |
610 | | |
611 | 337M | if (code == 1) { |
612 | 0 | if (pchars) |
613 | 0 | obj_string_data(mem, op, pchars, prlen); |
614 | 0 | return gs_note_error(gs_error_rangecheck); |
615 | 337M | } else { |
616 | 337M | if (pchars) |
617 | 337M | *pchars = str; |
618 | 337M | return code; |
619 | 337M | } |
620 | 337M | } |
621 | | |
622 | | /* Find the index of an operator that doesn't have one stored in it. */ |
623 | | ushort |
624 | | op_find_index(const ref * pref /* t_operator */ ) |
625 | 6.42M | { |
626 | 6.42M | op_proc_t proc = real_opproc(pref); |
627 | 6.42M | const op_def *const *opp = op_defs_all; |
628 | 6.42M | const op_def *const *opend = opp + (op_def_count / OP_DEFS_MAX_SIZE); |
629 | | |
630 | 120M | for (; opp < opend; ++opp) { |
631 | 120M | const op_def *def = *opp; |
632 | | |
633 | 779M | for (; def->oname != 0; ++def) |
634 | 664M | if (def->proc == proc) |
635 | 6.42M | return (opp - op_defs_all) * OP_DEFS_MAX_SIZE + (def - *opp); |
636 | 120M | } |
637 | | /* Lookup failed! This isn't possible.... */ |
638 | 219 | return 0; |
639 | 6.42M | } |
640 | | |
641 | | /* |
642 | | * Convert an operator index to an operator or oparray ref. |
643 | | * This is only used for debugging and for 'get' from packed arrays, |
644 | | * so it doesn't have to be very fast. |
645 | | */ |
646 | | void |
647 | | op_index_ref(const gs_memory_t *mem, uint index, ref * pref) |
648 | 249M | { |
649 | 249M | const op_array_table *opt; |
650 | | |
651 | 249M | if (op_index_is_operator(index)) { |
652 | 108M | make_oper(pref, index, op_index_proc(index)); |
653 | 108M | return; |
654 | 108M | } |
655 | 140M | opt = get_op_array(mem, index); |
656 | 140M | make_tasv(pref, t_oparray, opt->attrs, index, |
657 | 140M | const_refs, (opt->table.value.const_refs |
658 | 140M | + index - opt->base_index)); |
659 | 140M | } |
660 | | |
661 | | /* Get an element from an array of some kind. */ |
662 | | /* This is also used to index into Encoding vectors, */ |
663 | | /* the error name vector, etc. */ |
664 | | int |
665 | | array_get(const gs_memory_t *mem, const ref * aref, long index_long, ref * pref) |
666 | 11.5G | { |
667 | 11.5G | if ((ulong)index_long >= r_size(aref)) |
668 | 11.1k | return_error(gs_error_rangecheck); |
669 | 11.5G | switch (r_type(aref)) { |
670 | 8.18G | case t_array: |
671 | 8.18G | { |
672 | 8.18G | const ref *pvalue = aref->value.refs + index_long; |
673 | | |
674 | 8.18G | ref_assign(pref, pvalue); |
675 | 8.18G | } |
676 | 8.18G | break; |
677 | 2.32G | case t_mixedarray: |
678 | 2.32G | { |
679 | 2.32G | const ref_packed *packed = aref->value.packed; |
680 | 2.32G | uint index = (uint)index_long; |
681 | | |
682 | 33.9G | for (; index--;) |
683 | 31.6G | packed = packed_next(packed); |
684 | 2.32G | packed_get(mem, packed, pref); |
685 | 2.32G | } |
686 | 2.32G | break; |
687 | 1.02G | case t_shortarray: |
688 | 1.02G | { |
689 | 1.02G | const ref_packed *packed = aref->value.packed + index_long; |
690 | | |
691 | 1.02G | packed_get(mem, packed, pref); |
692 | 1.02G | } |
693 | 1.02G | break; |
694 | 7 | default: |
695 | 7 | return_error(gs_error_typecheck); |
696 | 11.5G | } |
697 | 11.5G | return 0; |
698 | 11.5G | } |
699 | | |
700 | | /* Get an element from a packed array. */ |
701 | | /* (This works for ordinary arrays too.) */ |
702 | | /* Source and destination are allowed to overlap if the source is packed, */ |
703 | | /* or if they are identical. */ |
704 | | void |
705 | | packed_get(const gs_memory_t *mem, const ref_packed * packed, ref * pref) |
706 | 4.56G | { |
707 | 4.56G | const ref_packed elt = *packed; |
708 | 4.56G | uint value = elt & packed_value_mask; |
709 | | |
710 | 4.56G | switch (elt >> r_packed_type_shift) { |
711 | 0 | default: /* (shouldn't happen) */ |
712 | 0 | make_null(pref); |
713 | 0 | break; |
714 | 109M | case pt_executable_operator: |
715 | 109M | op_index_ref(mem, value, pref); |
716 | 109M | break; |
717 | 827M | case pt_integer: |
718 | 827M | make_int(pref, (ps_int)value + packed_min_intval); |
719 | 827M | break; |
720 | 872M | case pt_literal_name: |
721 | 872M | name_index_ref(mem, value, pref); |
722 | 872M | break; |
723 | 2.57G | case pt_executable_name: |
724 | 2.57G | name_index_ref(mem, value, pref); |
725 | 2.57G | r_set_attrs(pref, a_executable); |
726 | 2.57G | break; |
727 | 187M | case pt_full_ref: |
728 | 187M | case pt_full_ref + 1: |
729 | 187M | ref_assign(pref, (const ref *)packed); |
730 | 4.56G | } |
731 | 4.56G | } |
732 | | |
733 | | /* Check to make sure an interval contains no object references */ |
734 | | /* to a space younger than a given one. */ |
735 | | /* Return 0 or gs_error_invalidaccess. */ |
736 | | int |
737 | | refs_check_space(const ref * bot, uint size, uint space) |
738 | 712M | { |
739 | 2.16G | for (; size--; bot++) |
740 | 1.45G | store_check_space(space, bot); |
741 | 712M | return 0; |
742 | 712M | } |
743 | | |
744 | | /* ------ String utilities ------ */ |
745 | | |
746 | | /* Convert a C string to a Ghostscript string */ |
747 | | int |
748 | | string_to_ref(const char *cstr, ref * pref, gs_ref_memory_t * mem, |
749 | | client_name_t cname) |
750 | 41.1k | { |
751 | 41.1k | uint size = strlen(cstr); |
752 | 41.1k | int code = gs_alloc_string_ref(mem, pref, a_all, size, cname); |
753 | | |
754 | 41.1k | if (code < 0) |
755 | 0 | return code; |
756 | 41.1k | memcpy(pref->value.bytes, cstr, size); |
757 | 41.1k | return 0; |
758 | 41.1k | } |
759 | | |
760 | | /* Convert a Ghostscript string to a C string. */ |
761 | | /* Return 0 iff the buffer can't be allocated. */ |
762 | | char * |
763 | | ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname) |
764 | 1.27M | { |
765 | 1.27M | uint size = r_size(pref); |
766 | 1.27M | char *str = (char *)gs_alloc_string(mem, size + 1, cname); |
767 | | |
768 | 1.27M | if (str == 0) |
769 | 0 | return 0; |
770 | 1.27M | memcpy(str, (const char *)pref->value.bytes, size); |
771 | 1.27M | str[size] = 0; |
772 | 1.27M | return str; |
773 | 1.27M | } |
774 | | |
775 | | /* ------ Operand utilities ------ */ |
776 | | |
777 | | /* Get N numeric operands from the stack or an array. */ |
778 | | /* Return a bit-mask indicating which ones are integers, */ |
779 | | /* or a (negative) error indication. */ |
780 | | /* The 1-bit in the bit-mask refers to the first operand. */ |
781 | | /* Store float versions of the operands at pval. */ |
782 | | /* The stack underflow check (check for t__invalid) is harmless */ |
783 | | /* if the operands come from somewhere other than the stack. */ |
784 | | int |
785 | | num_params(const ref * op, int count, double *pval) |
786 | 99.6M | { |
787 | 99.6M | int mask = 0; |
788 | | |
789 | 99.6M | pval += count; |
790 | 564M | while (--count >= 0) { |
791 | 464M | mask <<= 1; |
792 | 464M | switch (r_type(op)) { |
793 | 100M | case t_real: |
794 | 100M | *--pval = op->value.realval; |
795 | 100M | break; |
796 | 363M | case t_integer: |
797 | 363M | *--pval = (double)op->value.intval; |
798 | 363M | mask++; |
799 | 363M | break; |
800 | 93 | case t__invalid: |
801 | 93 | return_error(gs_error_stackunderflow); |
802 | 1.35k | default: |
803 | 1.35k | return_error(gs_error_typecheck); |
804 | 464M | } |
805 | 464M | op--; |
806 | 464M | } |
807 | | /* If count is very large, mask might overflow. */ |
808 | | /* In this case we clearly don't care about the value of mask. */ |
809 | 99.6M | return (mask < 0 ? 0 : mask); |
810 | 99.6M | } |
811 | | /* float_params doesn't bother to keep track of the mask. */ |
812 | | int |
813 | | float_params(const ref * op, int count, float *pval) |
814 | 54.8M | { |
815 | 221M | for (pval += count; --count >= 0; --op) |
816 | 166M | switch (r_type(op)) { |
817 | 51.3M | case t_real: |
818 | 51.3M | *--pval = op->value.realval; |
819 | 51.3M | break; |
820 | 115M | case t_integer: |
821 | 115M | *--pval = (float)op->value.intval; |
822 | 115M | break; |
823 | 73 | case t__invalid: |
824 | 73 | return_error(gs_error_stackunderflow); |
825 | 51 | default: |
826 | 51 | return_error(gs_error_typecheck); |
827 | 166M | } |
828 | 54.8M | return 0; |
829 | 54.8M | } |
830 | | |
831 | | /* Get N numeric parameters (as floating point numbers) from an array */ |
832 | | int |
833 | | process_float_array(const gs_memory_t *mem, const ref * parray, int count, float * pval) |
834 | 2.05M | { |
835 | 2.05M | int code = 0, indx0 = 0; |
836 | | |
837 | | /* we assume parray is an array of some type, of adequate length */ |
838 | 2.05M | if (r_has_type(parray, t_array)) |
839 | 1.48M | return float_params(parray->value.refs + count - 1, count, pval); |
840 | | |
841 | | /* short/mixed array; convert the entries to refs */ |
842 | 1.14M | while (count > 0 && code >= 0) { |
843 | 570k | int i, subcount; |
844 | 570k | ref ref_buff[20]; /* 20 is arbitrary */ |
845 | | |
846 | 570k | subcount = (count > countof(ref_buff) ? countof(ref_buff) : count); |
847 | 1.71M | for (i = 0; i < subcount && code >= 0; i++) |
848 | 1.14M | code = array_get(mem, parray, (long)(i + indx0), &ref_buff[i]); |
849 | 570k | if (code >= 0) |
850 | 570k | code = float_params(ref_buff + subcount - 1, subcount, pval); |
851 | 570k | count -= subcount; |
852 | 570k | pval += subcount; |
853 | 570k | indx0 += subcount; |
854 | 570k | } |
855 | | |
856 | 570k | return code; |
857 | 2.05M | } |
858 | | |
859 | | /* Get a single real parameter. */ |
860 | | /* The only possible errors are gs_error_typecheck and gs_error_stackunderflow. */ |
861 | | /* If an error is returned, the return value is not updated. */ |
862 | | int |
863 | | real_param(const ref * op, double *pparam) |
864 | 184M | { |
865 | 184M | switch (r_type(op)) { |
866 | 84.7M | case t_integer: |
867 | 84.7M | *pparam = (double)op->value.intval; |
868 | 84.7M | break; |
869 | 99.7M | case t_real: |
870 | 99.7M | *pparam = op->value.realval; |
871 | 99.7M | break; |
872 | 28 | case t__invalid: |
873 | 28 | return_error(gs_error_stackunderflow); |
874 | 3.36k | default: |
875 | 3.36k | return_error(gs_error_typecheck); |
876 | 184M | } |
877 | 184M | return 0; |
878 | 184M | } |
879 | | int |
880 | | float_param(const ref * op, float *pparam) |
881 | 3.60M | { |
882 | 3.60M | double dval; |
883 | 3.60M | int code = real_param(op, &dval); |
884 | | |
885 | 3.60M | if (code >= 0) |
886 | 3.60M | *pparam = (float)dval; /* can't overflow */ |
887 | 3.60M | return code; |
888 | 3.60M | } |
889 | | |
890 | | /* Get an integer parameter in a given range. */ |
891 | | int |
892 | | int_param(const ref * op, int max_value, int *pparam) |
893 | 1.47M | { |
894 | 1.47M | check_int_leu(*op, max_value); |
895 | 1.47M | *pparam = (int)op->value.intval; |
896 | 1.47M | return 0; |
897 | 1.47M | } |
898 | | |
899 | | /* Make real values on the operand stack. */ |
900 | | int |
901 | | make_reals(ref * op, const double *pval, int count) |
902 | 136k | { |
903 | | /* This should return gs_error_limitcheck if any real is too large */ |
904 | | /* to fit into a float on the stack. */ |
905 | 680k | for (; count--; op++, pval++) |
906 | 544k | make_real(op, *pval); |
907 | 136k | return 0; |
908 | 136k | } |
909 | | int |
910 | | make_floats(ref * op, const float *pval, int count) |
911 | 5.47M | { |
912 | | /* This should return gs_error_undefinedresult for infinities. */ |
913 | 20.0M | for (; count--; op++, pval++) |
914 | 14.5M | make_real(op, *pval); |
915 | 5.47M | return 0; |
916 | 5.47M | } |
917 | | |
918 | | /* Compute the error code when check_proc fails. */ |
919 | | /* Note that the client, not this procedure, uses return_error. */ |
920 | | /* The stack underflow check is harmless in the off-stack case. */ |
921 | | int |
922 | | check_proc_failed(const ref * pref) |
923 | 170 | { |
924 | 170 | if (r_is_array(pref)) { |
925 | 15 | if (r_has_attr(pref, a_executable)) |
926 | 0 | return gs_error_invalidaccess; |
927 | 15 | else |
928 | 15 | return gs_error_typecheck; |
929 | 155 | } else { |
930 | 155 | if (r_has_type(pref, t__invalid)) |
931 | 40 | return gs_error_stackunderflow; |
932 | 115 | else |
933 | 115 | return gs_error_typecheck; |
934 | 155 | } |
935 | 170 | } |
936 | | |
937 | | /* Compute the error code when a type check on the stack fails. */ |
938 | | /* Note that the client, not this procedure, uses return_error. */ |
939 | | int |
940 | | check_type_failed(const ref * op) |
941 | 104M | { |
942 | 104M | return (r_has_type(op, t__invalid) ? gs_error_stackunderflow : gs_error_typecheck); |
943 | 104M | } |
944 | | |
945 | | /* ------ Matrix utilities ------ */ |
946 | | |
947 | | /* Read a matrix operand. */ |
948 | | /* Return 0 if OK, error code if not. */ |
949 | | int |
950 | | read_matrix(const gs_memory_t *mem, const ref * op, gs_matrix * pmat) |
951 | 4.30M | { |
952 | 4.30M | int code; |
953 | 4.30M | ref values[6]; |
954 | 4.30M | const ref *pvalues; |
955 | | |
956 | 4.30M | switch (r_type(op)) { |
957 | 4.30M | case t_array: |
958 | 4.30M | pvalues = op->value.refs; |
959 | 4.30M | break; |
960 | 0 | case t_mixedarray: |
961 | 7 | case t_shortarray: |
962 | 7 | { |
963 | 7 | int i; |
964 | | |
965 | 37 | for (i = 0; i < 6; ++i) { |
966 | 32 | code = array_get(mem, op, (long)i, &values[i]); |
967 | 32 | if (code < 0) |
968 | 2 | return code; |
969 | 32 | } |
970 | 5 | pvalues = values; |
971 | 5 | } |
972 | 0 | break; |
973 | 222 | default: |
974 | 222 | return_op_typecheck(op); |
975 | 4.30M | } |
976 | 4.30M | check_read(*op); |
977 | 4.30M | if (r_size(op) != 6) |
978 | 21 | return_error(gs_error_rangecheck); |
979 | 4.30M | code = float_params(pvalues + 5, 6, (float *)pmat); |
980 | 4.30M | return (code < 0 ? code : 0); |
981 | 4.30M | } |
982 | | |
983 | | /* Write a matrix operand. */ |
984 | | /* Return 0 if OK, error code if not. */ |
985 | | int |
986 | | write_matrix_in(ref * op, const gs_matrix * pmat, gs_dual_memory_t *idmemory, |
987 | | gs_ref_memory_t *imem) |
988 | 2.25M | { |
989 | 2.25M | ref *aptr; |
990 | 2.25M | const float *pel; |
991 | 2.25M | int i; |
992 | | |
993 | 2.25M | check_write_type(*op, t_array); |
994 | 2.25M | if (r_size(op) != 6) |
995 | 0 | return_error(gs_error_rangecheck); |
996 | 2.25M | aptr = op->value.refs; |
997 | 2.25M | pel = (const float *)pmat; |
998 | 15.7M | for (i = 5; i >= 0; i--, aptr++, pel++) { |
999 | 13.5M | if (idmemory) { |
1000 | 13.2M | ref_save(op, aptr, "write_matrix"); |
1001 | 13.2M | make_real_new(aptr, *pel); |
1002 | 13.2M | } else { |
1003 | 247k | make_tav(aptr, t_real, imemory_new_mask(imem), realval, *pel); |
1004 | 247k | } |
1005 | 13.5M | } |
1006 | 2.25M | return 0; |
1007 | 2.25M | } |