/src/ghostpdl/psi/iutil.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2022 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, 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 | 3.00M | { |
58 | 3.00M | ref *to = aref->value.refs + index; |
59 | 3.00M | int code = refs_check_space(from, size, r_space(aref)); |
60 | | |
61 | 3.00M | if (code < 0) |
62 | 0 | return code; |
63 | | /* We have to worry about aliasing.... */ |
64 | 3.00M | if (to <= from || from + size <= to) |
65 | 8.36M | while (size--) |
66 | 5.36M | 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 | 3.00M | return 0; |
71 | 3.00M | } |
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 | 4.64M | { |
84 | 106M | for (; size--; ++to) |
85 | 101M | make_ta(to, t_null, new_mask); |
86 | 4.64M | } |
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 | 21.1M | { |
94 | 21.1M | ref nref; |
95 | | |
96 | 21.1M | 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.62M | switch (r_type(pref1)) { |
103 | 40 | case t_integer: |
104 | 40 | return (r_has_type(pref2, t_real) && |
105 | 40 | pref2->value.realval == pref1->value.intval); |
106 | 0 | case t_real: |
107 | 0 | return (r_has_type(pref2, t_integer) && |
108 | 0 | pref2->value.intval == pref1->value.realval); |
109 | 1.13M | case t_name: |
110 | 1.13M | if (!r_has_type(pref2, t_string)) |
111 | 1.06M | return false; |
112 | 67.6k | name_string_ref(mem, pref1, &nref); |
113 | 67.6k | pref1 = &nref; |
114 | 67.6k | break; |
115 | 78.9k | case t_string: |
116 | 78.9k | if (!r_has_type(pref2, t_name)) |
117 | 9.56k | return false; |
118 | 69.3k | name_string_ref(mem, pref2, &nref); |
119 | 69.3k | pref2 = &nref; |
120 | 69.3k | 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 | 40 | case t_mixedarray: |
127 | 40 | 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 | 40 | return ((int)r_type(pref1) + (int)r_type(pref2) == |
133 | 40 | t_mixedarray + t_shortarray) && |
134 | 40 | r_size(pref1) == 0 && r_size(pref2) == 0; |
135 | 412k | default: |
136 | 412k | if (r_btype(pref1) != r_btype(pref2)) |
137 | 412k | return false; |
138 | 1.62M | } |
139 | 1.62M | } |
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 | 19.7M | switch (r_btype(pref1)) { |
145 | 6.28k | case t_array: |
146 | 6.28k | return ((pref1->value.refs == pref2->value.refs || |
147 | 6.28k | r_size(pref1) == 0) && |
148 | 6.28k | r_size(pref1) == r_size(pref2)); |
149 | 0 | case t_mixedarray: |
150 | 683 | case t_shortarray: |
151 | 683 | return ((pref1->value.packed == pref2->value.packed || |
152 | 683 | r_size(pref1) == 0) && |
153 | 683 | r_size(pref1) == r_size(pref2)); |
154 | 6.28k | case t_boolean: |
155 | 6.28k | return (pref1->value.boolval == pref2->value.boolval); |
156 | 56.1k | case t_dictionary: |
157 | 56.1k | return (pref1->value.pdict == pref2->value.pdict); |
158 | 669 | case t_file: |
159 | 669 | return (pref1->value.pfile == pref2->value.pfile && |
160 | 669 | r_size(pref1) == r_size(pref2)); |
161 | 8.56M | case t_integer: |
162 | 8.56M | return (pref1->value.intval == pref2->value.intval); |
163 | 2.45k | case t_mark: |
164 | 504k | case t_null: |
165 | 504k | return true; |
166 | 10.0M | case t_name: |
167 | 10.0M | return (pref1->value.pname == pref2->value.pname); |
168 | 0 | case t_oparray: |
169 | 0 | case t_operator: |
170 | 0 | return (op_index(pref1) == op_index(pref2)); |
171 | 0 | case t_real: |
172 | 0 | return (pref1->value.realval == pref2->value.realval); |
173 | 0 | case t_save: |
174 | 0 | return (pref2->value.saveid == pref1->value.saveid); |
175 | 549k | case t_string: |
176 | 549k | return (!bytes_compare(pref1->value.bytes, r_size(pref1), |
177 | 549k | 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 | 0 | case t_astruct: |
182 | 0 | case t_pdfctx: |
183 | 0 | 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 | 19.7M | } |
188 | 0 | return false; /* shouldn't happen! */ |
189 | 19.7M | } |
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 | 1.27M | { |
267 | 1.27M | switch (r_type(op)) { |
268 | 909k | case t_name: { |
269 | 909k | ref nref; |
270 | | |
271 | 909k | name_string_ref(mem, op, &nref); |
272 | 909k | *pchars = nref.value.bytes; |
273 | 909k | *plen = r_size(&nref); |
274 | 909k | return 0; |
275 | 0 | } |
276 | 362k | case t_string: |
277 | 362k | check_read(*op); |
278 | 362k | *pchars = op->value.bytes; |
279 | 362k | *plen = r_size(op); |
280 | 362k | return 0; |
281 | 0 | default: |
282 | 0 | return_error(gs_error_typecheck); |
283 | 1.27M | } |
284 | 1.27M | } |
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 | 1.39M | { |
312 | 1.39M | char buf[256]; /* big enough for any float, double, or struct name */ |
313 | 1.39M | const byte *data = (const byte *)buf; |
314 | 1.39M | uint size; |
315 | 1.39M | int code; |
316 | 1.39M | ref nref; |
317 | | |
318 | 1.39M | if (full_print) { |
319 | 23 | static const char * const type_strings[] = { REF_TYPE_PRINT_STRINGS }; |
320 | | |
321 | 23 | switch (r_btype(op)) { |
322 | 0 | case t_boolean: |
323 | 0 | case t_integer: |
324 | 0 | break; |
325 | 0 | 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 | 0 | float value = op->value.realval; |
342 | 0 | float scanned; |
343 | 0 | code = gs_snprintf(buf, sizeof(buf), "%g", value); |
344 | 0 | if (code <= 0) |
345 | 0 | return_error(gs_error_undefinedresult); |
346 | 0 | code = sscanf(buf, "%f", &scanned); |
347 | 0 | if (code <= 0) |
348 | 0 | return_error(gs_error_undefinedresult); |
349 | 0 | if (scanned != value) |
350 | 0 | gs_snprintf(buf, sizeof(buf), "%.9g", value); |
351 | 0 | ensure_dot(buf, 256); |
352 | 0 | goto rs; |
353 | 0 | } |
354 | 0 | case t_operator: |
355 | 0 | case t_oparray: |
356 | 0 | code = obj_cvp(op, (byte *)buf + 2, sizeof(buf) - 4, &size, 0, 0, mem, restart); |
357 | 0 | if (code < 0) |
358 | 0 | return code; |
359 | 0 | buf[0] = buf[1] = buf[size + 2] = buf[size + 3] = '-'; |
360 | 0 | size += 4; |
361 | 0 | goto nl; |
362 | 18 | case t_name: |
363 | 18 | if (r_has_attr(op, a_executable)) { |
364 | 1 | code = obj_string_data(mem, op, &data, &size); |
365 | 1 | if (code < 0) |
366 | 0 | return code; |
367 | 1 | goto nl; |
368 | 1 | } |
369 | 17 | if (start_pos > 0) |
370 | 0 | return obj_cvp(op, str, len, prlen, 0, start_pos - 1, mem, restart); |
371 | 17 | if (len < 1) |
372 | 0 | return_error(gs_error_rangecheck); |
373 | 17 | code = obj_cvp(op, str + 1, len - 1, prlen, 0, 0, mem, restart); |
374 | 17 | if (code < 0) |
375 | 0 | return code; |
376 | 17 | str[0] = '/'; |
377 | 17 | ++*prlen; |
378 | 17 | return code; |
379 | 0 | case t_null: |
380 | 0 | data = (const byte *)"null"; |
381 | 0 | goto rs; |
382 | 5 | case t_string: |
383 | 5 | if (!r_has_attr(op, a_read)) |
384 | 0 | goto other; |
385 | 5 | size = r_size(op); |
386 | 5 | { |
387 | 5 | bool truncate = (full_print == 1 && size > CVP_MAX_STRING); |
388 | 5 | stream_cursor_read r; |
389 | 5 | stream_cursor_write w; |
390 | 5 | uint skip; |
391 | 5 | byte *wstr; |
392 | 5 | uint len1; |
393 | 5 | int status = 1; |
394 | | |
395 | 5 | if (start_pos == 0) { |
396 | 2 | if (len < 1) |
397 | 0 | return_error(gs_error_rangecheck); |
398 | 2 | str[0] = '('; |
399 | 2 | skip = 0; |
400 | 2 | wstr = str + 1; |
401 | 3 | } else { |
402 | 3 | skip = start_pos - 1; |
403 | 3 | wstr = str; |
404 | 3 | } |
405 | 5 | len1 = len + (str - wstr); |
406 | 5 | stream_cursor_read_init(&r, op->value.const_bytes, truncate ? CVP_MAX_STRING : size); |
407 | | |
408 | 6 | while (skip && status == 1) { |
409 | 4 | uint written; |
410 | | |
411 | 4 | stream_cursor_write_init(&w, (byte *)buf, min(skip + len1, sizeof(buf))); |
412 | 4 | status = s_PSSE_template.process(NULL, &r, &w, false); |
413 | | /* +1 accounts for crazy w.ptr initialisation - see stream_cursor_write_init() */ |
414 | 4 | written = (w.ptr - ((byte *)buf)) + 1; |
415 | 4 | if (written > skip) { |
416 | 3 | written -= skip; |
417 | 3 | memcpy(wstr, buf + skip, written); |
418 | 3 | wstr += written; |
419 | 3 | skip = 0; |
420 | 3 | break; |
421 | 3 | } |
422 | 1 | skip -= written; |
423 | 1 | } |
424 | | /* |
425 | | * We can reach here with status == 0 (and skip != 0) if |
426 | | * start_pos lies within the trailing ")" or "...)". |
427 | | */ |
428 | 5 | if (status == 0) { |
429 | | #ifdef DEBUG |
430 | | if (skip > (truncate ? 4 : 1)) { |
431 | | return_error(gs_error_Fatal); |
432 | | } |
433 | | #endif |
434 | 1 | } |
435 | 5 | stream_cursor_write_init(&w, (byte *)wstr, (size_t)((str + len) - wstr)); |
436 | 5 | if (status == 1) |
437 | 4 | status = s_PSSE_template.process(NULL, &r, &w, false); |
438 | 5 | *prlen = w.ptr - (str - 1); |
439 | 5 | if (status != 0) |
440 | 3 | return 1; |
441 | 2 | if (truncate) { |
442 | 1 | if (len - *prlen < 4 - skip) |
443 | 0 | return 1; |
444 | 1 | memcpy(w.ptr + 1, &"...)"[skip], 4 - skip); |
445 | 1 | *prlen += 4 - skip; |
446 | 1 | } else { |
447 | 1 | if (len - *prlen < 1 - skip) |
448 | 0 | return 1; |
449 | 1 | if (!skip) { |
450 | 1 | w.ptr[1] = ')'; |
451 | 1 | *prlen += 1; |
452 | 1 | } |
453 | 1 | } |
454 | 2 | } |
455 | 2 | 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 | 0 | default: |
486 | 0 | other: |
487 | 0 | { |
488 | 0 | int rtype = r_btype(op); |
489 | |
|
490 | 0 | if (rtype >= countof(type_strings)) |
491 | 0 | return_error(gs_error_rangecheck); |
492 | 0 | data = (const byte *)type_strings[rtype]; |
493 | 0 | if (data == 0) |
494 | 0 | return_error(gs_error_rangecheck); |
495 | 0 | } |
496 | 0 | goto rs; |
497 | 23 | } |
498 | 23 | } |
499 | | /* full_print = 0 */ |
500 | 1.39M | switch (r_btype(op)) { |
501 | 12 | case t_boolean: |
502 | 12 | data = (const byte *)(op->value.boolval ? "true" : "false"); |
503 | 12 | break; |
504 | 45.9k | case t_integer: |
505 | 45.9k | gs_snprintf(buf, sizeof(buf), "%"PRIpsint, op->value.intval); |
506 | 45.9k | break; |
507 | 8.94k | case t_string: |
508 | 8.94k | check_read(*op); |
509 | | /* falls through */ |
510 | 917k | case t_name: |
511 | 917k | code = obj_string_data(mem, op, &data, &size); |
512 | 917k | if (code < 0) |
513 | 0 | return code; |
514 | 917k | goto nl; |
515 | 917k | case t_oparray: { |
516 | 353k | uint index = op_index(op); |
517 | 353k | const op_array_table *opt = get_op_array(mem, index); |
518 | | |
519 | 353k | name_index_ref(mem, opt->nx_table[index - opt->base_index], &nref); |
520 | 353k | name_string_ref(mem, &nref, &nref); |
521 | 353k | code = obj_string_data(mem, &nref, &data, &size); |
522 | 353k | if (code < 0) |
523 | 0 | return code; |
524 | 353k | goto nl; |
525 | 353k | } |
526 | 353k | case t_operator: { |
527 | | /* Recover the name from the initialization table. */ |
528 | 11.0k | 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 | 11.0k | if (index > 0 && index < op_def_count) { |
536 | 11.0k | data = (const byte *)(op_index_def(index)->oname + 1); |
537 | 11.0k | break; |
538 | 11.0k | } |
539 | | /* Internal operator, no name. */ |
540 | 0 | gs_snprintf(buf, sizeof(buf), "@"PRI_INTPTR, (intptr_t) op->value.opproc); |
541 | 0 | break; |
542 | 11.0k | } |
543 | 2 | case t_real: |
544 | | /* |
545 | | * The value 0.0001 is a boundary case that the Adobe interpreters |
546 | | * print in f-format but at least some gs versions print in |
547 | | * e-format, presumably because of differences in the underlying C |
548 | | * library implementation. Work around this here. |
549 | | */ |
550 | 2 | if (op->value.realval == (float)0.0001) { |
551 | 0 | strncpy(buf, "0.0001", 256); |
552 | 2 | } else { |
553 | 2 | gs_snprintf(buf, sizeof(buf), "%g", op->value.realval); |
554 | 2 | } |
555 | 2 | ensure_dot(buf, 256); |
556 | 2 | break; |
557 | 69.7k | default: |
558 | 69.7k | data = (const byte *)"--nostringval--"; |
559 | 1.39M | } |
560 | 126k | rs: size = strlen((const char *)data); |
561 | 1.39M | nl: if (size < start_pos) |
562 | 0 | return_error(gs_error_rangecheck); |
563 | 1.39M | if (!restart && size > len) |
564 | 0 | return_error(gs_error_rangecheck); |
565 | 1.39M | size -= start_pos; |
566 | 1.39M | *prlen = min(size, len); |
567 | 1.39M | memmove(str, data + start_pos, *prlen); |
568 | 1.39M | return (size > len); |
569 | 1.39M | } |
570 | | /* |
571 | | * Make sure the converted form of a real number has at least one of an 'e' |
572 | | * or a decimal point, so it won't be mistaken for an integer. |
573 | | * Re-format the exponent to satisfy Genoa CET test. |
574 | | */ |
575 | | static void |
576 | | ensure_dot(char *buf, size_t buflen) |
577 | 2 | { |
578 | 2 | char *pe = strchr(buf, 'e'); |
579 | 2 | if (pe) { |
580 | 0 | int i; |
581 | 0 | (void)sscanf(pe + 1, "%d", &i); |
582 | 0 | buflen -= (size_t)(pe - buf); |
583 | | /* MSVC .net 2005 express doesn't support "%+02d" */ |
584 | 0 | if (i >= 0) |
585 | 0 | gs_snprintf(pe + 1, buflen, "+%02d", i); |
586 | 0 | else |
587 | 0 | gs_snprintf(pe + 1, buflen, "-%02d", -i); |
588 | 2 | } else if (strchr(buf, '.') == NULL) { |
589 | 2 | strcat(buf, ".0"); |
590 | 2 | } |
591 | 2 | } |
592 | | |
593 | | /* |
594 | | * Create a printable representation of an object, a la cvs and =. Return 0 |
595 | | * if OK, gs_error_rangecheck if the destination wasn't large enough, |
596 | | * gs_error_invalidaccess if the object's contents weren't readable. If pchars != |
597 | | * NULL, then if the object was a string or name, store a pointer to its |
598 | | * characters in *pchars even if it was too large; otherwise, set *pchars = |
599 | | * str. In any case, store the length in *prlen. |
600 | | */ |
601 | | int |
602 | | obj_cvs(const gs_memory_t *mem, const ref * op, byte * str, uint len, uint * prlen, |
603 | | const byte ** pchars) |
604 | 1.32M | { |
605 | 1.32M | int code = obj_cvp(op, str, len, prlen, 0, 0, mem, false); /* NB: NULL memptr */ |
606 | | |
607 | 1.32M | if (code == 1) { |
608 | 0 | if (pchars) |
609 | 0 | obj_string_data(mem, op, pchars, prlen); |
610 | 0 | return gs_note_error(gs_error_rangecheck); |
611 | 1.32M | } else { |
612 | 1.32M | if (pchars) |
613 | 1.32M | *pchars = str; |
614 | 1.32M | return code; |
615 | 1.32M | } |
616 | 1.32M | } |
617 | | |
618 | | /* Find the index of an operator that doesn't have one stored in it. */ |
619 | | ushort |
620 | | op_find_index(const ref * pref /* t_operator */ ) |
621 | 6.36k | { |
622 | 6.36k | op_proc_t proc = real_opproc(pref); |
623 | 6.36k | const op_def *const *opp = op_defs_all; |
624 | 6.36k | const op_def *const *opend = opp + (op_def_count / OP_DEFS_MAX_SIZE); |
625 | | |
626 | 118k | for (; opp < opend; ++opp) { |
627 | 118k | const op_def *def = *opp; |
628 | | |
629 | 776k | for (; def->oname != 0; ++def) |
630 | 664k | if (def->proc == proc) |
631 | 6.36k | return (opp - op_defs_all) * OP_DEFS_MAX_SIZE + (def - *opp); |
632 | 118k | } |
633 | | /* Lookup failed! This isn't possible.... */ |
634 | 0 | return 0; |
635 | 6.36k | } |
636 | | |
637 | | /* |
638 | | * Convert an operator index to an operator or oparray ref. |
639 | | * This is only used for debugging and for 'get' from packed arrays, |
640 | | * so it doesn't have to be very fast. |
641 | | */ |
642 | | void |
643 | | op_index_ref(const gs_memory_t *mem, uint index, ref * pref) |
644 | 860k | { |
645 | 860k | const op_array_table *opt; |
646 | | |
647 | 860k | if (op_index_is_operator(index)) { |
648 | 370k | make_oper(pref, index, op_index_proc(index)); |
649 | 370k | return; |
650 | 370k | } |
651 | 490k | opt = get_op_array(mem, index); |
652 | 490k | make_tasv(pref, t_oparray, opt->attrs, index, |
653 | 490k | const_refs, (opt->table.value.const_refs |
654 | 490k | + index - opt->base_index)); |
655 | 490k | } |
656 | | |
657 | | /* Get an element from an array of some kind. */ |
658 | | /* This is also used to index into Encoding vectors, */ |
659 | | /* the error name vector, etc. */ |
660 | | int |
661 | | array_get(const gs_memory_t *mem, const ref * aref, long index_long, ref * pref) |
662 | 102M | { |
663 | 102M | if ((ulong)index_long >= r_size(aref)) |
664 | 0 | return_error(gs_error_rangecheck); |
665 | 102M | switch (r_type(aref)) { |
666 | 89.0M | case t_array: |
667 | 89.0M | { |
668 | 89.0M | const ref *pvalue = aref->value.refs + index_long; |
669 | | |
670 | 89.0M | ref_assign(pref, pvalue); |
671 | 89.0M | } |
672 | 89.0M | break; |
673 | 8.29M | case t_mixedarray: |
674 | 8.29M | { |
675 | 8.29M | const ref_packed *packed = aref->value.packed; |
676 | 8.29M | uint index = (uint)index_long; |
677 | | |
678 | 128M | for (; index--;) |
679 | 119M | packed = packed_next(packed); |
680 | 8.29M | packed_get(mem, packed, pref); |
681 | 8.29M | } |
682 | 8.29M | break; |
683 | 4.70M | case t_shortarray: |
684 | 4.70M | { |
685 | 4.70M | const ref_packed *packed = aref->value.packed + index_long; |
686 | | |
687 | 4.70M | packed_get(mem, packed, pref); |
688 | 4.70M | } |
689 | 4.70M | break; |
690 | 0 | default: |
691 | 0 | return_error(gs_error_typecheck); |
692 | 102M | } |
693 | 102M | return 0; |
694 | 102M | } |
695 | | |
696 | | /* Get an element from a packed array. */ |
697 | | /* (This works for ordinary arrays too.) */ |
698 | | /* Source and destination are allowed to overlap if the source is packed, */ |
699 | | /* or if they are identical. */ |
700 | | void |
701 | | packed_get(const gs_memory_t *mem, const ref_packed * packed, ref * pref) |
702 | 21.6M | { |
703 | 21.6M | const ref_packed elt = *packed; |
704 | 21.6M | uint value = elt & packed_value_mask; |
705 | | |
706 | 21.6M | switch (elt >> r_packed_type_shift) { |
707 | 0 | default: /* (shouldn't happen) */ |
708 | 0 | make_null(pref); |
709 | 0 | break; |
710 | 373k | case pt_executable_operator: |
711 | 373k | op_index_ref(mem, value, pref); |
712 | 373k | break; |
713 | 3.80M | case pt_integer: |
714 | 3.80M | make_int(pref, (ps_int)value + packed_min_intval); |
715 | 3.80M | break; |
716 | 3.96M | case pt_literal_name: |
717 | 3.96M | name_index_ref(mem, value, pref); |
718 | 3.96M | break; |
719 | 12.7M | case pt_executable_name: |
720 | 12.7M | name_index_ref(mem, value, pref); |
721 | 12.7M | r_set_attrs(pref, a_executable); |
722 | 12.7M | break; |
723 | 730k | case pt_full_ref: |
724 | 730k | case pt_full_ref + 1: |
725 | 730k | ref_assign(pref, (const ref *)packed); |
726 | 21.6M | } |
727 | 21.6M | } |
728 | | |
729 | | /* Check to make sure an interval contains no object references */ |
730 | | /* to a space younger than a given one. */ |
731 | | /* Return 0 or gs_error_invalidaccess. */ |
732 | | int |
733 | | refs_check_space(const ref * bot, uint size, uint space) |
734 | 3.00M | { |
735 | 9.06M | for (; size--; bot++) |
736 | 6.06M | store_check_space(space, bot); |
737 | 3.00M | return 0; |
738 | 3.00M | } |
739 | | |
740 | | /* ------ String utilities ------ */ |
741 | | |
742 | | /* Convert a C string to a Ghostscript string */ |
743 | | int |
744 | | string_to_ref(const char *cstr, ref * pref, gs_ref_memory_t * mem, |
745 | | client_name_t cname) |
746 | 9 | { |
747 | 9 | uint size = strlen(cstr); |
748 | 9 | int code = gs_alloc_string_ref(mem, pref, a_all, size, cname); |
749 | | |
750 | 9 | if (code < 0) |
751 | 0 | return code; |
752 | 9 | memcpy(pref->value.bytes, cstr, size); |
753 | 9 | return 0; |
754 | 9 | } |
755 | | |
756 | | /* Convert a Ghostscript string to a C string. */ |
757 | | /* Return 0 iff the buffer can't be allocated. */ |
758 | | char * |
759 | | ref_to_string(const ref * pref, gs_memory_t * mem, client_name_t cname) |
760 | 5.46k | { |
761 | 5.46k | uint size = r_size(pref); |
762 | 5.46k | char *str = (char *)gs_alloc_string(mem, size + 1, cname); |
763 | | |
764 | 5.46k | if (str == 0) |
765 | 0 | return 0; |
766 | 5.46k | memcpy(str, (const char *)pref->value.bytes, size); |
767 | 5.46k | str[size] = 0; |
768 | 5.46k | return str; |
769 | 5.46k | } |
770 | | |
771 | | /* ------ Operand utilities ------ */ |
772 | | |
773 | | /* Get N numeric operands from the stack or an array. */ |
774 | | /* Return a bit-mask indicating which ones are integers, */ |
775 | | /* or a (negative) error indication. */ |
776 | | /* The 1-bit in the bit-mask refers to the first operand. */ |
777 | | /* Store float versions of the operands at pval. */ |
778 | | /* The stack underflow check (check for t__invalid) is harmless */ |
779 | | /* if the operands come from somewhere other than the stack. */ |
780 | | int |
781 | | num_params(const ref * op, int count, double *pval) |
782 | 369k | { |
783 | 369k | int mask = 0; |
784 | | |
785 | 369k | pval += count; |
786 | 1.77M | while (--count >= 0) { |
787 | 1.40M | mask <<= 1; |
788 | 1.40M | switch (r_type(op)) { |
789 | 731k | case t_real: |
790 | 731k | *--pval = op->value.realval; |
791 | 731k | break; |
792 | 678k | case t_integer: |
793 | 678k | *--pval = (double)op->value.intval; |
794 | 678k | mask++; |
795 | 678k | break; |
796 | 0 | case t__invalid: |
797 | 0 | return_error(gs_error_stackunderflow); |
798 | 0 | default: |
799 | 0 | return_error(gs_error_typecheck); |
800 | 1.40M | } |
801 | 1.40M | op--; |
802 | 1.40M | } |
803 | | /* If count is very large, mask might overflow. */ |
804 | | /* In this case we clearly don't care about the value of mask. */ |
805 | 369k | return (mask < 0 ? 0 : mask); |
806 | 369k | } |
807 | | /* float_params doesn't bother to keep track of the mask. */ |
808 | | int |
809 | | float_params(const ref * op, int count, float *pval) |
810 | 148k | { |
811 | 608k | for (pval += count; --count >= 0; --op) |
812 | 459k | switch (r_type(op)) { |
813 | 82.4k | case t_real: |
814 | 82.4k | *--pval = op->value.realval; |
815 | 82.4k | break; |
816 | 376k | case t_integer: |
817 | 376k | *--pval = (float)op->value.intval; |
818 | 376k | break; |
819 | 0 | case t__invalid: |
820 | 0 | return_error(gs_error_stackunderflow); |
821 | 0 | default: |
822 | 0 | return_error(gs_error_typecheck); |
823 | 459k | } |
824 | 148k | return 0; |
825 | 148k | } |
826 | | |
827 | | /* Get N numeric parameters (as floating point numbers) from an array */ |
828 | | int |
829 | | process_float_array(const gs_memory_t *mem, const ref * parray, int count, float * pval) |
830 | 3.41k | { |
831 | 3.41k | int code = 0, indx0 = 0; |
832 | | |
833 | | /* we assume parray is an array of some type, of adequate length */ |
834 | 3.41k | if (r_has_type(parray, t_array)) |
835 | 3.41k | return float_params(parray->value.refs + count - 1, count, pval); |
836 | | |
837 | | /* short/mixed array; convert the entries to refs */ |
838 | 0 | while (count > 0 && code >= 0) { |
839 | 0 | int i, subcount; |
840 | 0 | ref ref_buff[20]; /* 20 is arbitrary */ |
841 | |
|
842 | 0 | subcount = (count > countof(ref_buff) ? countof(ref_buff) : count); |
843 | 0 | for (i = 0; i < subcount && code >= 0; i++) |
844 | 0 | code = array_get(mem, parray, (long)(i + indx0), &ref_buff[i]); |
845 | 0 | if (code >= 0) |
846 | 0 | code = float_params(ref_buff + subcount - 1, subcount, pval); |
847 | 0 | count -= subcount; |
848 | 0 | pval += subcount; |
849 | 0 | indx0 += subcount; |
850 | 0 | } |
851 | |
|
852 | 0 | return code; |
853 | 3.41k | } |
854 | | |
855 | | /* Get a single real parameter. */ |
856 | | /* The only possible errors are gs_error_typecheck and gs_error_stackunderflow. */ |
857 | | /* If an error is returned, the return value is not updated. */ |
858 | | int |
859 | | real_param(const ref * op, double *pparam) |
860 | 1.20M | { |
861 | 1.20M | switch (r_type(op)) { |
862 | 349k | case t_integer: |
863 | 349k | *pparam = (double)op->value.intval; |
864 | 349k | break; |
865 | 852k | case t_real: |
866 | 852k | *pparam = op->value.realval; |
867 | 852k | break; |
868 | 0 | case t__invalid: |
869 | 0 | return_error(gs_error_stackunderflow); |
870 | 0 | default: |
871 | 0 | return_error(gs_error_typecheck); |
872 | 1.20M | } |
873 | 1.20M | return 0; |
874 | 1.20M | } |
875 | | int |
876 | | float_param(const ref * op, float *pparam) |
877 | 35.7k | { |
878 | 35.7k | double dval; |
879 | 35.7k | int code = real_param(op, &dval); |
880 | | |
881 | 35.7k | if (code >= 0) |
882 | 35.7k | *pparam = (float)dval; /* can't overflow */ |
883 | 35.7k | return code; |
884 | 35.7k | } |
885 | | |
886 | | /* Get an integer parameter in a given range. */ |
887 | | int |
888 | | int_param(const ref * op, int max_value, int *pparam) |
889 | 2 | { |
890 | 2 | check_int_leu(*op, max_value); |
891 | 2 | *pparam = (int)op->value.intval; |
892 | 2 | return 0; |
893 | 2 | } |
894 | | |
895 | | /* Make real values on the operand stack. */ |
896 | | int |
897 | | make_reals(ref * op, const double *pval, int count) |
898 | 0 | { |
899 | | /* This should return gs_error_limitcheck if any real is too large */ |
900 | | /* to fit into a float on the stack. */ |
901 | 0 | for (; count--; op++, pval++) |
902 | 0 | make_real(op, *pval); |
903 | 0 | return 0; |
904 | 0 | } |
905 | | int |
906 | | make_floats(ref * op, const float *pval, int count) |
907 | 6.80k | { |
908 | | /* This should return gs_error_undefinedresult for infinities. */ |
909 | 30.7k | for (; count--; op++, pval++) |
910 | 23.9k | make_real(op, *pval); |
911 | 6.80k | return 0; |
912 | 6.80k | } |
913 | | |
914 | | /* Compute the error code when check_proc fails. */ |
915 | | /* Note that the client, not this procedure, uses return_error. */ |
916 | | /* The stack underflow check is harmless in the off-stack case. */ |
917 | | int |
918 | | check_proc_failed(const ref * pref) |
919 | 0 | { |
920 | 0 | if (r_is_array(pref)) { |
921 | 0 | if (r_has_attr(pref, a_executable)) |
922 | 0 | return gs_error_invalidaccess; |
923 | 0 | else |
924 | 0 | return gs_error_typecheck; |
925 | 0 | } else { |
926 | 0 | if (r_has_type(pref, t__invalid)) |
927 | 0 | return gs_error_stackunderflow; |
928 | 0 | else |
929 | 0 | return gs_error_typecheck; |
930 | 0 | } |
931 | 0 | } |
932 | | |
933 | | /* Compute the error code when a type check on the stack fails. */ |
934 | | /* Note that the client, not this procedure, uses return_error. */ |
935 | | int |
936 | | check_type_failed(const ref * op) |
937 | 351k | { |
938 | 351k | return (r_has_type(op, t__invalid) ? gs_error_stackunderflow : gs_error_typecheck); |
939 | 351k | } |
940 | | |
941 | | /* ------ Matrix utilities ------ */ |
942 | | |
943 | | /* Read a matrix operand. */ |
944 | | /* Return 0 if OK, error code if not. */ |
945 | | int |
946 | | read_matrix(const gs_memory_t *mem, const ref * op, gs_matrix * pmat) |
947 | 9.42k | { |
948 | 9.42k | int code; |
949 | 9.42k | ref values[6]; |
950 | 9.42k | const ref *pvalues; |
951 | | |
952 | 9.42k | switch (r_type(op)) { |
953 | 9.42k | case t_array: |
954 | 9.42k | pvalues = op->value.refs; |
955 | 9.42k | break; |
956 | 0 | case t_mixedarray: |
957 | 0 | case t_shortarray: |
958 | 0 | { |
959 | 0 | int i; |
960 | |
|
961 | 0 | for (i = 0; i < 6; ++i) { |
962 | 0 | code = array_get(mem, op, (long)i, &values[i]); |
963 | 0 | if (code < 0) |
964 | 0 | return code; |
965 | 0 | } |
966 | 0 | pvalues = values; |
967 | 0 | } |
968 | 0 | break; |
969 | 0 | default: |
970 | 0 | return_op_typecheck(op); |
971 | 9.42k | } |
972 | 9.42k | check_read(*op); |
973 | 9.42k | if (r_size(op) != 6) |
974 | 0 | return_error(gs_error_rangecheck); |
975 | 9.42k | code = float_params(pvalues + 5, 6, (float *)pmat); |
976 | 9.42k | return (code < 0 ? code : 0); |
977 | 9.42k | } |
978 | | |
979 | | /* Write a matrix operand. */ |
980 | | /* Return 0 if OK, error code if not. */ |
981 | | int |
982 | | write_matrix_in(ref * op, const gs_matrix * pmat, gs_dual_memory_t *idmemory, |
983 | | gs_ref_memory_t *imem) |
984 | 10.5k | { |
985 | 10.5k | ref *aptr; |
986 | 10.5k | const float *pel; |
987 | 10.5k | int i; |
988 | | |
989 | 10.5k | check_write_type(*op, t_array); |
990 | 10.5k | if (r_size(op) != 6) |
991 | 0 | return_error(gs_error_rangecheck); |
992 | 10.5k | aptr = op->value.refs; |
993 | 10.5k | pel = (const float *)pmat; |
994 | 73.6k | for (i = 5; i >= 0; i--, aptr++, pel++) { |
995 | 63.1k | if (idmemory) { |
996 | 63.1k | ref_save(op, aptr, "write_matrix"); |
997 | 63.1k | make_real_new(aptr, *pel); |
998 | 63.1k | } else { |
999 | 0 | make_tav(aptr, t_real, imemory_new_mask(imem), realval, *pel); |
1000 | 0 | } |
1001 | 63.1k | } |
1002 | 10.5k | return 0; |
1003 | 10.5k | } |