/src/ghostpdl/pdf/pdf_dict.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2018-2025 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 | | /* dictionary handling for the PDF interpreter */ |
17 | | #include "ghostpdf.h" |
18 | | #include "pdf_types.h" |
19 | | #include "pdf_deref.h" |
20 | | #include "pdf_dict.h" |
21 | | #include "pdf_stack.h" |
22 | | #include "pdf_array.h" |
23 | | #include "pdf_int.h" |
24 | | #include "pdf_loop_detect.h" |
25 | | #include "pdf_misc.h" |
26 | | |
27 | | static int pdfi_dict_find(pdf_context *ctx, pdf_dict *d, const char *Key, bool sort); |
28 | | static int pdfi_dict_find_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, bool sort); |
29 | | |
30 | | void pdfi_free_dict(pdf_obj *o) |
31 | 13.4M | { |
32 | 13.4M | pdf_dict *d = (pdf_dict *)o; |
33 | 13.4M | int i; |
34 | | #if DEBUG_DICT |
35 | | pdf_name *name; |
36 | | #endif |
37 | | |
38 | 125M | for (i=0;i < d->entries;i++) { |
39 | | #if DEBUG_DICT |
40 | | name = (pdf_name *)d->list[i].key; |
41 | | #endif |
42 | 111M | if (d->list[i].value != NULL) |
43 | 111M | pdfi_countdown(d->list[i].value); |
44 | 111M | if (d->list[i].key != NULL) |
45 | 111M | pdfi_countdown(d->list[i].key); |
46 | 111M | } |
47 | 13.4M | gs_free_object(OBJ_MEMORY(d), d->list, "pdf interpreter free dictionary key/values"); |
48 | 13.4M | gs_free_object(OBJ_MEMORY(d), d, "pdf interpreter free dictionary"); |
49 | 13.4M | } |
50 | | |
51 | | /* Delete a key pair, either by specifying a char * or a pdf_name * |
52 | | */ |
53 | | static int pdfi_dict_delete_inner(pdf_context *ctx, pdf_dict *d, pdf_name *n, const char *str) |
54 | 200k | { |
55 | 200k | int i = 0; |
56 | | #if DEBUG_DICT |
57 | | pdf_name *name; |
58 | | #endif |
59 | | |
60 | 200k | if (n != NULL) |
61 | 1.46k | i = pdfi_dict_find_key(ctx, d, (const pdf_name *)n, false); |
62 | 199k | else |
63 | 199k | i = pdfi_dict_find(ctx, d, str, false); |
64 | | |
65 | 200k | if (i < 0) |
66 | 7 | return i; |
67 | | |
68 | 200k | pdfi_countdown(d->list[i].key); |
69 | 200k | pdfi_countdown(d->list[i].value); |
70 | 200k | d->entries--; |
71 | 200k | if (i != d->entries) |
72 | 2.38k | memmove(&d->list[i], &d->list[i+1], (d->entries - i) * sizeof(d->list[0])); |
73 | 200k | d->list[d->entries].key = NULL; |
74 | 200k | d->list[d->entries].value = NULL; |
75 | 200k | d->is_sorted = false; |
76 | 200k | return 0; |
77 | 200k | } |
78 | | |
79 | | int pdfi_dict_delete_pair(pdf_context *ctx, pdf_dict *d, pdf_name *n) |
80 | 1.46k | { |
81 | 1.46k | return pdfi_dict_delete_inner(ctx, d, n, NULL); |
82 | 1.46k | } |
83 | | |
84 | | int pdfi_dict_delete(pdf_context *ctx, pdf_dict *d, const char *str) |
85 | 199k | { |
86 | 199k | return pdfi_dict_delete_inner(ctx, d, NULL, str); |
87 | 199k | } |
88 | | |
89 | | /* This function is provided for symmetry with arrays, and in case we ever |
90 | | * want to change the behaviour of pdfi_dict_from_stack() and pdfi_dict_alloc() |
91 | | * similarly to the array behaviour, where we always have null PDF objects |
92 | | * rather than NULL pointers stored in the dictionary. |
93 | | */ |
94 | | int pdfi_dict_alloc(pdf_context *ctx, uint64_t size, pdf_dict **d) |
95 | 13.4M | { |
96 | 13.4M | *d = NULL; |
97 | 13.4M | return pdfi_object_alloc(ctx, PDF_DICT, size, (pdf_obj **)d); |
98 | 13.4M | } |
99 | | |
100 | | static int pdfi_dict_name_from_string(pdf_context *ctx, pdf_string *s, pdf_name **n) |
101 | 0 | { |
102 | 0 | int code = pdfi_object_alloc(ctx, PDF_NAME, s->length, (pdf_obj **)n); |
103 | 0 | if (code >= 0) { |
104 | 0 | memcpy((*n)->data, s->data, s->length); |
105 | 0 | pdfi_countup(*n); |
106 | 0 | } |
107 | 0 | return code; |
108 | 0 | } |
109 | | |
110 | | int pdfi_dict_from_stack(pdf_context *ctx, uint32_t indirect_num, uint32_t indirect_gen, bool convert_string_keys) |
111 | 12.3M | { |
112 | 12.3M | uint64_t index = 0; |
113 | 12.3M | pdf_dict *d = NULL; |
114 | 12.3M | uint64_t i = 0; |
115 | 12.3M | int code; |
116 | | #if DEBUG_DICT |
117 | | pdf_name *key; |
118 | | #endif |
119 | | |
120 | 12.3M | code = pdfi_count_to_mark(ctx, &index); |
121 | 12.3M | if (code < 0) { |
122 | 143k | pdfi_clear_to_mark(ctx); |
123 | 143k | return code; |
124 | 143k | } |
125 | | |
126 | 12.2M | if (index & 1) { |
127 | 233k | pdfi_clear_to_mark(ctx); |
128 | 233k | return_error(gs_error_rangecheck); |
129 | 233k | } |
130 | | |
131 | 11.9M | code = pdfi_dict_alloc(ctx, index >> 1, &d); |
132 | 11.9M | if (code < 0) { |
133 | 0 | pdfi_clear_to_mark(ctx); |
134 | 0 | return code; |
135 | 0 | } |
136 | | |
137 | 11.9M | d->entries = d->size; |
138 | | |
139 | 72.5M | while (index) { |
140 | 60.6M | i = (index / 2) - 1; |
141 | | |
142 | | /* In PDF keys are *required* to be names, so we ought to check that here */ |
143 | 60.6M | if (pdfi_type_of((pdf_obj *)ctx->stack_top[-2]) == PDF_NAME) { |
144 | 60.5M | d->list[i].key = ctx->stack_top[-2]; |
145 | 60.5M | pdfi_countup(d->list[i].key); |
146 | | #if DEBUG_DICT |
147 | | key = (pdf_name *)d->list[i].key; |
148 | | #endif |
149 | 60.5M | d->list[i].value = ctx->stack_top[-1]; |
150 | 60.5M | pdfi_countup(d->list[i].value); |
151 | 60.5M | } else { |
152 | 44.9k | if (convert_string_keys && (pdfi_type_of((pdf_obj *)ctx->stack_top[-2]) == PDF_STRING)) { |
153 | 0 | pdf_name *n; |
154 | 0 | code = pdfi_dict_name_from_string(ctx, (pdf_string *)ctx->stack_top[-2], &n); |
155 | 0 | if (code < 0) { |
156 | 0 | pdfi_free_dict((pdf_obj *)d); |
157 | 0 | pdfi_clear_to_mark(ctx); |
158 | 0 | return_error(gs_error_typecheck); |
159 | 0 | } |
160 | 0 | d->list[i].key = (pdf_obj *)n; /* pdfi_dict_name_from_string() sets refcnt to 1 */ |
161 | 0 | d->list[i].value = ctx->stack_top[-1]; |
162 | 0 | pdfi_countup(d->list[i].value); |
163 | 0 | } |
164 | 44.9k | else { |
165 | 44.9k | pdfi_free_dict((pdf_obj *)d); |
166 | 44.9k | pdfi_clear_to_mark(ctx); |
167 | 44.9k | return_error(gs_error_typecheck); |
168 | 44.9k | } |
169 | 44.9k | } |
170 | | |
171 | 60.5M | pdfi_pop(ctx, 2); |
172 | 60.5M | index -= 2; |
173 | 60.5M | } |
174 | | |
175 | 11.9M | code = pdfi_clear_to_mark(ctx); |
176 | 11.9M | if (code < 0) { |
177 | 0 | pdfi_free_dict((pdf_obj *)d); |
178 | 0 | return code; |
179 | 0 | } |
180 | | |
181 | 11.9M | if (ctx->args.pdfdebug) |
182 | 0 | outprintf (ctx->memory, "\n >>\n"); |
183 | | |
184 | 11.9M | d->indirect_num = indirect_num; |
185 | 11.9M | d->indirect_gen = indirect_gen; |
186 | | |
187 | 11.9M | code = pdfi_push(ctx, (pdf_obj *)d); |
188 | 11.9M | if (code < 0) |
189 | 0 | pdfi_free_dict((pdf_obj *)d); |
190 | | |
191 | 11.9M | return code; |
192 | 11.9M | } |
193 | | |
194 | | /* Convenience routine for common case where there are two possible keys */ |
195 | | int |
196 | | pdfi_dict_get2(pdf_context *ctx, pdf_dict *d, const char *Key1, |
197 | | const char *Key2, pdf_obj **o) |
198 | 1.52M | { |
199 | 1.52M | int code; |
200 | | |
201 | | /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. Assume abbreviated names are shorter :-) */ |
202 | 1.52M | if (strlen(Key1) < strlen(Key2)) { |
203 | 0 | code = pdfi_dict_get(ctx, d, Key1, o); |
204 | 0 | if (code == gs_error_undefined) |
205 | 0 | code = pdfi_dict_get(ctx, d, Key2, o); |
206 | 1.52M | } else { |
207 | 1.52M | code = pdfi_dict_get(ctx, d, Key2, o); |
208 | 1.52M | if (code == gs_error_undefined) |
209 | 1.29M | code = pdfi_dict_get(ctx, d, Key1, o); |
210 | 1.52M | } |
211 | 1.52M | return code; |
212 | 1.52M | } |
213 | | |
214 | | static int pdfi_dict_compare_entry(const void *a, const void *b) |
215 | 1.17G | { |
216 | 1.17G | pdf_name *key_a = (pdf_name *)((pdf_dict_entry *)a)->key, *key_b = (pdf_name *)((pdf_dict_entry *)b)->key; |
217 | | |
218 | 1.17G | if (key_a == NULL) { |
219 | 799k | if (key_b == NULL) |
220 | 799k | return 0; |
221 | 0 | else |
222 | 0 | return 1; |
223 | 799k | } |
224 | | |
225 | 1.17G | if (key_b == NULL) |
226 | 146k | return -1; |
227 | | |
228 | 1.17G | if (key_a->length != key_b->length) |
229 | 374M | return key_a->length - key_b->length; |
230 | | |
231 | 800M | return strncmp((const char *)key_a->data, (const char *)key_b->data, key_a->length); |
232 | 1.17G | } |
233 | | |
234 | | static int pdfi_dict_find_sorted(pdf_context *ctx, pdf_dict *d, const char *Key) |
235 | 96.1M | { |
236 | 96.1M | int start = 0, end = d->size - 1, middle = 0, keylen = strlen(Key); |
237 | 96.1M | pdf_name *test_key; |
238 | | |
239 | 816M | while (start <= end) { |
240 | 811M | middle = start + (end - start) / 2; |
241 | 811M | test_key = (pdf_name *)d->list[middle].key; |
242 | | |
243 | | /* Sorting pushes unused key/values (NULL) to the end of the dictionary */ |
244 | 811M | if (test_key == NULL) { |
245 | 1.21M | end = middle - 1; |
246 | 1.21M | continue; |
247 | 1.21M | } |
248 | | |
249 | 810M | if (test_key->length == keylen) { |
250 | 509M | int result = strncmp((const char *)test_key->data, Key, keylen); |
251 | | |
252 | 509M | if (result == 0) |
253 | 90.5M | return middle; |
254 | 418M | if (result < 0) |
255 | 218M | start = middle + 1; |
256 | 200M | else |
257 | 200M | end = middle - 1; |
258 | 418M | } else { |
259 | 300M | if (test_key->length < keylen) |
260 | 107M | start = middle + 1; |
261 | 193M | else |
262 | 193M | end = middle -1; |
263 | 300M | } |
264 | 810M | } |
265 | 5.58M | return gs_note_error(gs_error_undefined); |
266 | 96.1M | } |
267 | | |
268 | | static int pdfi_dict_find_unsorted(pdf_context *ctx, pdf_dict *d, const char *Key) |
269 | 177M | { |
270 | 177M | int i; |
271 | 177M | pdf_name *t; |
272 | | |
273 | 20.2G | for (i=0;i< d->entries;i++) { |
274 | 20.1G | t = (pdf_name *)d->list[i].key; |
275 | | |
276 | 20.1G | if (t && pdfi_type_of(t) == PDF_NAME) { |
277 | 20.1G | if (pdfi_name_is((pdf_name *)t, Key)) { |
278 | 69.2M | return i; |
279 | 69.2M | } |
280 | 20.1G | } |
281 | 20.1G | } |
282 | 177M | return_error(gs_error_undefined); |
283 | 177M | } |
284 | | |
285 | | static int pdfi_dict_find(pdf_context *ctx, pdf_dict *d, const char *Key, bool sort) |
286 | 273M | { |
287 | 273M | if (!d->is_sorted) { |
288 | 177M | if (d->entries > 32 && sort) { |
289 | 336k | qsort(d->list, d->size, sizeof(pdf_dict_entry), pdfi_dict_compare_entry); |
290 | 336k | d->is_sorted = true; |
291 | 336k | return pdfi_dict_find_sorted(ctx, d, Key); |
292 | 336k | } else |
293 | 177M | return pdfi_dict_find_unsorted(ctx, d, Key); |
294 | 177M | } else |
295 | 95.8M | return pdfi_dict_find_sorted(ctx, d, Key); |
296 | 273M | } |
297 | | |
298 | | static int pdfi_dict_find_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, bool sort) |
299 | 149M | { |
300 | 149M | char *Test = NULL; |
301 | 149M | int index = 0; |
302 | | |
303 | 149M | Test = (char *)gs_alloc_bytes(ctx->memory, Key->length + 1, "pdfi_dict_find_key"); |
304 | 149M | if (Test == NULL) |
305 | 0 | return_error(gs_error_VMerror); |
306 | | |
307 | 149M | memcpy(Test, Key->data, Key->length); |
308 | 149M | Test[Key->length] = 0x00; |
309 | | |
310 | 149M | index = pdfi_dict_find(ctx, d, Test, sort); |
311 | | |
312 | 149M | gs_free_object(ctx->memory, Test, "pdfi_dict_find_key"); |
313 | 149M | return index; |
314 | 149M | } |
315 | | |
316 | | /* The object returned by pdfi_dict_get has its reference count incremented by 1 to |
317 | | * indicate the reference now held by the caller, in **o. |
318 | | */ |
319 | | int pdfi_dict_get_common(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o, bool cache) |
320 | 53.8M | { |
321 | 53.8M | int index = 0, code = 0; |
322 | | |
323 | 53.8M | *o = NULL; |
324 | | |
325 | 53.8M | if (pdfi_type_of(d) != PDF_DICT) |
326 | 50.0k | return_error(gs_error_typecheck); |
327 | | |
328 | 53.8M | index = pdfi_dict_find(ctx, d, Key, true); |
329 | 53.8M | if (index < 0) |
330 | 12.8M | return index; |
331 | | |
332 | 41.0M | if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) { |
333 | 1.59M | pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value; |
334 | | |
335 | 1.59M | if (r->ref_object_num == d->object_num) |
336 | 961 | return_error(gs_error_circular_reference); |
337 | | |
338 | 1.59M | if (cache) |
339 | 1.59M | code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o); |
340 | 0 | else |
341 | 0 | code = pdfi_deref_loop_detect_nocache(ctx, r->ref_object_num, r->ref_generation_num, o); |
342 | 1.59M | if (code < 0) |
343 | 567k | return code; |
344 | | /* The file Bug690138.pdf has font dictionaries which contain ToUnicode keys where |
345 | | * the value is an indirect reference to the same font object. If we replace the |
346 | | * indirect reference in the dictionary with the font dictionary it becomes self |
347 | | * referencing and never counts down to 0, leading to a memory leak. |
348 | | * This is clearly an error, so flag it and don't replace the indirect reference. |
349 | | */ |
350 | 1.02M | if ((*o) < (pdf_obj *)(uintptr_t)(TOKEN__LAST_KEY)) { |
351 | | /* "FAST" object, therefore can't be a problem. */ |
352 | 641 | pdfi_countdown(d->list[index].value); |
353 | 641 | d->list[index].value = *o; |
354 | 1.02M | } else if ((*o)->object_num == 0 || (*o)->object_num != d->object_num) { |
355 | 1.02M | pdfi_countdown(d->list[index].value); |
356 | 1.02M | d->list[index].value = *o; |
357 | 1.02M | } else { |
358 | 0 | code = pdfi_set_error_stop(ctx, gs_note_error(gs_error_undefinedresult), NULL, E_DICT_SELF_REFERENCE, "pdfi_dict_get", NULL); |
359 | 0 | return code; |
360 | 0 | } |
361 | 1.02M | } |
362 | 40.4M | *o = d->list[index].value; |
363 | 40.4M | pdfi_countup(*o); |
364 | | |
365 | 40.4M | return code; |
366 | 41.0M | } |
367 | | |
368 | | /* Get object from dict without resolving indirect references |
369 | | * Will inc refcnt by 1 |
370 | | */ |
371 | | int pdfi_dict_get_no_deref(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o) |
372 | 22.5k | { |
373 | 22.5k | int index=0; |
374 | | |
375 | 22.5k | *o = NULL; |
376 | | |
377 | 22.5k | if (pdfi_type_of(d) != PDF_DICT) |
378 | 0 | return_error(gs_error_typecheck); |
379 | | |
380 | 22.5k | index = pdfi_dict_find_key(ctx, d, Key, true); |
381 | 22.5k | if (index < 0) |
382 | 0 | return index; |
383 | | |
384 | 22.5k | *o = d->list[index].value; |
385 | 22.5k | pdfi_countup(*o); |
386 | 22.5k | return 0; |
387 | 22.5k | } |
388 | | |
389 | | /* Get by pdf_name rather than by char * |
390 | | * The object returned by pdfi_dict_get has its reference count incremented by 1 to |
391 | | * indicate the reference now held by the caller, in **o. |
392 | | */ |
393 | | int pdfi_dict_get_by_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o) |
394 | 97.3M | { |
395 | 97.3M | int index=0, code = 0; |
396 | | |
397 | 97.3M | *o = NULL; |
398 | | |
399 | 97.3M | if (pdfi_type_of(d) != PDF_DICT) |
400 | 204 | return_error(gs_error_typecheck); |
401 | | |
402 | 97.3M | index = pdfi_dict_find_key(ctx, d, Key, true); |
403 | 97.3M | if (index < 0) |
404 | 7.27M | return index; |
405 | | |
406 | 90.1M | if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) { |
407 | 66.0k | pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value; |
408 | | |
409 | 66.0k | code = pdfi_deref_loop_detect(ctx, r->ref_object_num, r->ref_generation_num, o); |
410 | 66.0k | if (code < 0) |
411 | 26.3k | return code; |
412 | 39.6k | pdfi_countdown(d->list[index].value); |
413 | 39.6k | d->list[index].value = *o; |
414 | 39.6k | } |
415 | 90.0M | *o = d->list[index].value; |
416 | 90.0M | pdfi_countup(*o); |
417 | 90.0M | return 0; |
418 | 90.1M | } |
419 | | |
420 | | /* Get indirect reference without de-referencing it */ |
421 | | int pdfi_dict_get_ref(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_indirect_ref **o) |
422 | 0 | { |
423 | 0 | int index=0; |
424 | |
|
425 | 0 | *o = NULL; |
426 | |
|
427 | 0 | if (pdfi_type_of(d) != PDF_DICT) |
428 | 0 | return_error(gs_error_typecheck); |
429 | | |
430 | 0 | index = pdfi_dict_find(ctx, d, Key, true); |
431 | 0 | if (index < 0) |
432 | 0 | return index; |
433 | | |
434 | 0 | if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) { |
435 | 0 | *o = (pdf_indirect_ref *)d->list[index].value; |
436 | 0 | pdfi_countup(*o); |
437 | 0 | return 0; |
438 | 0 | } else { |
439 | 0 | return_error(gs_error_typecheck); |
440 | 0 | } |
441 | 0 | } |
442 | | |
443 | | /* As per pdfi_dict_get(), but doesn't replace an indirect reference in a dictionary with a |
444 | | * new object. This is for Resources following, such as Do, where we will have to seek and |
445 | | * read the indirect object anyway, and we need to ensure that Form XObjects (for example) |
446 | | * don't have circular calls. |
447 | | * |
448 | | * Takes either strKey or nameKey param. Other will be NULL. |
449 | | */ |
450 | | static int pdfi_dict_get_no_store_R_inner(pdf_context *ctx, pdf_dict *d, const char *strKey, |
451 | | const pdf_name *nameKey, pdf_obj **o) |
452 | 4.71M | { |
453 | 4.71M | int index=0, code = 0; |
454 | | |
455 | 4.71M | *o = NULL; |
456 | | |
457 | 4.71M | if (pdfi_type_of(d) != PDF_DICT) |
458 | 0 | return_error(gs_error_typecheck); |
459 | | |
460 | 4.71M | if (strKey == NULL) |
461 | 3.98M | index = pdfi_dict_find_key(ctx, d, nameKey, true); |
462 | 732k | else |
463 | 732k | index = pdfi_dict_find(ctx, d, strKey, true); |
464 | | |
465 | 4.71M | if (index < 0) |
466 | 328k | return index; |
467 | | |
468 | 4.39M | if (pdfi_type_of(d->list[index].value) == PDF_INDIRECT) { |
469 | 4.13M | pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[index].value; |
470 | | |
471 | 4.13M | code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, o); |
472 | 4.13M | if (code < 0) |
473 | 1.51M | return code; |
474 | 4.13M | } else { |
475 | 258k | *o = d->list[index].value; |
476 | 258k | pdfi_countup(*o); |
477 | 258k | } |
478 | 2.87M | return 0; |
479 | 4.39M | } |
480 | | |
481 | | /* Wrapper to pdfi_dict_no_store_R_inner(), takes a char * as Key */ |
482 | | int pdfi_dict_get_no_store_R(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o) |
483 | 732k | { |
484 | 732k | return pdfi_dict_get_no_store_R_inner(ctx, d, Key, NULL, o); |
485 | 732k | } |
486 | | |
487 | | /* Wrapper to pdfi_dict_no_store_R_inner(), takes a pdf_name * as Key */ |
488 | | int pdfi_dict_get_no_store_R_key(pdf_context *ctx, pdf_dict *d, const pdf_name *Key, pdf_obj **o) |
489 | 3.98M | { |
490 | 3.98M | return pdfi_dict_get_no_store_R_inner(ctx, d, NULL, Key, o); |
491 | 3.98M | } |
492 | | |
493 | | /* Convenience routine for common case where there are two possible keys */ |
494 | | int |
495 | | pdfi_dict_get_type2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, pdf_obj_type type, pdf_obj **o) |
496 | 0 | { |
497 | 0 | int code; |
498 | | |
499 | | /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. Assume abbreviated names are shorter :-) */ |
500 | 0 | if (strlen(Key1) < strlen(Key2)) { |
501 | 0 | code = pdfi_dict_get_type(ctx, d, Key1, type, o); |
502 | 0 | if (code == gs_error_undefined) |
503 | 0 | code = pdfi_dict_get_type(ctx, d, Key2, type, o); |
504 | 0 | } else { |
505 | 0 | code = pdfi_dict_get_type(ctx, d, Key2, type, o); |
506 | 0 | if (code == gs_error_undefined) |
507 | 0 | code = pdfi_dict_get_type(ctx, d, Key1, type, o); |
508 | 0 | } |
509 | 0 | return code; |
510 | 0 | } |
511 | | |
512 | | int pdfi_dict_get_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type type, pdf_obj **o) |
513 | 27.1M | { |
514 | 27.1M | int code; |
515 | | |
516 | 27.1M | code = pdfi_dict_get(ctx, d, Key, o); |
517 | 27.1M | if (code < 0) |
518 | 2.79M | return code; |
519 | | |
520 | 24.3M | if (pdfi_type_of(*o) != type) { |
521 | 43.8k | pdfi_countdown(*o); |
522 | 43.8k | *o = NULL; |
523 | 43.8k | return_error(gs_error_typecheck); |
524 | 43.8k | } |
525 | 24.3M | return 0; |
526 | 24.3M | } |
527 | | |
528 | | int pdfi_dict_get_type_no_store_R(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type type, pdf_obj **o) |
529 | 206 | { |
530 | 206 | int code; |
531 | | |
532 | 206 | code = pdfi_dict_get_no_store_R(ctx, d, Key, o); |
533 | 206 | if (code < 0) |
534 | 11 | return code; |
535 | | |
536 | 195 | if (pdfi_type_of(*o) != type) { |
537 | 0 | pdfi_countdown(*o); |
538 | 0 | *o = NULL; |
539 | 0 | return_error(gs_error_typecheck); |
540 | 0 | } |
541 | 195 | return 0; |
542 | 195 | } |
543 | | |
544 | | /* Convenience routine for common case where value has two possible keys */ |
545 | | int |
546 | | pdfi_dict_get_int2(pdf_context *ctx, pdf_dict *d, const char *Key1, |
547 | | const char *Key2, int64_t *i) |
548 | 381k | { |
549 | 381k | int code; |
550 | | |
551 | | /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. Assume abbreviated names are shorter :-) */ |
552 | 381k | if (strlen(Key1) < strlen(Key2)) { |
553 | 0 | code = pdfi_dict_get_int(ctx, d, Key1, i); |
554 | 0 | if (code == gs_error_undefined) |
555 | 0 | code = pdfi_dict_get_int(ctx, d, Key2, i); |
556 | 381k | } else { |
557 | 381k | code = pdfi_dict_get_int(ctx, d, Key2, i); |
558 | 381k | if (code == gs_error_undefined) |
559 | 157k | code = pdfi_dict_get_int(ctx, d, Key1, i); |
560 | 381k | } |
561 | 381k | return code; |
562 | 381k | } |
563 | | |
564 | | int pdfi_dict_get_int(pdf_context *ctx, pdf_dict *d, const char *Key, int64_t *i) |
565 | 7.11M | { |
566 | 7.11M | int code; |
567 | 7.11M | pdf_obj *n; |
568 | | |
569 | 7.11M | code = pdfi_dict_get(ctx, d, Key, &n); |
570 | 7.11M | if (code < 0) |
571 | 1.52M | return code; |
572 | 5.59M | code = pdfi_obj_to_int(ctx, n, i); |
573 | 5.59M | pdfi_countdown(n); |
574 | 5.59M | return code; |
575 | 7.11M | } |
576 | | |
577 | | /* Get an int from dict, and if undefined, return provided default */ |
578 | | int pdfi_dict_get_int_def(pdf_context *ctx, pdf_dict *d, const char *Key, int64_t *i, |
579 | | int64_t def_val) |
580 | 177k | { |
581 | 177k | int code; |
582 | | |
583 | 177k | code = pdfi_dict_get_int(ctx, d, Key, i); |
584 | 177k | if (code == gs_error_undefined) { |
585 | 25.6k | *i = def_val; |
586 | 25.6k | code = 0; |
587 | 25.6k | } |
588 | | |
589 | 177k | return code; |
590 | 177k | } |
591 | | |
592 | | /* Convenience routine for common case where value has two possible keys */ |
593 | | int |
594 | | pdfi_dict_get_bool2(pdf_context *ctx, pdf_dict *d, const char *Key1, |
595 | | const char *Key2, bool *val) |
596 | 763k | { |
597 | 763k | int code; |
598 | | |
599 | | /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. Assume abbreviated names are shorter :-) */ |
600 | 763k | if (strlen(Key1) < strlen(Key2)) { |
601 | 0 | code = pdfi_dict_get_bool(ctx, d, Key1, val); |
602 | 0 | if (code == gs_error_undefined) |
603 | 0 | code = pdfi_dict_get_bool(ctx, d, Key2, val); |
604 | 763k | } else { |
605 | 763k | code = pdfi_dict_get_bool(ctx, d, Key2, val); |
606 | 763k | if (code == gs_error_undefined) |
607 | 540k | code = pdfi_dict_get_bool(ctx, d, Key1, val); |
608 | 763k | } |
609 | 763k | return code; |
610 | 763k | } |
611 | | |
612 | | int pdfi_dict_get_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool *val) |
613 | 2.29M | { |
614 | 2.29M | int code; |
615 | 2.29M | pdf_obj *b; |
616 | | |
617 | 2.29M | code = pdfi_dict_get(ctx, d, Key, &b); |
618 | 2.29M | if (code < 0) |
619 | 1.31M | return code; |
620 | | |
621 | 979k | if (b == PDF_TRUE_OBJ) { |
622 | 471k | *val = 1; |
623 | 471k | return 0; |
624 | 507k | } else if (b == PDF_FALSE_OBJ) { |
625 | 507k | *val = 0; |
626 | 507k | return 0; |
627 | 507k | } |
628 | | |
629 | 81 | pdfi_countdown(b); |
630 | | |
631 | 81 | *val = 0; /* Be consistent at least! */ |
632 | 81 | return_error(gs_error_typecheck); |
633 | 979k | } |
634 | | |
635 | | int pdfi_dict_get_number2(pdf_context *ctx, pdf_dict *d, const char *Key1, const char *Key2, double *f) |
636 | 765k | { |
637 | 765k | int code; |
638 | | |
639 | | /* ISO 32000-2:2020 (PDF 2.0) - abbreviated names take precendence. Assume abbreviated names are shorter :-) */ |
640 | 765k | if (strlen(Key1) < strlen(Key2)) { |
641 | 0 | code = pdfi_dict_get_number(ctx, d, Key1, f); |
642 | 0 | if (code == gs_error_undefined) |
643 | 0 | code = pdfi_dict_get_number(ctx, d, Key2, f); |
644 | 765k | } else { |
645 | 765k | code = pdfi_dict_get_number(ctx, d, Key2, f); |
646 | 765k | if (code == gs_error_undefined) |
647 | 316k | code = pdfi_dict_get_number(ctx, d, Key1, f); |
648 | 765k | } |
649 | 765k | return code; |
650 | 765k | } |
651 | | |
652 | | int pdfi_dict_get_number(pdf_context *ctx, pdf_dict *d, const char *Key, double *f) |
653 | 4.14M | { |
654 | 4.14M | int code; |
655 | 4.14M | pdf_obj *o; |
656 | | |
657 | 4.14M | code = pdfi_dict_get(ctx, d, Key, &o); |
658 | 4.14M | if (code < 0) |
659 | 1.94M | return code; |
660 | 2.19M | code = pdfi_obj_to_real(ctx, o, f); |
661 | 2.19M | pdfi_countdown(o); |
662 | | |
663 | 2.19M | return code; |
664 | 4.14M | } |
665 | | |
666 | | /* convenience functions for retrieving arrys, see shadings and functions */ |
667 | | |
668 | | /* The 'fill' versions fill existing arrays, and need a size, |
669 | | * the 'make' versions allocate memory and fill it. Both varieties return the |
670 | | * number of entries on success. The fill Matrix utility expects to always |
671 | | * receive 6 values. The Domain function expects to receive an even number of |
672 | | * entries and each pair must have the second element larger than the first. |
673 | | */ |
674 | | int fill_domain_from_dict(pdf_context *ctx, float *parray, int size, pdf_dict *dict) |
675 | 78.5k | { |
676 | 78.5k | int code, i; |
677 | 78.5k | pdf_array *a = NULL; |
678 | 78.5k | double f; |
679 | 78.5k | uint64_t array_size; |
680 | | |
681 | 78.5k | code = pdfi_dict_get(ctx, dict, "Domain", (pdf_obj **)&a); |
682 | 78.5k | if (code < 0) |
683 | 27.1k | return code; |
684 | 51.4k | if (pdfi_type_of(a) != PDF_ARRAY) { |
685 | 0 | pdfi_countdown(a); |
686 | 0 | return_error(gs_error_typecheck); |
687 | 0 | } |
688 | 51.4k | array_size = pdfi_array_size(a); |
689 | 51.4k | if (array_size & 1 || array_size > size) { |
690 | 6 | pdfi_countdown(a); |
691 | 6 | return_error(gs_error_rangecheck); |
692 | 6 | } |
693 | | |
694 | 154k | for (i=0;i< array_size;i++) { |
695 | 102k | code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f); |
696 | 102k | if (code < 0) { |
697 | 8 | pdfi_countdown(a); |
698 | 8 | return_error(code); |
699 | 8 | } |
700 | 102k | parray[i] = (float)f; |
701 | 102k | } |
702 | 51.4k | pdfi_countdown(a); |
703 | 51.4k | return array_size; |
704 | 51.4k | } |
705 | | |
706 | | int fill_float_array_from_dict(pdf_context *ctx, float *parray, int size, pdf_dict *dict, const char *Key) |
707 | 81.5k | { |
708 | 81.5k | int code, i; |
709 | 81.5k | pdf_array *a = NULL; |
710 | 81.5k | double f; |
711 | 81.5k | uint64_t array_size; |
712 | | |
713 | 81.5k | code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a); |
714 | 81.5k | if (code < 0) |
715 | 46 | return code; |
716 | 81.5k | if (pdfi_type_of(a) != PDF_ARRAY) { |
717 | 0 | code = gs_note_error(gs_error_typecheck); |
718 | 0 | goto exit; |
719 | 0 | } |
720 | 81.5k | array_size = pdfi_array_size(a); |
721 | 81.5k | if (array_size > size) { |
722 | 13 | code = gs_note_error(gs_error_rangecheck); |
723 | 13 | goto exit; |
724 | 13 | } |
725 | | |
726 | 426k | for (i=0; i< array_size; i++) { |
727 | 344k | code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f); |
728 | 344k | if (code < 0) |
729 | 9 | goto exit; |
730 | 344k | parray[i] = (float)f; |
731 | 344k | } |
732 | 81.5k | code = array_size; |
733 | 81.5k | exit: |
734 | 81.5k | pdfi_countdown(a); |
735 | 81.5k | return code; |
736 | 81.5k | } |
737 | | |
738 | | int fill_bool_array_from_dict(pdf_context *ctx, bool *parray, int size, pdf_dict *dict, const char *Key) |
739 | 78.4k | { |
740 | 78.4k | int code, i; |
741 | 78.4k | pdf_array *a = NULL; |
742 | 78.4k | pdf_obj *o; |
743 | 78.4k | uint64_t array_size; |
744 | | |
745 | 78.4k | code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a); |
746 | 78.4k | if (code < 0) |
747 | 450 | return code; |
748 | 78.0k | if (pdfi_type_of(a) != PDF_ARRAY) { |
749 | 4 | pdfi_countdown(a); |
750 | 4 | return_error(gs_error_typecheck); |
751 | 4 | } |
752 | 78.0k | array_size = pdfi_array_size(a); |
753 | 78.0k | if (array_size > size) |
754 | 0 | return_error(gs_error_rangecheck); |
755 | | |
756 | 234k | for (i=0;i< array_size;i++) { |
757 | 156k | code = pdfi_array_get(ctx, a, (uint64_t)i, (pdf_obj **)&o); |
758 | 156k | if (code < 0) { |
759 | 0 | pdfi_countdown(a); |
760 | 0 | return_error(code); |
761 | 0 | } |
762 | 156k | if (o == PDF_TRUE_OBJ) { |
763 | 155k | parray[i] = 1; |
764 | 155k | } else if (o == PDF_FALSE_OBJ) { |
765 | 1.01k | parray[i] = 0; |
766 | 1.01k | } else { |
767 | 6 | pdfi_countdown(o); |
768 | 6 | pdfi_countdown(a); |
769 | 6 | return_error(gs_error_typecheck); |
770 | 6 | } |
771 | 156k | } |
772 | 78.0k | pdfi_countdown(a); |
773 | 78.0k | return array_size; |
774 | 78.0k | } |
775 | | |
776 | | int fill_matrix_from_dict(pdf_context *ctx, float *parray, pdf_dict *dict) |
777 | 14 | { |
778 | 14 | int code, i; |
779 | 14 | pdf_array *a = NULL; |
780 | 14 | double f; |
781 | 14 | uint64_t array_size; |
782 | | |
783 | 14 | code = pdfi_dict_get(ctx, dict, "Matrix", (pdf_obj **)&a); |
784 | 14 | if (code < 0) |
785 | 14 | return code; |
786 | 0 | if (pdfi_type_of(a) != PDF_ARRAY) { |
787 | 0 | pdfi_countdown(a); |
788 | 0 | return_error(gs_error_typecheck); |
789 | 0 | } |
790 | 0 | array_size = pdfi_array_size(a); |
791 | 0 | if (array_size != 6) { |
792 | 0 | pdfi_countdown(a); |
793 | 0 | return_error(gs_error_rangecheck); |
794 | 0 | } |
795 | | |
796 | 0 | for (i=0; i< array_size; i++) { |
797 | 0 | code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f); |
798 | 0 | if (code < 0) { |
799 | 0 | pdfi_countdown(a); |
800 | 0 | return_error(code); |
801 | 0 | } |
802 | 0 | parray[i] = (float)f; |
803 | 0 | } |
804 | 0 | pdfi_countdown(a); |
805 | 0 | return array_size; |
806 | 0 | } |
807 | | |
808 | | /* Returns < 0 for error or the number of entries allocated */ |
809 | | int pdfi_make_float_array_from_dict(pdf_context *ctx, float **parray, pdf_dict *dict, const char *Key) |
810 | 1.01M | { |
811 | 1.01M | int code, i; |
812 | 1.01M | pdf_array *a = NULL; |
813 | 1.01M | float *arr = NULL; |
814 | 1.01M | double f; |
815 | 1.01M | uint64_t array_size; |
816 | | |
817 | 1.01M | *parray = NULL; |
818 | | |
819 | 1.01M | code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a); |
820 | 1.01M | if (code < 0) |
821 | 235k | return code; |
822 | 777k | if (pdfi_type_of(a) != PDF_ARRAY) { |
823 | 0 | pdfi_countdown(a); |
824 | 0 | return_error(gs_error_typecheck); |
825 | 0 | } |
826 | 777k | array_size = pdfi_array_size(a); |
827 | | |
828 | 777k | arr = (float *)gs_alloc_byte_array(ctx->memory, array_size, |
829 | 777k | sizeof(float), "array_from_dict_key"); |
830 | 777k | if (arr == NULL) |
831 | 0 | return_error(gs_error_VMerror); |
832 | | |
833 | 777k | *parray = arr; |
834 | | |
835 | 3.12M | for (i=0;i< array_size;i++) { |
836 | 2.34M | code = pdfi_array_get_number(ctx, a, (uint64_t)i, &f); |
837 | 2.34M | if (code < 0) { |
838 | 200 | gs_free_const_object(ctx->memory, arr, "float_array"); |
839 | 200 | *parray = NULL; |
840 | 200 | pdfi_countdown(a); |
841 | 200 | return_error(code); |
842 | 200 | } |
843 | 2.34M | (*parray)[i] = (float)f; |
844 | 2.34M | } |
845 | 777k | pdfi_countdown(a); |
846 | 777k | return array_size; |
847 | 777k | } |
848 | | |
849 | | int pdfi_make_int_array_from_dict(pdf_context *ctx, int **parray, pdf_dict *dict, const char *Key) |
850 | 47.1k | { |
851 | 47.1k | int code, i; |
852 | 47.1k | pdf_array *a = NULL; |
853 | 47.1k | int *arr = NULL; |
854 | 47.1k | pdf_num *o; |
855 | 47.1k | uint64_t array_size; |
856 | | |
857 | 47.1k | *parray = NULL; |
858 | | |
859 | 47.1k | code = pdfi_dict_get(ctx, dict, Key, (pdf_obj **)&a); |
860 | 47.1k | if (code < 0) |
861 | 30 | return code; |
862 | 47.1k | if (pdfi_type_of(a) != PDF_ARRAY) { |
863 | 0 | pdfi_countdown(a); |
864 | 0 | return_error(gs_error_typecheck); |
865 | 0 | } |
866 | 47.1k | array_size = pdfi_array_size(a); |
867 | 47.1k | arr = (int *)gs_alloc_byte_array(ctx->memory, array_size, |
868 | 47.1k | sizeof(int), "array_from_dict_key"); |
869 | 47.1k | if (arr == NULL) |
870 | 0 | return_error(gs_error_VMerror); |
871 | | |
872 | 47.1k | *parray = arr; |
873 | | |
874 | 95.1k | for (i=0;i< array_size;i++) { |
875 | 48.0k | code = pdfi_array_get_type(ctx, a, (uint64_t)i, PDF_INT, (pdf_obj **)&o); |
876 | 48.0k | if (code < 0) { |
877 | 45 | gs_free_const_object(ctx->memory, arr, "int_array"); |
878 | 45 | *parray = NULL; |
879 | 45 | pdfi_countdown(a); |
880 | 45 | return_error(code); |
881 | 45 | } |
882 | 48.0k | (*parray)[i] = (int)o->value.i; |
883 | 48.0k | pdfi_countdown(o); |
884 | 48.0k | } |
885 | 47.0k | pdfi_countdown(a); |
886 | 47.0k | return array_size; |
887 | 47.1k | } |
888 | | |
889 | | /* Put into dictionary with key as object - |
890 | | If the key already exists, we'll only replace it |
891 | | if "replace" is true. |
892 | | */ |
893 | | int pdfi_dict_put_obj(pdf_context *ctx, pdf_dict *d, pdf_obj *Key, pdf_obj *value, bool replace) |
894 | 47.8M | { |
895 | 47.8M | int i; |
896 | 47.8M | pdf_dict_entry *new_list; |
897 | | |
898 | 47.8M | if (pdfi_type_of(d) != PDF_DICT) |
899 | 0 | return_error(gs_error_typecheck); |
900 | | |
901 | 47.8M | if (pdfi_type_of(Key) != PDF_NAME) |
902 | 0 | return_error(gs_error_typecheck); |
903 | | |
904 | | /* First, do we have a Key/value pair already ? */ |
905 | 47.8M | i = pdfi_dict_find_key(ctx, d, (pdf_name *)Key, false); |
906 | 47.8M | if (i >= 0) { |
907 | 52.0k | if (d->list[i].value == value || replace == false) |
908 | | /* We already have this value stored with this key.... */ |
909 | 42.9k | return 0; |
910 | 9.06k | pdfi_countdown(d->list[i].value); |
911 | 9.06k | d->list[i].value = value; |
912 | 9.06k | pdfi_countup(value); |
913 | 9.06k | return 0; |
914 | 52.0k | } |
915 | | |
916 | 47.7M | d->is_sorted = false; |
917 | | |
918 | | /* Nope, its a new Key */ |
919 | 47.7M | if (d->size > d->entries) { |
920 | | /* We have a hole, find and use it */ |
921 | 19.6G | for (i=0;i< d->size;i++) { |
922 | 19.6G | if (d->list[i].key == NULL) { |
923 | 45.5M | d->list[i].key = Key; |
924 | 45.5M | pdfi_countup(Key); |
925 | 45.5M | d->list[i].value = value; |
926 | 45.5M | pdfi_countup(value); |
927 | 45.5M | d->entries++; |
928 | 45.5M | return 0; |
929 | 45.5M | } |
930 | 19.6G | } |
931 | 45.5M | } |
932 | | |
933 | 2.24M | new_list = (pdf_dict_entry *)gs_alloc_bytes(ctx->memory, (d->size + 1) * sizeof(pdf_dict_entry), "pdfi_dict_put reallocate dictionary key/values"); |
934 | 2.24M | if (new_list == NULL) { |
935 | 0 | return_error(gs_error_VMerror); |
936 | 0 | } |
937 | 2.24M | if (d->size > 0) |
938 | 2.08M | memcpy(new_list, d->list, d->size * sizeof(pdf_dict_entry)); |
939 | | |
940 | 2.24M | gs_free_object(ctx->memory, d->list, "pdfi_dict_put key/value reallocation"); |
941 | | |
942 | 2.24M | d->list = new_list; |
943 | | |
944 | 2.24M | d->list[d->size].key = Key; |
945 | 2.24M | d->list[d->size].value = value; |
946 | 2.24M | d->size++; |
947 | 2.24M | d->entries++; |
948 | 2.24M | pdfi_countup(Key); |
949 | 2.24M | pdfi_countup(value); |
950 | | |
951 | 2.24M | return 0; |
952 | 2.24M | } |
953 | | |
954 | | /* |
955 | | * Be very cautious using this routine; it does not check to see if a key already exists |
956 | | * in a dictionary!. This is initially at least intended for use by the font code, to build |
957 | | * a CharStrings dictionary. We do that by adding each glyph individually with a name |
958 | | * created from a loop counter, so we know there cannot be any duplicates, and the time |
959 | | * taken to check that each of 64K names was unique was quite significant. |
960 | | * See bug #705534, the old PDF interpreter (nullpage, 72 dpi) runs this file in ~20 seconds |
961 | | * pdfi runs it in around 40 seconds. With this change it runs in around 3 seconds. THis is, |
962 | | * of course, an extreme example. |
963 | | */ |
964 | | int pdfi_dict_put_unchecked(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value) |
965 | 3.23M | { |
966 | 3.23M | int i, code = 0; |
967 | 3.23M | pdf_dict_entry *new_list; |
968 | 3.23M | pdf_obj *key = NULL; |
969 | | |
970 | 3.23M | code = pdfi_name_alloc(ctx, (byte *)Key, strlen(Key), &key); |
971 | 3.23M | if (code < 0) |
972 | 0 | return code; |
973 | 3.23M | pdfi_countup(key); |
974 | | |
975 | 3.23M | if (d->size > d->entries) { |
976 | 3.23M | int search_start = d->entries < 1 ? 0 : d->entries - 1; |
977 | 3.23M | do { |
978 | | /* We have a hole, find and use it */ |
979 | 6.47M | for (i = search_start; i < d->size; i++) { |
980 | 6.47M | if (d->list[i].key == NULL) { |
981 | 3.23M | d->list[i].key = key; |
982 | 3.23M | d->list[i].value = value; |
983 | 3.23M | pdfi_countup(value); |
984 | 3.23M | d->entries++; |
985 | 3.23M | return 0; |
986 | 3.23M | } |
987 | 6.47M | } |
988 | 0 | if (search_start == 0) { |
989 | | /* This shouldn't ever happen, but just in case.... */ |
990 | 0 | break; |
991 | 0 | } |
992 | 0 | search_start = 0; |
993 | 0 | } while(1); |
994 | 3.23M | } |
995 | | |
996 | 0 | new_list = (pdf_dict_entry *)gs_alloc_bytes(ctx->memory, (d->size + 1) * sizeof(pdf_dict_entry), "pdfi_dict_put reallocate dictionary key/values"); |
997 | 0 | if (new_list == NULL) { |
998 | 0 | return_error(gs_error_VMerror); |
999 | 0 | } |
1000 | 0 | memcpy(new_list, d->list, d->size * sizeof(pdf_dict_entry)); |
1001 | |
|
1002 | 0 | gs_free_object(ctx->memory, d->list, "pdfi_dict_put key/value reallocation"); |
1003 | |
|
1004 | 0 | d->list = new_list; |
1005 | |
|
1006 | 0 | d->list[d->size].key = key; |
1007 | 0 | d->list[d->size].value = value; |
1008 | 0 | d->size++; |
1009 | 0 | d->entries++; |
1010 | 0 | pdfi_countup(value); |
1011 | |
|
1012 | 0 | return 0; |
1013 | 0 | } |
1014 | | |
1015 | | /* Put into dictionary with key as string */ |
1016 | | int pdfi_dict_put(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj *value) |
1017 | 3.54M | { |
1018 | 3.54M | int code; |
1019 | 3.54M | pdf_obj *key = NULL; |
1020 | | |
1021 | 3.54M | code = pdfi_name_alloc(ctx, (byte *)Key, strlen(Key), &key); |
1022 | 3.54M | if (code < 0) |
1023 | 0 | return code; |
1024 | 3.54M | pdfi_countup(key); |
1025 | | |
1026 | 3.54M | code = pdfi_dict_put_obj(ctx, d, key, value, true); |
1027 | 3.54M | pdfi_countdown(key); /* get rid of extra ref */ |
1028 | 3.54M | return code; |
1029 | 3.54M | } |
1030 | | |
1031 | | int pdfi_dict_put_int(pdf_context *ctx, pdf_dict *d, const char *key, int64_t value) |
1032 | 1.32k | { |
1033 | 1.32k | int code; |
1034 | 1.32k | pdf_num *obj; |
1035 | | |
1036 | 1.32k | code = pdfi_object_alloc(ctx, PDF_INT, 0, (pdf_obj **)&obj); |
1037 | 1.32k | if (code < 0) |
1038 | 0 | return code; |
1039 | 1.32k | obj->value.i = value; |
1040 | | |
1041 | 1.32k | return pdfi_dict_put(ctx, d, key, (pdf_obj *)obj); |
1042 | 1.32k | } |
1043 | | |
1044 | | int pdfi_dict_put_bool(pdf_context *ctx, pdf_dict *d, const char *key, bool value) |
1045 | 7.61k | { |
1046 | 7.61k | pdf_obj *obj = (value ? PDF_TRUE_OBJ : PDF_FALSE_OBJ); |
1047 | | |
1048 | 7.61k | return pdfi_dict_put(ctx, d, key, obj); |
1049 | 7.61k | } |
1050 | | |
1051 | | int pdfi_dict_put_name(pdf_context *ctx, pdf_dict *d, const char *key, const char *name) |
1052 | 0 | { |
1053 | 0 | int code; |
1054 | 0 | pdf_obj *obj = NULL; |
1055 | |
|
1056 | 0 | code = pdfi_name_alloc(ctx, (byte *)name, strlen(name), &obj); |
1057 | 0 | if (code < 0) |
1058 | 0 | return code; |
1059 | 0 | pdfi_countup(obj); |
1060 | |
|
1061 | 0 | code = pdfi_dict_put(ctx, d, key, obj); |
1062 | 0 | pdfi_countdown(obj); /* get rid of extra ref */ |
1063 | 0 | return code; |
1064 | 0 | } |
1065 | | |
1066 | | int pdfi_dict_copy(pdf_context *ctx, pdf_dict *target, pdf_dict *source) |
1067 | 24.3k | { |
1068 | 24.3k | int i=0, code = 0; |
1069 | | |
1070 | 33.8k | for (i=0;i< source->entries;i++) { |
1071 | 9.41k | code = pdfi_dict_put_obj(ctx, target, source->list[i].key, source->list[i].value, true); |
1072 | 9.41k | if (code < 0) |
1073 | 0 | return code; |
1074 | 9.41k | target->is_sorted = source->is_sorted; |
1075 | 9.41k | } |
1076 | 24.3k | return 0; |
1077 | 24.3k | } |
1078 | | |
1079 | | int pdfi_dict_known(pdf_context *ctx, pdf_dict *d, const char *Key, bool *known) |
1080 | 69.1M | { |
1081 | 69.1M | int i; |
1082 | | |
1083 | 69.1M | if (pdfi_type_of(d) != PDF_DICT) |
1084 | 2.91k | return_error(gs_error_typecheck); |
1085 | | |
1086 | 69.1M | *known = false; |
1087 | 69.1M | i = pdfi_dict_find(ctx, d, Key, true); |
1088 | 69.1M | if (i >= 0) |
1089 | 23.9M | *known = true; |
1090 | | |
1091 | 69.1M | return 0; |
1092 | 69.1M | } |
1093 | | |
1094 | | int pdfi_dict_known_by_key(pdf_context *ctx, pdf_dict *d, pdf_name *Key, bool *known) |
1095 | 104k | { |
1096 | 104k | int i; |
1097 | | |
1098 | 104k | if (pdfi_type_of(d) != PDF_DICT) |
1099 | 0 | return_error(gs_error_typecheck); |
1100 | | |
1101 | 104k | *known = false; |
1102 | 104k | i = pdfi_dict_find_key(ctx, d, Key, true); |
1103 | 104k | if (i >= 0) |
1104 | 93.8k | *known = true; |
1105 | | |
1106 | 104k | return 0; |
1107 | 104k | } |
1108 | | |
1109 | | /* Tests if a Key is present in the dictionary, if it is, retrieves the value associated with the |
1110 | | * key. Returns < 0 for error, 0 if the key is not found > 0 if the key is present, and initialises |
1111 | | * the value in the arguments. Since this uses pdf_dict_get(), the returned value has its |
1112 | | * reference count incremented by 1, just like pdfi_dict_get(). |
1113 | | */ |
1114 | | int pdfi_dict_knownget(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj **o) |
1115 | 9.98M | { |
1116 | 9.98M | bool known = false; |
1117 | 9.98M | int code; |
1118 | | |
1119 | 9.98M | code = pdfi_dict_known(ctx, d, Key, &known); |
1120 | 9.98M | if (code < 0) |
1121 | 522 | return code; |
1122 | | |
1123 | 9.98M | if (known == false) |
1124 | 6.69M | return 0; |
1125 | | |
1126 | 3.28M | code = pdfi_dict_get(ctx, d, Key, o); |
1127 | 3.28M | if (code < 0) |
1128 | 48.2k | return code; |
1129 | | |
1130 | 3.23M | return 1; |
1131 | 3.28M | } |
1132 | | |
1133 | | /* Like pdfi_dict_knownget() but allows the user to specify a type for the object that we get. |
1134 | | * returns < 0 for error (including typecheck if the object is not the requested type) |
1135 | | * 0 if the key is not found, or > 0 if the key was found and returned. |
1136 | | */ |
1137 | | int pdfi_dict_knownget_type(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type type, pdf_obj **o) |
1138 | 37.3M | { |
1139 | 37.3M | bool known = false; |
1140 | 37.3M | int code; |
1141 | | |
1142 | 37.3M | code = pdfi_dict_known(ctx, d, Key, &known); |
1143 | 37.3M | if (code < 0) |
1144 | 2.39k | return code; |
1145 | | |
1146 | 37.3M | if (known == false) |
1147 | 19.6M | return 0; |
1148 | | |
1149 | 17.7M | code = pdfi_dict_get_type(ctx, d, Key, type, o); |
1150 | 17.7M | if (code < 0) |
1151 | 467k | return code; |
1152 | | |
1153 | 17.2M | return 1; |
1154 | 17.7M | } |
1155 | | |
1156 | | /* As above but don't store any dereferenced object. Used for Annots when we need the /Parent but |
1157 | | * storing that back to the annot would create a circulare reference to the page object |
1158 | | */ |
1159 | | int pdfi_dict_knownget_type_no_store_R(pdf_context *ctx, pdf_dict *d, const char *Key, pdf_obj_type type, pdf_obj **o) |
1160 | 206 | { |
1161 | 206 | bool known = false; |
1162 | 206 | int code; |
1163 | | |
1164 | 206 | code = pdfi_dict_known(ctx, d, Key, &known); |
1165 | 206 | if (code < 0) |
1166 | 0 | return code; |
1167 | | |
1168 | 206 | if (known == false) |
1169 | 0 | return 0; |
1170 | | |
1171 | 206 | code = pdfi_dict_get_type_no_store_R(ctx, d, Key, type, o); |
1172 | 206 | if (code < 0) |
1173 | 11 | return code; |
1174 | | |
1175 | 195 | return 1; |
1176 | 206 | } |
1177 | | |
1178 | | int pdfi_dict_knownget_bool(pdf_context *ctx, pdf_dict *d, const char *Key, bool *b) |
1179 | 16.9k | { |
1180 | 16.9k | bool known = false; |
1181 | 16.9k | int code; |
1182 | | |
1183 | 16.9k | code = pdfi_dict_known(ctx, d, Key, &known); |
1184 | 16.9k | if (code < 0) |
1185 | 0 | return code; |
1186 | | |
1187 | 16.9k | if (known == false) |
1188 | 10.8k | return 0; |
1189 | | |
1190 | 6.17k | code = pdfi_dict_get_bool(ctx, d, Key, b); |
1191 | 6.17k | if (code < 0) |
1192 | 0 | return code; |
1193 | | |
1194 | 6.17k | return 1; |
1195 | 6.17k | } |
1196 | | |
1197 | | /* Like pdfi_dict_knownget_type() but retrieves numbers (two possible types) |
1198 | | */ |
1199 | | int pdfi_dict_knownget_number(pdf_context *ctx, pdf_dict *d, const char *Key, double *f) |
1200 | 1.80M | { |
1201 | 1.80M | bool known = false; |
1202 | 1.80M | int code; |
1203 | | |
1204 | 1.80M | code = pdfi_dict_known(ctx, d, Key, &known); |
1205 | 1.80M | if (code < 0) |
1206 | 0 | return code; |
1207 | | |
1208 | 1.80M | if (known == false) |
1209 | 1.67M | return 0; |
1210 | | |
1211 | 128k | code = pdfi_dict_get_number(ctx, d, Key, f); |
1212 | 128k | if (code < 0) |
1213 | 0 | return code; |
1214 | | |
1215 | 128k | return 1; |
1216 | 128k | } |
1217 | | |
1218 | | int pdfi_dict_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value, uint64_t *index) |
1219 | 2.29M | { |
1220 | 2.29M | int code; |
1221 | | |
1222 | 2.29M | if (pdfi_type_of(d) != PDF_DICT) |
1223 | 0 | return_error(gs_error_typecheck); |
1224 | | |
1225 | 2.29M | while (1) { |
1226 | 2.29M | if (*index >= d->entries) { |
1227 | 153k | *Key = NULL; |
1228 | 153k | *Value= NULL; |
1229 | 153k | return gs_error_undefined; |
1230 | 153k | } |
1231 | | |
1232 | | /* If we find NULL keys skip over them. This should never |
1233 | | * happen as we check the number of entries above, and we |
1234 | | * compact dictionaries on deletion of key/value pairs. |
1235 | | * This is a belt and braces check in case creation of the |
1236 | | * dictionary somehow ends up with NULL keys in the allocated |
1237 | | * section. |
1238 | | */ |
1239 | 2.14M | *Key = d->list[*index].key; |
1240 | 2.14M | if (*Key == NULL) { |
1241 | 0 | (*index)++; |
1242 | 0 | continue; |
1243 | 0 | } |
1244 | | |
1245 | 2.14M | if (pdfi_type_of(d->list[*index].value) == PDF_INDIRECT) { |
1246 | 1.38M | pdf_indirect_ref *r = (pdf_indirect_ref *)d->list[*index].value; |
1247 | 1.38M | pdf_obj *o; |
1248 | | |
1249 | 1.38M | code = pdfi_dereference(ctx, r->ref_object_num, r->ref_generation_num, &o); |
1250 | 1.38M | if (code < 0) { |
1251 | 293k | *Key = *Value = NULL; |
1252 | 293k | return code; |
1253 | 293k | } |
1254 | 1.09M | *Value = o; |
1255 | 1.09M | break; |
1256 | 1.38M | } else { |
1257 | 751k | *Value = d->list[*index].value; |
1258 | 751k | pdfi_countup(*Value); |
1259 | 751k | break; |
1260 | 751k | } |
1261 | 2.14M | } |
1262 | | |
1263 | 1.84M | pdfi_countup(*Key); |
1264 | 1.84M | (*index)++; |
1265 | 1.84M | return 0; |
1266 | 2.29M | } |
1267 | | |
1268 | | int pdfi_dict_first(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, pdf_obj **Value, uint64_t *index) |
1269 | 747k | { |
1270 | 747k | uint64_t *i = index; |
1271 | | |
1272 | 747k | *i = 0; |
1273 | 747k | return pdfi_dict_next(ctx, d, Key, Value, index); |
1274 | 747k | } |
1275 | | |
1276 | | int pdfi_dict_key_next(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, uint64_t *index) |
1277 | 80.1M | { |
1278 | 80.1M | uint64_t *i = index; |
1279 | | |
1280 | 80.1M | if (pdfi_type_of(d) != PDF_DICT) |
1281 | 0 | return_error(gs_error_typecheck); |
1282 | | |
1283 | 80.1M | while (1) { |
1284 | 80.1M | if (*i >= d->entries) { |
1285 | 102k | *Key = NULL; |
1286 | 102k | return gs_error_undefined; |
1287 | 102k | } |
1288 | | |
1289 | 80.0M | *Key = d->list[*i].key; |
1290 | 80.0M | if (*Key == NULL) { |
1291 | 0 | (*i)++; |
1292 | 0 | continue; |
1293 | 0 | } |
1294 | 80.0M | pdfi_countup(*Key); |
1295 | 80.0M | (*i)++; |
1296 | 80.0M | break; |
1297 | 80.0M | } |
1298 | 80.0M | return 0; |
1299 | 80.1M | } |
1300 | | |
1301 | | int pdfi_dict_key_first(pdf_context *ctx, pdf_dict *d, pdf_obj **Key, uint64_t *index) |
1302 | 521k | { |
1303 | 521k | uint64_t *i = index; |
1304 | | |
1305 | 521k | *i = 0; |
1306 | 521k | return pdfi_dict_key_next(ctx, d, Key, index); |
1307 | 521k | } |
1308 | | |
1309 | | int pdfi_merge_dicts(pdf_context *ctx, pdf_dict *target, pdf_dict *source) |
1310 | 216k | { |
1311 | 216k | int i, code; |
1312 | 216k | bool known = false; |
1313 | | |
1314 | 319k | for (i=0;i< source->entries;i++) { |
1315 | 103k | code = pdfi_dict_known_by_key(ctx, target, (pdf_name *)source->list[i].key, &known); |
1316 | 103k | if (code < 0) |
1317 | 0 | return code; |
1318 | 103k | if (!known) { |
1319 | 10.2k | code = pdfi_dict_put_obj(ctx, target, source->list[i].key, source->list[i].value, true); |
1320 | 10.2k | if (code < 0) |
1321 | 0 | return code; |
1322 | 10.2k | } |
1323 | 103k | } |
1324 | 216k | target->is_sorted = false; |
1325 | 216k | return 0; |
1326 | 216k | } |
1327 | | |
1328 | | /* Return Length of a stream, or 0 if it's not a stream |
1329 | | * Caches the Length |
1330 | | */ |
1331 | | int64_t pdfi_stream_length(pdf_context *ctx, pdf_stream *stream) |
1332 | 634k | { |
1333 | 634k | int64_t Length = 0; |
1334 | 634k | int code; |
1335 | | |
1336 | 634k | if (pdfi_type_of(stream) != PDF_STREAM) |
1337 | 0 | return 0; |
1338 | | |
1339 | 634k | if (stream->length_valid) |
1340 | 403k | return stream->Length; |
1341 | | |
1342 | 230k | code = pdfi_dict_get_int(ctx, stream->stream_dict, "Length", &Length); |
1343 | 230k | if (code < 0) |
1344 | 229k | Length = 0; |
1345 | | |
1346 | | /* Make sure Length is not negative... */ |
1347 | 230k | if (Length < 0) |
1348 | 0 | Length = 0; |
1349 | | |
1350 | | /* Cache it */ |
1351 | 230k | stream->Length = Length; |
1352 | 230k | stream->length_valid = true; |
1353 | | |
1354 | 230k | return 0; |
1355 | 634k | } |
1356 | | |
1357 | | /* Safely get offset from a stream object. |
1358 | | * If it's not actually a stream, just return 0. |
1359 | | */ |
1360 | | gs_offset_t pdfi_stream_offset(pdf_context *ctx, pdf_stream *stream) |
1361 | 2.66M | { |
1362 | 2.66M | if (pdfi_type_of(stream) != PDF_STREAM) |
1363 | 44 | return 0; |
1364 | 2.66M | return stream->stream_offset; |
1365 | 2.66M | } |
1366 | | |
1367 | | pdf_stream *pdfi_stream_parent(pdf_context *ctx, pdf_stream *stream) |
1368 | 1.36M | { |
1369 | 1.36M | if (pdfi_type_of(stream) != PDF_STREAM) |
1370 | 45.5k | return 0; |
1371 | 1.32M | return (pdf_stream *)stream->parent_obj; |
1372 | 1.36M | } |
1373 | | |
1374 | | void pdfi_set_stream_parent(pdf_context *ctx, pdf_stream *stream, pdf_stream *parent) |
1375 | 516k | { |
1376 | | /* Ordinarily we would increment the reference count of the parent object here, |
1377 | | * because we are taking a new reference to it. But if we do that we will end up |
1378 | | * with circular references and will never count down and release the objects. |
1379 | | * This is because the parent object must have a Resources dictionary which |
1380 | | * references this stream, when we dereference the stream we store it in the |
1381 | | * Parent's Resources dictionary. So the parent points to the child, the child |
1382 | | * points to the parent and we always end up with a refcnt for each of 1. Since we |
1383 | | * only ever consult parent_obj in an illegal case we deal with this by not |
1384 | | * incrementing the reference count. To try and avoid any dangling references |
1385 | | * we clear the parent_obj when we finish executing the stream in |
1386 | | * pdfi_interpret_content_stream. |
1387 | | */ |
1388 | 516k | stream->parent_obj = (pdf_obj *)parent; |
1389 | 516k | } |
1390 | | |
1391 | | void pdfi_clear_stream_parent(pdf_context *ctx, pdf_stream *stream) |
1392 | 516k | { |
1393 | 516k | stream->parent_obj = NULL; |
1394 | 516k | } |
1395 | | |
1396 | | /* Get the dict from a pdf_obj, returns typecheck if it doesn't have one */ |
1397 | | int pdfi_dict_from_obj(pdf_context *ctx, pdf_obj *obj, pdf_dict **dict) |
1398 | 103M | { |
1399 | 103M | *dict = NULL; |
1400 | 103M | switch (pdfi_type_of(obj)) { |
1401 | 398k | case PDF_DICT: |
1402 | 398k | *dict = (pdf_dict *)obj; |
1403 | 398k | break; |
1404 | 103M | case PDF_STREAM: |
1405 | 103M | *dict = ((pdf_stream *)obj)->stream_dict; |
1406 | 103M | break; |
1407 | 941 | default: |
1408 | 941 | return_error(gs_error_typecheck); |
1409 | 103M | } |
1410 | 103M | return 0; |
1411 | 103M | } |