/src/ghostpdl/psi/zdict.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2001-2021 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 | | /* Dictionary operators */ |
18 | | #include "ghost.h" |
19 | | #include "oper.h" |
20 | | #include "iddict.h" |
21 | | #include "dstack.h" |
22 | | #include "ilevel.h" /* for [count]dictstack */ |
23 | | #include "iname.h" /* for dict_find_name */ |
24 | | #include "ipacked.h" /* for inline dict lookup */ |
25 | | #include "ivmspace.h" |
26 | | #include "store.h" |
27 | | #include "iscan.h" /* for SCAN_PDF_RULES */ |
28 | | |
29 | | /* <int> dict <dict> */ |
30 | | int |
31 | | zdict(i_ctx_t *i_ctx_p) |
32 | 39.3M | { |
33 | 39.3M | os_ptr op = osp; |
34 | | |
35 | 39.3M | check_type(*op, t_integer); |
36 | 39.3M | if (op->value.intval < 0) |
37 | 13 | return_error(gs_error_rangecheck); |
38 | 39.3M | return dict_create((uint) op->value.intval, op); |
39 | 39.3M | } |
40 | | |
41 | | /* <dict> maxlength <int> */ |
42 | | static int |
43 | | zmaxlength(i_ctx_t *i_ctx_p) |
44 | 52.8M | { |
45 | 52.8M | os_ptr op = osp; |
46 | | |
47 | 52.8M | check_type(*op, t_dictionary); |
48 | 52.8M | check_dict_read(*op); |
49 | 52.8M | make_int(op, dict_maxlength(op)); |
50 | 52.8M | return 0; |
51 | 52.8M | } |
52 | | |
53 | | /* <dict> begin - */ |
54 | | int |
55 | | zbegin(i_ctx_t *i_ctx_p) |
56 | 170M | { |
57 | 170M | os_ptr op = osp; |
58 | | |
59 | 170M | check_type(*op, t_dictionary); |
60 | 170M | check_dict_read(*op); |
61 | 170M | if ( dsp == dstop ) { |
62 | 101 | int code = ref_stack_extend(&d_stack, 1); |
63 | | |
64 | 101 | if ( code < 0 ) { |
65 | 0 | if (code == gs_error_dictstackoverflow) { |
66 | | /* Adobe doesn't restore the operand that caused stack */ |
67 | | /* overflow. We do the same to match CET 20-02-02 */ |
68 | 0 | pop(1); |
69 | 0 | } |
70 | 0 | return code; |
71 | 0 | } |
72 | 101 | } |
73 | 170M | ++dsp; |
74 | 170M | ref_assign(dsp, op); |
75 | 170M | dict_set_top(); |
76 | 170M | pop(1); |
77 | 170M | return 0; |
78 | 170M | } |
79 | | |
80 | | /* - end - */ |
81 | | int |
82 | | zend(i_ctx_t *i_ctx_p) |
83 | 170M | { |
84 | 170M | if (ref_stack_count_inline(&d_stack) == min_dstack_size) { |
85 | | /* We would underflow the d-stack. */ |
86 | 462 | return_error(gs_error_dictstackunderflow); |
87 | 462 | } |
88 | 170M | while (dsp == dsbot) { |
89 | | /* We would underflow the current block. */ |
90 | 26 | ref_stack_pop_block(&d_stack); |
91 | 26 | } |
92 | 170M | dsp--; |
93 | 170M | dict_set_top(); |
94 | 170M | return 0; |
95 | 170M | } |
96 | | |
97 | | /* <key> <value> def - */ |
98 | | /* |
99 | | * We make this into a separate procedure because |
100 | | * the interpreter will almost always call it directly. |
101 | | */ |
102 | | int |
103 | | zop_def(i_ctx_t *i_ctx_p) |
104 | 285M | { |
105 | 285M | os_ptr op = osp; |
106 | 285M | os_ptr op1 = op - 1; |
107 | 285M | ref *pvslot; |
108 | | |
109 | | /* The following combines a check_op(2) with a type check. */ |
110 | 285M | switch (r_type(op1)) { |
111 | 280M | case t_name: { |
112 | | /* We can use the fast single-probe lookup here. */ |
113 | 280M | uint nidx = name_index(imemory, op1); |
114 | 280M | uint htemp; |
115 | | |
116 | 280M | if_dict_find_name_by_index_top(nidx, htemp, pvslot) { |
117 | 1.78M | if (dtop_can_store(op)) |
118 | 1.78M | goto ra; |
119 | 1.78M | } |
120 | 278M | break; /* handle all slower cases */ |
121 | 280M | } |
122 | 278M | case t_null: |
123 | 1 | return_error(gs_error_typecheck); |
124 | 22 | case t__invalid: |
125 | 22 | return_error(gs_error_stackunderflow); |
126 | 285M | } |
127 | | /* |
128 | | * Combine the check for a writable top dictionary with |
129 | | * the global/local store check. See dstack.h for details. |
130 | | */ |
131 | 284M | if (!dtop_can_store(op)) { |
132 | 0 | check_dict_write(*dsp); |
133 | | /* |
134 | | * If the dictionary is writable, the problem must be |
135 | | * an invalid store. |
136 | | */ |
137 | 0 | return_error(gs_error_invalidaccess); |
138 | 0 | } |
139 | | /* |
140 | | * Save a level of procedure call in the common (redefinition) |
141 | | * case. With the current interfaces, we pay a double lookup |
142 | | * in the uncommon case. |
143 | | */ |
144 | 284M | if (dict_find(dsp, op1, &pvslot) <= 0) |
145 | 274M | return idict_put(dsp, op1, op); |
146 | 11.1M | ra: |
147 | 11.1M | if ((pvslot->tas.type_attrs & (&i_ctx_p->memory)->test_mask) == 0) |
148 | 24.8k | alloc_save_change(idmemory, &dsp->value.pdict->values, (ref_packed *)pvslot, "dict_put(value)"); |
149 | 11.1M | ref_assign_new_inline(pvslot,op); |
150 | | |
151 | 11.1M | return 0; |
152 | 284M | } |
153 | | int |
154 | | zdef(i_ctx_t *i_ctx_p) |
155 | 0 | { |
156 | 0 | int code = zop_def(i_ctx_p); |
157 | |
|
158 | 0 | if (code >= 0) { |
159 | 0 | pop(2); |
160 | 0 | } |
161 | 0 | return code; |
162 | 0 | } |
163 | | |
164 | | /* <key> load <value> */ |
165 | | static int |
166 | | zload(i_ctx_t *i_ctx_p) |
167 | 170M | { |
168 | 170M | os_ptr op = osp; |
169 | 170M | ref *pvalue; |
170 | | |
171 | 170M | switch (r_type(op)) { |
172 | 170M | case t_name: |
173 | | /* Use the fast lookup. */ |
174 | 170M | if ((pvalue = dict_find_name(op)) == 0) |
175 | 8 | return_error(gs_error_undefined); |
176 | 170M | ref_assign(op, pvalue); |
177 | 170M | return 0; |
178 | 0 | case t_null: |
179 | 0 | return_error(gs_error_typecheck); |
180 | 11 | case t__invalid: |
181 | 11 | return_error(gs_error_stackunderflow); |
182 | 26 | default: { |
183 | | /* Use an explicit loop. */ |
184 | 26 | uint size = ref_stack_count(&d_stack); |
185 | 26 | uint i; |
186 | | |
187 | 101 | for (i = 0; i < size; i++) { |
188 | 76 | ref *dp = ref_stack_index(&d_stack, i); |
189 | | |
190 | 76 | check_dict_read(*dp); |
191 | 76 | if (dict_find(dp, op, &pvalue) > 0) { |
192 | 1 | ref_assign(op, pvalue); |
193 | 1 | return 0; |
194 | 1 | } |
195 | 76 | } |
196 | 26 | return_error(gs_error_undefined); |
197 | 26 | } |
198 | 170M | } |
199 | 170M | } |
200 | | |
201 | | /* get - implemented in zgeneric.c */ |
202 | | |
203 | | /* put - implemented in zgeneric.c */ |
204 | | |
205 | | /* <dict> <key> .undef - */ |
206 | | /* <dict> <key> undef - */ |
207 | | static int |
208 | | zundef(i_ctx_t *i_ctx_p) |
209 | 17.7M | { |
210 | 17.7M | os_ptr op = osp; |
211 | 17.7M | os_ptr op1 = op - 1; |
212 | 17.7M | int code; |
213 | | |
214 | 17.7M | check_type(*op1, t_dictionary); |
215 | 17.7M | check_dict_write(*op1); |
216 | 17.7M | code = idict_undef(op1, op); |
217 | 17.7M | if (code < 0 && code != gs_error_undefined) /* ignore undefined error */ |
218 | 0 | return code; |
219 | 17.7M | pop(2); |
220 | 17.7M | return 0; |
221 | 17.7M | } |
222 | | |
223 | | /* <dict> <key> known <bool> */ |
224 | | static int |
225 | | zknown(i_ctx_t *i_ctx_p) |
226 | 198M | { |
227 | 198M | os_ptr op = osp; |
228 | 198M | register os_ptr op1 = op - 1; |
229 | 198M | ref *pvalue; |
230 | 198M | int code; |
231 | | |
232 | 198M | check_type(*op1, t_dictionary); |
233 | 198M | check_dict_read(*op1); |
234 | 198M | code = dict_find(op1, op, &pvalue); |
235 | 198M | switch (code) { |
236 | 9.79M | case gs_error_dictfull: |
237 | 9.79M | code = 0; |
238 | 198M | case 0: case 1: |
239 | 198M | break; |
240 | 0 | default: |
241 | 0 | return code; |
242 | 198M | } |
243 | 198M | make_bool(op1, code); |
244 | 198M | pop(1); |
245 | 198M | return 0; |
246 | 198M | } |
247 | | |
248 | | /* <key> where <dict> true */ |
249 | | /* <key> where false */ |
250 | | int |
251 | | zwhere(i_ctx_t *i_ctx_p) |
252 | 8.74M | { |
253 | 8.74M | os_ptr op = osp; |
254 | 8.74M | ref_stack_enum_t rsenum; |
255 | | |
256 | 8.74M | check_op(1); |
257 | 8.74M | ref_stack_enum_begin(&rsenum, &d_stack); |
258 | 8.74M | do { |
259 | 8.74M | const ref *const bot = rsenum.ptr; |
260 | 8.74M | const ref *pdref = bot + rsenum.size; |
261 | 8.74M | ref *pvalue; |
262 | 8.74M | int code; |
263 | | |
264 | 29.8M | while (pdref-- > bot) { |
265 | 26.1M | check_dict_read(*pdref); |
266 | 26.1M | code = dict_find(pdref, op, &pvalue); |
267 | 26.1M | if (code < 0 && code != gs_error_dictfull) |
268 | 0 | return code; |
269 | 26.1M | if (code > 0) { |
270 | 5.03M | push(1); |
271 | 5.03M | ref_assign(op - 1, pdref); |
272 | 5.03M | make_true(op); |
273 | 5.03M | return 0; |
274 | 5.03M | } |
275 | 26.1M | } |
276 | 8.74M | } while (ref_stack_enum_next(&rsenum)); |
277 | 3.71M | make_false(op); |
278 | 3.71M | return 0; |
279 | 8.74M | } |
280 | | |
281 | | /* copy for dictionaries -- called from zcopy in zgeneric.c. */ |
282 | | /* Only the type of *op has been checked. */ |
283 | | int |
284 | | zcopy_dict(i_ctx_t *i_ctx_p) |
285 | 1.24M | { |
286 | 1.24M | os_ptr op = osp; |
287 | 1.24M | os_ptr op1 = op - 1; |
288 | 1.24M | int code; |
289 | | |
290 | 1.24M | check_type(*op1, t_dictionary); |
291 | 1.24M | check_dict_read(*op1); |
292 | 1.24M | check_dict_write(*op); |
293 | 1.24M | if (!imemory->gs_lib_ctx->dict_auto_expand && |
294 | 1.24M | (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1)) |
295 | 1.24M | ) |
296 | 0 | return_error(gs_error_rangecheck); |
297 | 1.24M | code = idict_copy(op1, op); |
298 | 1.24M | if (code < 0) |
299 | 0 | return code; |
300 | | /* |
301 | | * In Level 1 systems, we must copy the access attributes too. |
302 | | * The only possible effect this can have is to make the |
303 | | * copy read-only if the original dictionary is read-only. |
304 | | */ |
305 | 1.24M | if (!level2_enabled) |
306 | 1.24M | r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1)); |
307 | 1.24M | ref_assign(op1, op); |
308 | 1.24M | pop(1); |
309 | 1.24M | return 0; |
310 | 1.24M | } |
311 | | |
312 | | /* - currentdict <dict> */ |
313 | | static int |
314 | | zcurrentdict(i_ctx_t *i_ctx_p) |
315 | 53.2M | { |
316 | 53.2M | os_ptr op = osp; |
317 | | |
318 | 53.2M | push(1); |
319 | 53.2M | ref_assign(op, dsp); |
320 | 53.2M | return 0; |
321 | 53.2M | } |
322 | | |
323 | | /* - countdictstack <int> */ |
324 | | static int |
325 | | zcountdictstack(i_ctx_t *i_ctx_p) |
326 | 139k | { |
327 | 139k | os_ptr op = osp; |
328 | 139k | uint count = ref_stack_count(&d_stack); |
329 | | |
330 | 139k | push(1); |
331 | 139k | if (!level2_enabled) |
332 | 0 | count--; /* see dstack.h */ |
333 | 139k | make_int(op, count); |
334 | 139k | return 0; |
335 | 139k | } |
336 | | |
337 | | /* <array> dictstack <subarray> */ |
338 | | static int |
339 | | zdictstack(i_ctx_t *i_ctx_p) |
340 | 137k | { |
341 | 137k | os_ptr op = osp; |
342 | 137k | uint count = ref_stack_count(&d_stack); |
343 | | |
344 | 137k | if (!level2_enabled) |
345 | 0 | count--; /* see dstack.h */ |
346 | 137k | if (!r_is_array(op)) |
347 | 137k | return_op_typecheck(op); |
348 | 137k | if (r_size(op) < count) |
349 | 0 | return_error(gs_error_rangecheck); |
350 | 137k | if (!r_has_type_attrs(op, t_array, a_write)) |
351 | 0 | return_error(gs_error_invalidaccess); |
352 | 137k | return ref_stack_store(&d_stack, op, count, 0, 0, true, idmemory, |
353 | 137k | "dictstack"); |
354 | 137k | } |
355 | | |
356 | | /* - cleardictstack - */ |
357 | | static int |
358 | | zcleardictstack(i_ctx_t *i_ctx_p) |
359 | 437 | { |
360 | 452 | while (zend(i_ctx_p) >= 0) |
361 | 437 | DO_NOTHING; |
362 | 437 | return 0; |
363 | 437 | } |
364 | | |
365 | | /* ------ Extensions ------ */ |
366 | | |
367 | | /* -mark- <key0> <value0> <key1> <value1> ... .dicttomark <dict> */ |
368 | | /* This is the Level 2 >> operator. */ |
369 | | static int |
370 | | zdicttomark(i_ctx_t *i_ctx_p) |
371 | 28.7M | { |
372 | 28.7M | uint count2 = ref_stack_counttomark(&o_stack); |
373 | 28.7M | ref rdict; |
374 | 28.7M | int code; |
375 | 28.7M | uint idx; |
376 | | |
377 | 28.7M | if (count2 == 0) |
378 | 23 | return_error(gs_error_unmatchedmark); |
379 | 28.7M | count2--; |
380 | 28.7M | if ((count2 & 1) != 0) |
381 | 14 | return_error(gs_error_rangecheck); |
382 | 28.7M | code = dict_create(count2 >> 1, &rdict); |
383 | 28.7M | if (code < 0) |
384 | 0 | return code; |
385 | 28.7M | if ((i_ctx_p->scanner_options & SCAN_PDF_RULES) != 0) { |
386 | 0 | for (idx = count2; idx > 0; idx -= 2) { |
387 | 0 | code = idict_put(&rdict, |
388 | 0 | ref_stack_index(&o_stack, idx - 1), |
389 | 0 | ref_stack_index(&o_stack, idx - 2)); |
390 | 0 | if (code < 0) { /* There's no way to free the dictionary -- too bad. */ |
391 | 0 | return code; |
392 | 0 | } |
393 | 0 | } |
394 | 0 | } |
395 | 28.7M | else { |
396 | | /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */ |
397 | | /* we must enter the keys in top-to-bottom order. */ |
398 | 893M | for (idx = 0; idx < count2; idx += 2) { |
399 | 864M | code = idict_put(&rdict, |
400 | 864M | ref_stack_index(&o_stack, idx + 1), |
401 | 864M | ref_stack_index(&o_stack, idx)); |
402 | 864M | if (code < 0) { /* There's no way to free the dictionary -- too bad. */ |
403 | 0 | return code; |
404 | 0 | } |
405 | 864M | } |
406 | 28.7M | } |
407 | 28.7M | ref_stack_pop(&o_stack, count2); |
408 | 28.7M | ref_assign(osp, &rdict); |
409 | 28.7M | return code; |
410 | 28.7M | } |
411 | | |
412 | | /* <dict1> <dict2> .forcecopynew <dict2> */ |
413 | | /* |
414 | | * This operator is a special-purpose accelerator for use by 'restore' (see |
415 | | * gs_dps1.ps). Note that this operator does *not* require that dict2 be |
416 | | * writable. Hence it is in the same category of "dangerous" operators as |
417 | | * .forceput and .forceundef. |
418 | | */ |
419 | | static int |
420 | | zforcecopynew(i_ctx_t *i_ctx_p) |
421 | 72.0k | { |
422 | 72.0k | os_ptr op = osp; |
423 | 72.0k | os_ptr op1 = op - 1; |
424 | 72.0k | int code; |
425 | | |
426 | 72.0k | check_type(*op1, t_dictionary); |
427 | 72.0k | check_dict_read(*op1); |
428 | 72.0k | check_type(*op, t_dictionary); |
429 | | /*check_dict_write(*op);*/ /* see above */ |
430 | | /* This is only recognized in Level 2 mode. */ |
431 | 72.0k | if (!imemory->gs_lib_ctx->dict_auto_expand) |
432 | 0 | return_error(gs_error_undefined); |
433 | 72.0k | code = idict_copy_new(op1, op); |
434 | 72.0k | if (code < 0) |
435 | 0 | return code; |
436 | 72.0k | ref_assign(op1, op); |
437 | 72.0k | pop(1); |
438 | 72.0k | return 0; |
439 | 72.0k | } |
440 | | |
441 | | /* <dict> <key> .forceundef - */ |
442 | | /* |
443 | | * This forces an "undef" even if the dictionary is not writable. |
444 | | * Like .forceput, it is meant to be used only in a few special situations, |
445 | | * and should not be accessible by name after initialization. |
446 | | */ |
447 | | static int |
448 | | zforceundef(i_ctx_t *i_ctx_p) |
449 | 48.3M | { |
450 | 48.3M | os_ptr op = osp; |
451 | | |
452 | 48.3M | check_type(op[-1], t_dictionary); |
453 | | /* Don't check_dict_write */ |
454 | 48.3M | idict_undef(op - 1, op); /* ignore undefined error */ |
455 | 48.3M | pop(2); |
456 | 48.3M | return 0; |
457 | 48.3M | } |
458 | | |
459 | | /* <dict> <key> .knownget <value> true */ |
460 | | /* <dict> <key> .knownget false */ |
461 | | static int |
462 | | zknownget(i_ctx_t *i_ctx_p) |
463 | 395M | { |
464 | 395M | os_ptr op = osp; |
465 | 395M | register os_ptr op1 = op - 1; |
466 | 395M | ref *pvalue; |
467 | | |
468 | 395M | check_type(*op1, t_dictionary); |
469 | 395M | check_dict_read(*op1); |
470 | 395M | if (dict_find(op1, op, &pvalue) <= 0) { |
471 | 91.0M | make_false(op1); |
472 | 91.0M | pop(1); |
473 | 304M | } else { |
474 | 304M | ref_assign(op1, pvalue); |
475 | 304M | make_true(op); |
476 | 304M | } |
477 | 395M | return 0; |
478 | 395M | } |
479 | | |
480 | | /* <dict> <key> .knownundef <bool> */ |
481 | | static int |
482 | | zknownundef(i_ctx_t *i_ctx_p) |
483 | 0 | { |
484 | 0 | os_ptr op = osp; |
485 | 0 | os_ptr op1 = op - 1; |
486 | 0 | int code; |
487 | |
|
488 | 0 | check_type(*op1, t_dictionary); |
489 | 0 | check_dict_write(*op1); |
490 | 0 | code = idict_undef(op1, op); |
491 | 0 | make_bool(op1, code == 0); |
492 | 0 | pop(1); |
493 | 0 | return 0; |
494 | 0 | } |
495 | | |
496 | | /* <dict> <int> .setmaxlength - */ |
497 | | static int |
498 | | zsetmaxlength(i_ctx_t *i_ctx_p) |
499 | 6.42M | { |
500 | 6.42M | os_ptr op = osp; |
501 | 6.42M | os_ptr op1 = op - 1; |
502 | 6.42M | uint new_size; |
503 | 6.42M | int code; |
504 | | |
505 | 6.42M | check_type(*op1, t_dictionary); |
506 | 6.42M | check_dict_write(*op1); |
507 | 6.42M | check_type(*op, t_integer); |
508 | 6.42M | if (op->value.intval < 0) |
509 | 0 | return_error(gs_error_rangecheck); |
510 | 6.42M | new_size = (uint) op->value.intval; |
511 | 6.42M | if (dict_length(op - 1) > new_size) |
512 | 0 | return_error(gs_error_dictfull); |
513 | 6.42M | code = idict_resize(op - 1, new_size); |
514 | 6.42M | if (code >= 0) |
515 | 6.42M | pop(2); |
516 | 6.42M | return code; |
517 | 6.42M | } |
518 | | |
519 | | /* ------ Initialization procedure ------ */ |
520 | | |
521 | | /* We need to split the table because of the 16-element limit. */ |
522 | | const op_def zdict1_op_defs[] = { |
523 | | {"0cleardictstack", zcleardictstack}, |
524 | | {"1begin", zbegin}, |
525 | | {"0countdictstack", zcountdictstack}, |
526 | | {"0currentdict", zcurrentdict}, |
527 | | {"2def", zdef}, |
528 | | {"1dict", zdict}, |
529 | | {"0dictstack", zdictstack}, |
530 | | {"0end", zend}, |
531 | | {"2known", zknown}, |
532 | | {"1load", zload}, |
533 | | {"1maxlength", zmaxlength}, |
534 | | {"2.undef", zundef}, /* we need this even in Level 1 */ |
535 | | {"1where", zwhere}, |
536 | | op_def_end(0) |
537 | | }; |
538 | | const op_def zdict2_op_defs[] = { |
539 | | /* Extensions */ |
540 | | {"1.dicttomark", zdicttomark}, |
541 | | {"2.forcecopynew", zforcecopynew}, |
542 | | {"2.forceundef", zforceundef}, |
543 | | {"2.knownget", zknownget}, |
544 | | {"1.knownundef", zknownundef}, |
545 | | {"2.setmaxlength", zsetmaxlength}, |
546 | | /* |
547 | | * In Level 2, >> is a synonym for .dicttomark, and undef for |
548 | | * .undef. By giving the former their own entries, they will not be |
549 | | * "eq" to .dicttomark and .undef, but that doesn't matter, since |
550 | | * we're doing this only for the sake of Adobe- compatible error |
551 | | * stacks. |
552 | | */ |
553 | | op_def_begin_level2(), |
554 | | {"1>>", zdicttomark}, |
555 | | {"2undef", zundef}, |
556 | | op_def_end(0) |
557 | | }; |