/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 | 443k | { |
33 | 443k | os_ptr op = osp; |
34 | | |
35 | 443k | check_type(*op, t_integer); |
36 | 443k | if (op->value.intval < 0) |
37 | 0 | return_error(gs_error_rangecheck); |
38 | 443k | return dict_create((uint) op->value.intval, op); |
39 | 443k | } |
40 | | |
41 | | /* <dict> maxlength <int> */ |
42 | | static int |
43 | | zmaxlength(i_ctx_t *i_ctx_p) |
44 | 400k | { |
45 | 400k | os_ptr op = osp; |
46 | | |
47 | 400k | check_type(*op, t_dictionary); |
48 | 400k | check_dict_read(*op); |
49 | 400k | make_int(op, dict_maxlength(op)); |
50 | 400k | return 0; |
51 | 400k | } |
52 | | |
53 | | /* <dict> begin - */ |
54 | | int |
55 | | zbegin(i_ctx_t *i_ctx_p) |
56 | 1.29M | { |
57 | 1.29M | os_ptr op = osp; |
58 | | |
59 | 1.29M | check_type(*op, t_dictionary); |
60 | 1.29M | check_dict_read(*op); |
61 | 1.29M | if ( dsp == dstop ) { |
62 | 0 | int code = ref_stack_extend(&d_stack, 1); |
63 | |
|
64 | 0 | 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 | 0 | } |
73 | 1.29M | ++dsp; |
74 | 1.29M | ref_assign(dsp, op); |
75 | 1.29M | dict_set_top(); |
76 | 1.29M | pop(1); |
77 | 1.29M | return 0; |
78 | 1.29M | } |
79 | | |
80 | | /* - end - */ |
81 | | int |
82 | | zend(i_ctx_t *i_ctx_p) |
83 | 1.29M | { |
84 | 1.29M | if (ref_stack_count_inline(&d_stack) == min_dstack_size) { |
85 | | /* We would underflow the d-stack. */ |
86 | 1 | return_error(gs_error_dictstackunderflow); |
87 | 1 | } |
88 | 1.29M | while (dsp == dsbot) { |
89 | | /* We would underflow the current block. */ |
90 | 0 | ref_stack_pop_block(&d_stack); |
91 | 0 | } |
92 | 1.29M | dsp--; |
93 | 1.29M | dict_set_top(); |
94 | 1.29M | return 0; |
95 | 1.29M | } |
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 | 1.47M | { |
105 | 1.47M | os_ptr op = osp; |
106 | 1.47M | os_ptr op1 = op - 1; |
107 | 1.47M | ref *pvslot; |
108 | | |
109 | | /* The following combines a check_op(2) with a type check. */ |
110 | 1.47M | switch (r_type(op1)) { |
111 | 1.44M | case t_name: { |
112 | | /* We can use the fast single-probe lookup here. */ |
113 | 1.44M | uint nidx = name_index(imemory, op1); |
114 | 1.44M | uint htemp; |
115 | | |
116 | 1.44M | if_dict_find_name_by_index_top(nidx, htemp, pvslot) { |
117 | 13.6k | if (dtop_can_store(op)) |
118 | 13.6k | goto ra; |
119 | 13.6k | } |
120 | 1.43M | break; /* handle all slower cases */ |
121 | 1.44M | } |
122 | 1.43M | case t_null: |
123 | 0 | return_error(gs_error_typecheck); |
124 | 0 | case t__invalid: |
125 | 0 | return_error(gs_error_stackunderflow); |
126 | 1.47M | } |
127 | | /* |
128 | | * Combine the check for a writable top dictionary with |
129 | | * the global/local store check. See dstack.h for details. |
130 | | */ |
131 | 1.46M | 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 | 1.46M | if (dict_find(dsp, op1, &pvslot) <= 0) |
145 | 1.41M | return idict_put(dsp, op1, op); |
146 | 58.7k | ra: |
147 | 58.7k | if ((pvslot->tas.type_attrs & (&i_ctx_p->memory)->test_mask) == 0) |
148 | 0 | alloc_save_change(idmemory, &dsp->value.pdict->values, (ref_packed *)pvslot, "dict_put(value)"); |
149 | 58.7k | ref_assign_new_inline(pvslot,op); |
150 | | |
151 | 58.7k | return 0; |
152 | 1.46M | } |
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 | 1.30M | { |
168 | 1.30M | os_ptr op = osp; |
169 | 1.30M | ref *pvalue; |
170 | | |
171 | 1.30M | switch (r_type(op)) { |
172 | 1.30M | case t_name: |
173 | | /* Use the fast lookup. */ |
174 | 1.30M | if ((pvalue = dict_find_name(op)) == 0) |
175 | 0 | return_error(gs_error_undefined); |
176 | 1.30M | ref_assign(op, pvalue); |
177 | 1.30M | return 0; |
178 | 0 | case t_null: |
179 | 0 | return_error(gs_error_typecheck); |
180 | 0 | case t__invalid: |
181 | 0 | return_error(gs_error_stackunderflow); |
182 | 0 | default: { |
183 | | /* Use an explicit loop. */ |
184 | 0 | uint size = ref_stack_count(&d_stack); |
185 | 0 | uint i; |
186 | |
|
187 | 0 | for (i = 0; i < size; i++) { |
188 | 0 | ref *dp = ref_stack_index(&d_stack, i); |
189 | |
|
190 | 0 | check_dict_read(*dp); |
191 | 0 | if (dict_find(dp, op, &pvalue) > 0) { |
192 | 0 | ref_assign(op, pvalue); |
193 | 0 | return 0; |
194 | 0 | } |
195 | 0 | } |
196 | 0 | return_error(gs_error_undefined); |
197 | 0 | } |
198 | 1.30M | } |
199 | 1.30M | } |
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 | 128k | { |
210 | 128k | os_ptr op = osp; |
211 | 128k | os_ptr op1 = op - 1; |
212 | 128k | int code; |
213 | | |
214 | 128k | check_type(*op1, t_dictionary); |
215 | 128k | check_dict_write(*op1); |
216 | 128k | code = idict_undef(op1, op); |
217 | 128k | if (code < 0 && code != gs_error_undefined) /* ignore undefined error */ |
218 | 0 | return code; |
219 | 128k | pop(2); |
220 | 128k | return 0; |
221 | 128k | } |
222 | | |
223 | | /* <dict> <key> known <bool> */ |
224 | | static int |
225 | | zknown(i_ctx_t *i_ctx_p) |
226 | 1.43M | { |
227 | 1.43M | os_ptr op = osp; |
228 | 1.43M | register os_ptr op1 = op - 1; |
229 | 1.43M | ref *pvalue; |
230 | 1.43M | int code; |
231 | | |
232 | 1.43M | check_type(*op1, t_dictionary); |
233 | 1.43M | check_dict_read(*op1); |
234 | 1.43M | code = dict_find(op1, op, &pvalue); |
235 | 1.43M | switch (code) { |
236 | 63.4k | case gs_error_dictfull: |
237 | 63.4k | code = 0; |
238 | 1.43M | case 0: case 1: |
239 | 1.43M | break; |
240 | 0 | default: |
241 | 0 | return code; |
242 | 1.43M | } |
243 | 1.43M | make_bool(op1, code); |
244 | 1.43M | pop(1); |
245 | 1.43M | return 0; |
246 | 1.43M | } |
247 | | |
248 | | /* <key> where <dict> true */ |
249 | | /* <key> where false */ |
250 | | int |
251 | | zwhere(i_ctx_t *i_ctx_p) |
252 | 76.4k | { |
253 | 76.4k | os_ptr op = osp; |
254 | 76.4k | ref_stack_enum_t rsenum; |
255 | | |
256 | 76.4k | check_op(1); |
257 | 76.4k | ref_stack_enum_begin(&rsenum, &d_stack); |
258 | 76.4k | do { |
259 | 76.4k | const ref *const bot = rsenum.ptr; |
260 | 76.4k | const ref *pdref = bot + rsenum.size; |
261 | 76.4k | ref *pvalue; |
262 | 76.4k | int code; |
263 | | |
264 | 292k | while (pdref-- > bot) { |
265 | 254k | check_dict_read(*pdref); |
266 | 254k | code = dict_find(pdref, op, &pvalue); |
267 | 254k | if (code < 0 && code != gs_error_dictfull) |
268 | 0 | return code; |
269 | 254k | if (code > 0) { |
270 | 38.8k | push(1); |
271 | 38.8k | ref_assign(op - 1, pdref); |
272 | 38.8k | make_true(op); |
273 | 38.8k | return 0; |
274 | 38.8k | } |
275 | 254k | } |
276 | 76.4k | } while (ref_stack_enum_next(&rsenum)); |
277 | 37.6k | make_false(op); |
278 | 37.6k | return 0; |
279 | 76.4k | } |
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 | 9.56k | { |
286 | 9.56k | os_ptr op = osp; |
287 | 9.56k | os_ptr op1 = op - 1; |
288 | 9.56k | int code; |
289 | | |
290 | 9.56k | check_type(*op1, t_dictionary); |
291 | 9.56k | check_dict_read(*op1); |
292 | 9.56k | check_dict_write(*op); |
293 | 9.56k | if (!imemory->gs_lib_ctx->dict_auto_expand && |
294 | 9.56k | (dict_length(op) != 0 || dict_maxlength(op) < dict_length(op1)) |
295 | 9.56k | ) |
296 | 0 | return_error(gs_error_rangecheck); |
297 | 9.56k | code = idict_copy(op1, op); |
298 | 9.56k | 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 | 9.56k | if (!level2_enabled) |
306 | 9.56k | r_copy_attrs(dict_access_ref(op), a_write, dict_access_ref(op1)); |
307 | 9.56k | ref_assign(op1, op); |
308 | 9.56k | pop(1); |
309 | 9.56k | return 0; |
310 | 9.56k | } |
311 | | |
312 | | /* - currentdict <dict> */ |
313 | | static int |
314 | | zcurrentdict(i_ctx_t *i_ctx_p) |
315 | 401k | { |
316 | 401k | os_ptr op = osp; |
317 | | |
318 | 401k | push(1); |
319 | 401k | ref_assign(op, dsp); |
320 | 401k | return 0; |
321 | 401k | } |
322 | | |
323 | | /* - countdictstack <int> */ |
324 | | static int |
325 | | zcountdictstack(i_ctx_t *i_ctx_p) |
326 | 706 | { |
327 | 706 | os_ptr op = osp; |
328 | 706 | uint count = ref_stack_count(&d_stack); |
329 | | |
330 | 706 | push(1); |
331 | 706 | if (!level2_enabled) |
332 | 0 | count--; /* see dstack.h */ |
333 | 706 | make_int(op, count); |
334 | 706 | return 0; |
335 | 706 | } |
336 | | |
337 | | /* <array> dictstack <subarray> */ |
338 | | static int |
339 | | zdictstack(i_ctx_t *i_ctx_p) |
340 | 702 | { |
341 | 702 | os_ptr op = osp; |
342 | 702 | uint count = ref_stack_count(&d_stack); |
343 | | |
344 | 702 | if (!level2_enabled) |
345 | 0 | count--; /* see dstack.h */ |
346 | 702 | if (!r_is_array(op)) |
347 | 702 | return_op_typecheck(op); |
348 | 702 | if (r_size(op) < count) |
349 | 0 | return_error(gs_error_rangecheck); |
350 | 702 | if (!r_has_type_attrs(op, t_array, a_write)) |
351 | 0 | return_error(gs_error_invalidaccess); |
352 | 702 | return ref_stack_store(&d_stack, op, count, 0, 0, true, idmemory, |
353 | 702 | "dictstack"); |
354 | 702 | } |
355 | | |
356 | | /* - cleardictstack - */ |
357 | | static int |
358 | | zcleardictstack(i_ctx_t *i_ctx_p) |
359 | 1 | { |
360 | 1 | while (zend(i_ctx_p) >= 0) |
361 | 1 | DO_NOTHING; |
362 | 1 | return 0; |
363 | 1 | } |
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 | 158k | { |
372 | 158k | uint count2 = ref_stack_counttomark(&o_stack); |
373 | 158k | ref rdict; |
374 | 158k | int code; |
375 | 158k | uint idx; |
376 | | |
377 | 158k | if (count2 == 0) |
378 | 0 | return_error(gs_error_unmatchedmark); |
379 | 158k | count2--; |
380 | 158k | if ((count2 & 1) != 0) |
381 | 0 | return_error(gs_error_rangecheck); |
382 | 158k | code = dict_create(count2 >> 1, &rdict); |
383 | 158k | if (code < 0) |
384 | 0 | return code; |
385 | 158k | 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 | 158k | else { |
396 | | /* << /a 1 /a 2 >> => << /a 1 >>, i.e., */ |
397 | | /* we must enter the keys in top-to-bottom order. */ |
398 | 6.40M | for (idx = 0; idx < count2; idx += 2) { |
399 | 6.24M | code = idict_put(&rdict, |
400 | 6.24M | ref_stack_index(&o_stack, idx + 1), |
401 | 6.24M | ref_stack_index(&o_stack, idx)); |
402 | 6.24M | if (code < 0) { /* There's no way to free the dictionary -- too bad. */ |
403 | 0 | return code; |
404 | 0 | } |
405 | 6.24M | } |
406 | 158k | } |
407 | 158k | ref_stack_pop(&o_stack, count2); |
408 | 158k | ref_assign(osp, &rdict); |
409 | 158k | return code; |
410 | 158k | } |
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 | 671 | { |
422 | 671 | os_ptr op = osp; |
423 | 671 | os_ptr op1 = op - 1; |
424 | 671 | int code; |
425 | | |
426 | 671 | check_type(*op1, t_dictionary); |
427 | 671 | check_dict_read(*op1); |
428 | 671 | check_type(*op, t_dictionary); |
429 | | /*check_dict_write(*op);*/ /* see above */ |
430 | | /* This is only recognized in Level 2 mode. */ |
431 | 671 | if (!imemory->gs_lib_ctx->dict_auto_expand) |
432 | 0 | return_error(gs_error_undefined); |
433 | 671 | code = idict_copy_new(op1, op); |
434 | 671 | if (code < 0) |
435 | 0 | return code; |
436 | 671 | ref_assign(op1, op); |
437 | 671 | pop(1); |
438 | 671 | return 0; |
439 | 671 | } |
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 | 369k | { |
450 | 369k | os_ptr op = osp; |
451 | | |
452 | 369k | check_type(op[-1], t_dictionary); |
453 | | /* Don't check_dict_write */ |
454 | 369k | idict_undef(op - 1, op); /* ignore undefined error */ |
455 | 369k | pop(2); |
456 | 369k | return 0; |
457 | 369k | } |
458 | | |
459 | | /* <dict> <key> .knownget <value> true */ |
460 | | /* <dict> <key> .knownget false */ |
461 | | static int |
462 | | zknownget(i_ctx_t *i_ctx_p) |
463 | 3.00M | { |
464 | 3.00M | os_ptr op = osp; |
465 | 3.00M | register os_ptr op1 = op - 1; |
466 | 3.00M | ref *pvalue; |
467 | | |
468 | 3.00M | check_type(*op1, t_dictionary); |
469 | 3.00M | check_dict_read(*op1); |
470 | 3.00M | if (dict_find(op1, op, &pvalue) <= 0) { |
471 | 829k | make_false(op1); |
472 | 829k | pop(1); |
473 | 2.17M | } else { |
474 | 2.17M | ref_assign(op1, pvalue); |
475 | 2.17M | make_true(op); |
476 | 2.17M | } |
477 | 3.00M | return 0; |
478 | 3.00M | } |
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 | 49.1k | { |
500 | 49.1k | os_ptr op = osp; |
501 | 49.1k | os_ptr op1 = op - 1; |
502 | 49.1k | uint new_size; |
503 | 49.1k | int code; |
504 | | |
505 | 49.1k | check_type(*op1, t_dictionary); |
506 | 49.1k | check_dict_write(*op1); |
507 | 49.1k | check_type(*op, t_integer); |
508 | 49.1k | if (op->value.intval < 0) |
509 | 0 | return_error(gs_error_rangecheck); |
510 | 49.1k | new_size = (uint) op->value.intval; |
511 | 49.1k | if (dict_length(op - 1) > new_size) |
512 | 0 | return_error(gs_error_dictfull); |
513 | 49.1k | code = idict_resize(op - 1, new_size); |
514 | 49.1k | if (code >= 0) |
515 | 49.1k | pop(2); |
516 | 49.1k | return code; |
517 | 49.1k | } |
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 | | }; |