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