1 | #include "mupdf/fitz.h" |
2 | #include "mupdf/pdf.h" |
3 | #include "../fitz/fitz-imp.h" |
4 | |
5 | #include <stdarg.h> |
6 | #include <stdlib.h> |
7 | #include <string.h> |
8 | |
9 | #define PDF_MAKE_NAME(STRING,NAME) STRING, |
10 | static const char *PDF_NAME_LIST[] = { |
11 | "" , "" , "" , /* dummy slots for null, true, and false */ |
12 | #include "mupdf/pdf/name-table.h" |
13 | }; |
14 | #undef PDF_MAKE_NAME |
15 | |
16 | typedef enum pdf_objkind_e |
17 | { |
18 | PDF_INT = 'i', |
19 | PDF_REAL = 'f', |
20 | PDF_STRING = 's', |
21 | PDF_NAME = 'n', |
22 | PDF_ARRAY = 'a', |
23 | PDF_DICT = 'd', |
24 | PDF_INDIRECT = 'r' |
25 | } pdf_objkind; |
26 | |
27 | struct keyval |
28 | { |
29 | pdf_obj *k; |
30 | pdf_obj *v; |
31 | }; |
32 | |
33 | enum |
34 | { |
35 | PDF_FLAGS_MARKED = 1, |
36 | PDF_FLAGS_SORTED = 2, |
37 | PDF_FLAGS_DIRTY = 4, |
38 | PDF_FLAGS_MEMO_BASE = 8, |
39 | PDF_FLAGS_MEMO_BASE_BOOL = 16 |
40 | }; |
41 | |
42 | struct pdf_obj_s |
43 | { |
44 | short refs; |
45 | unsigned char kind; |
46 | unsigned char flags; |
47 | }; |
48 | |
49 | typedef struct pdf_obj_num_s |
50 | { |
51 | pdf_obj super; |
52 | union |
53 | { |
54 | int64_t i; |
55 | float f; |
56 | } u; |
57 | } pdf_obj_num; |
58 | |
59 | typedef struct pdf_obj_string_s |
60 | { |
61 | pdf_obj super; |
62 | char *text; /* utf8 encoded text string */ |
63 | unsigned int len; |
64 | char buf[1]; |
65 | } pdf_obj_string; |
66 | |
67 | typedef struct pdf_obj_name_s |
68 | { |
69 | pdf_obj super; |
70 | char n[1]; |
71 | } pdf_obj_name; |
72 | |
73 | typedef struct pdf_obj_array_s |
74 | { |
75 | pdf_obj super; |
76 | pdf_document *doc; |
77 | int parent_num; |
78 | int len; |
79 | int cap; |
80 | pdf_obj **items; |
81 | } pdf_obj_array; |
82 | |
83 | typedef struct pdf_obj_dict_s |
84 | { |
85 | pdf_obj super; |
86 | pdf_document *doc; |
87 | int parent_num; |
88 | int len; |
89 | int cap; |
90 | struct keyval *items; |
91 | } pdf_obj_dict; |
92 | |
93 | typedef struct pdf_obj_ref_s |
94 | { |
95 | pdf_obj super; |
96 | pdf_document *doc; /* Only needed for arrays, dicts and indirects */ |
97 | int num; |
98 | int gen; |
99 | } pdf_obj_ref; |
100 | |
101 | #define NAME(obj) ((pdf_obj_name *)(obj)) |
102 | #define NUM(obj) ((pdf_obj_num *)(obj)) |
103 | #define STRING(obj) ((pdf_obj_string *)(obj)) |
104 | #define DICT(obj) ((pdf_obj_dict *)(obj)) |
105 | #define ARRAY(obj) ((pdf_obj_array *)(obj)) |
106 | #define REF(obj) ((pdf_obj_ref *)(obj)) |
107 | |
108 | pdf_obj * |
109 | pdf_new_int(fz_context *ctx, int64_t i) |
110 | { |
111 | pdf_obj_num *obj; |
112 | obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_num)), "pdf_obj(int)" ); |
113 | obj->super.refs = 1; |
114 | obj->super.kind = PDF_INT; |
115 | obj->super.flags = 0; |
116 | obj->u.i = i; |
117 | return &obj->super; |
118 | } |
119 | |
120 | pdf_obj * |
121 | pdf_new_real(fz_context *ctx, float f) |
122 | { |
123 | pdf_obj_num *obj; |
124 | obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_num)), "pdf_obj(real)" ); |
125 | obj->super.refs = 1; |
126 | obj->super.kind = PDF_REAL; |
127 | obj->super.flags = 0; |
128 | obj->u.f = f; |
129 | return &obj->super; |
130 | } |
131 | |
132 | pdf_obj * |
133 | pdf_new_string(fz_context *ctx, const char *str, size_t len) |
134 | { |
135 | pdf_obj_string *obj; |
136 | unsigned int l = (unsigned int)len; |
137 | |
138 | if ((size_t)l != len) |
139 | fz_throw(ctx, FZ_ERROR_GENERIC, "Overflow in pdf string" ); |
140 | |
141 | obj = Memento_label(fz_malloc(ctx, offsetof(pdf_obj_string, buf) + len + 1), "pdf_obj(string)" ); |
142 | obj->super.refs = 1; |
143 | obj->super.kind = PDF_STRING; |
144 | obj->super.flags = 0; |
145 | obj->text = NULL; |
146 | obj->len = l; |
147 | memcpy(obj->buf, str, len); |
148 | obj->buf[len] = '\0'; |
149 | return &obj->super; |
150 | } |
151 | |
152 | pdf_obj * |
153 | pdf_new_name(fz_context *ctx, const char *str) |
154 | { |
155 | pdf_obj_name *obj; |
156 | int l = 3; /* skip dummy slots */ |
157 | int r = nelem(PDF_NAME_LIST) - 1; |
158 | while (l <= r) |
159 | { |
160 | int m = (l + r) >> 1; |
161 | int c = strcmp(str, PDF_NAME_LIST[m]); |
162 | if (c < 0) |
163 | r = m - 1; |
164 | else if (c > 0) |
165 | l = m + 1; |
166 | else |
167 | return (pdf_obj*)(intptr_t)m; |
168 | } |
169 | |
170 | obj = Memento_label(fz_malloc(ctx, offsetof(pdf_obj_name, n) + strlen(str) + 1), "pdf_obj(name)" ); |
171 | obj->super.refs = 1; |
172 | obj->super.kind = PDF_NAME; |
173 | obj->super.flags = 0; |
174 | strcpy(obj->n, str); |
175 | return &obj->super; |
176 | } |
177 | |
178 | pdf_obj * |
179 | pdf_new_indirect(fz_context *ctx, pdf_document *doc, int num, int gen) |
180 | { |
181 | pdf_obj_ref *obj; |
182 | obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_ref)), "pdf_obj(indirect)" ); |
183 | obj->super.refs = 1; |
184 | obj->super.kind = PDF_INDIRECT; |
185 | obj->super.flags = 0; |
186 | obj->doc = doc; |
187 | obj->num = num; |
188 | obj->gen = gen; |
189 | return &obj->super; |
190 | } |
191 | |
192 | #define OBJ_IS_NULL(obj) (obj == PDF_NULL) |
193 | #define OBJ_IS_BOOL(obj) (obj == PDF_TRUE || obj == PDF_FALSE) |
194 | #define OBJ_IS_NAME(obj) ((obj > PDF_FALSE && obj < PDF_LIMIT) || (obj >= PDF_LIMIT && obj->kind == PDF_NAME)) |
195 | #define OBJ_IS_INT(obj) \ |
196 | (obj >= PDF_LIMIT && obj->kind == PDF_INT) |
197 | #define OBJ_IS_REAL(obj) \ |
198 | (obj >= PDF_LIMIT && obj->kind == PDF_REAL) |
199 | #define OBJ_IS_NUMBER(obj) \ |
200 | (obj >= PDF_LIMIT && (obj->kind == PDF_REAL || obj->kind == PDF_INT)) |
201 | #define OBJ_IS_STRING(obj) \ |
202 | (obj >= PDF_LIMIT && obj->kind == PDF_STRING) |
203 | #define OBJ_IS_ARRAY(obj) \ |
204 | (obj >= PDF_LIMIT && obj->kind == PDF_ARRAY) |
205 | #define OBJ_IS_DICT(obj) \ |
206 | (obj >= PDF_LIMIT && obj->kind == PDF_DICT) |
207 | #define OBJ_IS_INDIRECT(obj) \ |
208 | (obj >= PDF_LIMIT && obj->kind == PDF_INDIRECT) |
209 | |
210 | #define RESOLVE(obj) \ |
211 | if (OBJ_IS_INDIRECT(obj)) \ |
212 | obj = pdf_resolve_indirect_chain(ctx, obj); \ |
213 | |
214 | int pdf_is_indirect(fz_context *ctx, pdf_obj *obj) |
215 | { |
216 | return OBJ_IS_INDIRECT(obj); |
217 | } |
218 | |
219 | int pdf_is_null(fz_context *ctx, pdf_obj *obj) |
220 | { |
221 | RESOLVE(obj); |
222 | return OBJ_IS_NULL(obj); |
223 | } |
224 | |
225 | int pdf_is_bool(fz_context *ctx, pdf_obj *obj) |
226 | { |
227 | RESOLVE(obj); |
228 | return OBJ_IS_BOOL(obj); |
229 | } |
230 | |
231 | int pdf_is_int(fz_context *ctx, pdf_obj *obj) |
232 | { |
233 | RESOLVE(obj); |
234 | return OBJ_IS_INT(obj); |
235 | } |
236 | |
237 | int pdf_is_real(fz_context *ctx, pdf_obj *obj) |
238 | { |
239 | RESOLVE(obj); |
240 | return OBJ_IS_REAL(obj); |
241 | } |
242 | |
243 | int pdf_is_number(fz_context *ctx, pdf_obj *obj) |
244 | { |
245 | RESOLVE(obj); |
246 | return OBJ_IS_NUMBER(obj); |
247 | } |
248 | |
249 | int pdf_is_string(fz_context *ctx, pdf_obj *obj) |
250 | { |
251 | RESOLVE(obj); |
252 | return OBJ_IS_STRING(obj); |
253 | } |
254 | |
255 | int pdf_is_name(fz_context *ctx, pdf_obj *obj) |
256 | { |
257 | RESOLVE(obj); |
258 | return OBJ_IS_NAME(obj); |
259 | } |
260 | |
261 | int pdf_is_array(fz_context *ctx, pdf_obj *obj) |
262 | { |
263 | RESOLVE(obj); |
264 | return OBJ_IS_ARRAY(obj); |
265 | } |
266 | |
267 | int pdf_is_dict(fz_context *ctx, pdf_obj *obj) |
268 | { |
269 | RESOLVE(obj); |
270 | return OBJ_IS_DICT(obj); |
271 | } |
272 | |
273 | /* safe, silent failure, no error reporting on type mismatches */ |
274 | int pdf_to_bool(fz_context *ctx, pdf_obj *obj) |
275 | { |
276 | RESOLVE(obj); |
277 | return obj == PDF_TRUE; |
278 | } |
279 | |
280 | int pdf_to_int(fz_context *ctx, pdf_obj *obj) |
281 | { |
282 | RESOLVE(obj); |
283 | if (obj < PDF_LIMIT) |
284 | return 0; |
285 | if (obj->kind == PDF_INT) |
286 | return (int)NUM(obj)->u.i; |
287 | if (obj->kind == PDF_REAL) |
288 | return (int)(NUM(obj)->u.f + 0.5f); /* No roundf in MSVC */ |
289 | return 0; |
290 | } |
291 | |
292 | int64_t pdf_to_int64(fz_context *ctx, pdf_obj *obj) |
293 | { |
294 | RESOLVE(obj); |
295 | if (obj < PDF_LIMIT) |
296 | return 0; |
297 | if (obj->kind == PDF_INT) |
298 | return NUM(obj)->u.i; |
299 | if (obj->kind == PDF_REAL) |
300 | return (NUM(obj)->u.f + 0.5f); /* No roundf in MSVC */ |
301 | return 0; |
302 | } |
303 | |
304 | float pdf_to_real(fz_context *ctx, pdf_obj *obj) |
305 | { |
306 | RESOLVE(obj); |
307 | if (obj < PDF_LIMIT) |
308 | return 0; |
309 | if (obj->kind == PDF_REAL) |
310 | return NUM(obj)->u.f; |
311 | if (obj->kind == PDF_INT) |
312 | return NUM(obj)->u.i; |
313 | return 0; |
314 | } |
315 | |
316 | const char *pdf_to_name(fz_context *ctx, pdf_obj *obj) |
317 | { |
318 | RESOLVE(obj); |
319 | if (obj < PDF_LIMIT) |
320 | return PDF_NAME_LIST[((intptr_t)obj)]; |
321 | if (obj->kind == PDF_NAME) |
322 | return NAME(obj)->n; |
323 | return "" ; |
324 | } |
325 | |
326 | char *pdf_to_str_buf(fz_context *ctx, pdf_obj *obj) |
327 | { |
328 | RESOLVE(obj); |
329 | if (OBJ_IS_STRING(obj)) |
330 | return STRING(obj)->buf; |
331 | return "" ; |
332 | } |
333 | |
334 | int pdf_to_str_len(fz_context *ctx, pdf_obj *obj) |
335 | { |
336 | RESOLVE(obj); |
337 | if (OBJ_IS_STRING(obj)) |
338 | return STRING(obj)->len; |
339 | return 0; |
340 | } |
341 | |
342 | const char *pdf_to_string(fz_context *ctx, pdf_obj *obj, size_t *sizep) |
343 | { |
344 | RESOLVE(obj); |
345 | if (OBJ_IS_STRING(obj)) |
346 | { |
347 | if (sizep) |
348 | *sizep = STRING(obj)->len; |
349 | return STRING(obj)->buf; |
350 | } |
351 | if (sizep) |
352 | *sizep = 0; |
353 | return "" ; |
354 | } |
355 | |
356 | const char *pdf_to_text_string(fz_context *ctx, pdf_obj *obj) |
357 | { |
358 | RESOLVE(obj); |
359 | if (OBJ_IS_STRING(obj)) |
360 | { |
361 | if (!STRING(obj)->text) |
362 | STRING(obj)->text = pdf_new_utf8_from_pdf_string(ctx, STRING(obj)->buf, STRING(obj)->len); |
363 | return STRING(obj)->text; |
364 | } |
365 | return "" ; |
366 | } |
367 | |
368 | void pdf_set_int(fz_context *ctx, pdf_obj *obj, int64_t i) |
369 | { |
370 | if (OBJ_IS_INT(obj)) |
371 | NUM(obj)->u.i = i; |
372 | } |
373 | |
374 | /* for use by pdf_crypt_obj_imp to decrypt AES string in place */ |
375 | void pdf_set_str_len(fz_context *ctx, pdf_obj *obj, int newlen) |
376 | { |
377 | RESOLVE(obj); |
378 | if (!OBJ_IS_STRING(obj)) |
379 | return; /* This should never happen */ |
380 | if (newlen < 0 || (unsigned int)newlen > STRING(obj)->len) |
381 | return; /* This should never happen */ |
382 | STRING(obj)->buf[newlen] = 0; |
383 | STRING(obj)->len = newlen; |
384 | } |
385 | |
386 | int pdf_to_num(fz_context *ctx, pdf_obj *obj) |
387 | { |
388 | if (OBJ_IS_INDIRECT(obj)) |
389 | return REF(obj)->num; |
390 | return 0; |
391 | } |
392 | |
393 | int pdf_to_gen(fz_context *ctx, pdf_obj *obj) |
394 | { |
395 | if (OBJ_IS_INDIRECT(obj)) |
396 | return REF(obj)->gen; |
397 | return 0; |
398 | } |
399 | |
400 | pdf_document *pdf_get_indirect_document(fz_context *ctx, pdf_obj *obj) |
401 | { |
402 | if (OBJ_IS_INDIRECT(obj)) |
403 | return REF(obj)->doc; |
404 | return NULL; |
405 | } |
406 | |
407 | pdf_document *pdf_get_bound_document(fz_context *ctx, pdf_obj *obj) |
408 | { |
409 | if (obj < PDF_LIMIT) |
410 | return NULL; |
411 | if (obj->kind == PDF_INDIRECT) |
412 | return REF(obj)->doc; |
413 | if (obj->kind == PDF_ARRAY) |
414 | return ARRAY(obj)->doc; |
415 | if (obj->kind == PDF_DICT) |
416 | return DICT(obj)->doc; |
417 | return NULL; |
418 | } |
419 | |
420 | int pdf_objcmp_resolve(fz_context *ctx, pdf_obj *a, pdf_obj *b) |
421 | { |
422 | RESOLVE(a); |
423 | RESOLVE(b); |
424 | return pdf_objcmp(ctx, a, b); |
425 | } |
426 | |
427 | int |
428 | pdf_objcmp(fz_context *ctx, pdf_obj *a, pdf_obj *b) |
429 | { |
430 | int i; |
431 | |
432 | if (a == b) |
433 | return 0; |
434 | |
435 | /* a or b is null, true, or false */ |
436 | if (a <= PDF_FALSE || b <= PDF_FALSE) |
437 | return 1; |
438 | |
439 | /* a is a constant name */ |
440 | if (a < PDF_LIMIT) |
441 | { |
442 | if (b < PDF_LIMIT) |
443 | return a != b; |
444 | if (b->kind != PDF_NAME) |
445 | return 1; |
446 | return strcmp(PDF_NAME_LIST[(intptr_t)a], NAME(b)->n); |
447 | } |
448 | |
449 | /* b is a constant name */ |
450 | if (b < PDF_LIMIT) |
451 | { |
452 | if (a->kind != PDF_NAME) |
453 | return 1; |
454 | return strcmp(NAME(a)->n, PDF_NAME_LIST[(intptr_t)b]); |
455 | } |
456 | |
457 | /* both a and b are allocated objects */ |
458 | if (a->kind != b->kind) |
459 | return 1; |
460 | |
461 | switch (a->kind) |
462 | { |
463 | case PDF_INT: |
464 | return NUM(a)->u.i - NUM(b)->u.i; |
465 | |
466 | case PDF_REAL: |
467 | if (NUM(a)->u.f < NUM(b)->u.f) |
468 | return -1; |
469 | if (NUM(a)->u.f > NUM(b)->u.f) |
470 | return 1; |
471 | return 0; |
472 | |
473 | case PDF_STRING: |
474 | if (STRING(a)->len < STRING(b)->len) |
475 | { |
476 | if (memcmp(STRING(a)->buf, STRING(b)->buf, STRING(a)->len) <= 0) |
477 | return -1; |
478 | return 1; |
479 | } |
480 | if (STRING(a)->len > STRING(b)->len) |
481 | { |
482 | if (memcmp(STRING(a)->buf, STRING(b)->buf, STRING(b)->len) >= 0) |
483 | return 1; |
484 | return -1; |
485 | } |
486 | return memcmp(STRING(a)->buf, STRING(b)->buf, STRING(a)->len); |
487 | |
488 | case PDF_NAME: |
489 | return strcmp(NAME(a)->n, NAME(b)->n); |
490 | |
491 | case PDF_INDIRECT: |
492 | if (REF(a)->num == REF(b)->num) |
493 | return REF(a)->gen - REF(b)->gen; |
494 | return REF(a)->num - REF(b)->num; |
495 | |
496 | case PDF_ARRAY: |
497 | if (ARRAY(a)->len != ARRAY(b)->len) |
498 | return ARRAY(a)->len - ARRAY(b)->len; |
499 | for (i = 0; i < ARRAY(a)->len; i++) |
500 | if (pdf_objcmp(ctx, ARRAY(a)->items[i], ARRAY(b)->items[i])) |
501 | return 1; |
502 | return 0; |
503 | |
504 | case PDF_DICT: |
505 | if (DICT(a)->len != DICT(b)->len) |
506 | return DICT(a)->len - DICT(b)->len; |
507 | for (i = 0; i < DICT(a)->len; i++) |
508 | { |
509 | if (pdf_objcmp(ctx, DICT(a)->items[i].k, DICT(b)->items[i].k)) |
510 | return 1; |
511 | if (pdf_objcmp(ctx, DICT(a)->items[i].v, DICT(b)->items[i].v)) |
512 | return 1; |
513 | } |
514 | return 0; |
515 | } |
516 | return 1; |
517 | } |
518 | |
519 | int pdf_name_eq(fz_context *ctx, pdf_obj *a, pdf_obj *b) |
520 | { |
521 | RESOLVE(a); |
522 | RESOLVE(b); |
523 | if (a <= PDF_FALSE || b <= PDF_FALSE) |
524 | return 0; |
525 | if (a < PDF_LIMIT || b < PDF_LIMIT) |
526 | return (a == b); |
527 | if (a->kind == PDF_NAME && b->kind == PDF_NAME) |
528 | return !strcmp(NAME(a)->n, NAME(b)->n); |
529 | return 0; |
530 | } |
531 | |
532 | static char * |
533 | pdf_objkindstr(pdf_obj *obj) |
534 | { |
535 | if (obj == PDF_NULL) |
536 | return "null" ; |
537 | if (obj == PDF_TRUE || obj == PDF_FALSE) |
538 | return "boolean" ; |
539 | if (obj < PDF_LIMIT) |
540 | return "name" ; |
541 | switch (obj->kind) |
542 | { |
543 | case PDF_INT: return "integer" ; |
544 | case PDF_REAL: return "real" ; |
545 | case PDF_STRING: return "string" ; |
546 | case PDF_NAME: return "name" ; |
547 | case PDF_ARRAY: return "array" ; |
548 | case PDF_DICT: return "dictionary" ; |
549 | case PDF_INDIRECT: return "reference" ; |
550 | } |
551 | return "<unknown>" ; |
552 | } |
553 | |
554 | pdf_obj * |
555 | pdf_new_array(fz_context *ctx, pdf_document *doc, int initialcap) |
556 | { |
557 | pdf_obj_array *obj; |
558 | int i; |
559 | |
560 | obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_array)), "pdf_obj(array)" ); |
561 | obj->super.refs = 1; |
562 | obj->super.kind = PDF_ARRAY; |
563 | obj->super.flags = 0; |
564 | obj->doc = doc; |
565 | obj->parent_num = 0; |
566 | |
567 | obj->len = 0; |
568 | obj->cap = initialcap > 1 ? initialcap : 6; |
569 | |
570 | fz_try(ctx) |
571 | { |
572 | obj->items = fz_malloc_array(ctx, obj->cap, pdf_obj*); |
573 | } |
574 | fz_catch(ctx) |
575 | { |
576 | fz_free(ctx, obj); |
577 | fz_rethrow(ctx); |
578 | } |
579 | for (i = 0; i < obj->cap; i++) |
580 | obj->items[i] = NULL; |
581 | |
582 | return &obj->super; |
583 | } |
584 | |
585 | static void |
586 | pdf_array_grow(fz_context *ctx, pdf_obj_array *obj) |
587 | { |
588 | int i; |
589 | int new_cap = (obj->cap * 3) / 2; |
590 | |
591 | obj->items = fz_realloc_array(ctx, obj->items, new_cap, pdf_obj*); |
592 | obj->cap = new_cap; |
593 | |
594 | for (i = obj->len ; i < obj->cap; i++) |
595 | obj->items[i] = NULL; |
596 | } |
597 | |
598 | pdf_obj * |
599 | pdf_copy_array(fz_context *ctx, pdf_obj *obj) |
600 | { |
601 | pdf_document *doc; |
602 | pdf_obj *arr; |
603 | int i; |
604 | int n; |
605 | |
606 | RESOLVE(obj); |
607 | if (!OBJ_IS_ARRAY(obj)) |
608 | fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)" , pdf_objkindstr(obj)); |
609 | |
610 | doc = ARRAY(obj)->doc; |
611 | |
612 | n = pdf_array_len(ctx, obj); |
613 | arr = pdf_new_array(ctx, doc, n); |
614 | fz_try(ctx) |
615 | for (i = 0; i < n; i++) |
616 | pdf_array_push(ctx, arr, pdf_array_get(ctx, obj, i)); |
617 | fz_catch(ctx) |
618 | { |
619 | pdf_drop_obj(ctx, arr); |
620 | fz_rethrow(ctx); |
621 | } |
622 | |
623 | return arr; |
624 | } |
625 | |
626 | int |
627 | pdf_array_len(fz_context *ctx, pdf_obj *obj) |
628 | { |
629 | RESOLVE(obj); |
630 | if (!OBJ_IS_ARRAY(obj)) |
631 | return 0; |
632 | return ARRAY(obj)->len; |
633 | } |
634 | |
635 | pdf_obj * |
636 | pdf_array_get(fz_context *ctx, pdf_obj *obj, int i) |
637 | { |
638 | RESOLVE(obj); |
639 | if (!OBJ_IS_ARRAY(obj)) |
640 | return NULL; |
641 | if (i < 0 || i >= ARRAY(obj)->len) |
642 | return NULL; |
643 | return ARRAY(obj)->items[i]; |
644 | } |
645 | |
646 | static void prepare_object_for_alteration(fz_context *ctx, pdf_obj *obj, pdf_obj *val) |
647 | { |
648 | pdf_document *doc, *val_doc; |
649 | int parent; |
650 | |
651 | /* |
652 | obj should be a dict or an array. We don't care about |
653 | any other types, as they aren't 'containers'. |
654 | */ |
655 | if (obj < PDF_LIMIT) |
656 | return; |
657 | |
658 | switch (obj->kind) |
659 | { |
660 | case PDF_DICT: |
661 | doc = DICT(obj)->doc; |
662 | parent = DICT(obj)->parent_num; |
663 | break; |
664 | case PDF_ARRAY: |
665 | doc = ARRAY(obj)->doc; |
666 | parent = ARRAY(obj)->parent_num; |
667 | break; |
668 | default: |
669 | return; |
670 | } |
671 | |
672 | if (val) |
673 | { |
674 | val_doc = pdf_get_bound_document(ctx, val); |
675 | if (doc && val_doc && val_doc != doc) |
676 | fz_throw(ctx, FZ_ERROR_GENERIC, "container and item belong to different documents" ); |
677 | } |
678 | |
679 | /* |
680 | parent_num = 0 while an object is being parsed from the file. |
681 | No further action is necessary. |
682 | */ |
683 | if (parent == 0 || doc->freeze_updates) |
684 | return; |
685 | |
686 | /* |
687 | Otherwise we need to ensure that the containing hierarchy of objects |
688 | has been moved to the incremental xref section and the newly linked |
689 | object needs to record the parent_num |
690 | */ |
691 | pdf_xref_ensure_incremental_object(ctx, doc, parent); |
692 | pdf_set_obj_parent(ctx, val, parent); |
693 | } |
694 | |
695 | void |
696 | pdf_array_put(fz_context *ctx, pdf_obj *obj, int i, pdf_obj *item) |
697 | { |
698 | RESOLVE(obj); |
699 | if (!OBJ_IS_ARRAY(obj)) |
700 | fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)" , pdf_objkindstr(obj)); |
701 | if (i == ARRAY(obj)->len) |
702 | { |
703 | pdf_array_push(ctx, obj, item); |
704 | return; |
705 | } |
706 | if (i < 0 || i > ARRAY(obj)->len) |
707 | fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds" ); |
708 | prepare_object_for_alteration(ctx, obj, item); |
709 | pdf_drop_obj(ctx, ARRAY(obj)->items[i]); |
710 | ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); |
711 | } |
712 | |
713 | void |
714 | pdf_array_put_drop(fz_context *ctx, pdf_obj *obj, int i, pdf_obj *item) |
715 | { |
716 | fz_try(ctx) |
717 | pdf_array_put(ctx, obj, i, item); |
718 | fz_always(ctx) |
719 | pdf_drop_obj(ctx, item); |
720 | fz_catch(ctx) |
721 | fz_rethrow(ctx); |
722 | } |
723 | |
724 | void |
725 | pdf_array_push(fz_context *ctx, pdf_obj *obj, pdf_obj *item) |
726 | { |
727 | RESOLVE(obj); |
728 | if (!OBJ_IS_ARRAY(obj)) |
729 | fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)" , pdf_objkindstr(obj)); |
730 | prepare_object_for_alteration(ctx, obj, item); |
731 | if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) |
732 | pdf_array_grow(ctx, ARRAY(obj)); |
733 | ARRAY(obj)->items[ARRAY(obj)->len] = pdf_keep_obj(ctx, item); |
734 | ARRAY(obj)->len++; |
735 | } |
736 | |
737 | void |
738 | pdf_array_push_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *item) |
739 | { |
740 | fz_try(ctx) |
741 | pdf_array_push(ctx, obj, item); |
742 | fz_always(ctx) |
743 | pdf_drop_obj(ctx, item); |
744 | fz_catch(ctx) |
745 | fz_rethrow(ctx); |
746 | } |
747 | |
748 | void |
749 | pdf_array_insert(fz_context *ctx, pdf_obj *obj, pdf_obj *item, int i) |
750 | { |
751 | RESOLVE(obj); |
752 | if (!OBJ_IS_ARRAY(obj)) |
753 | fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)" , pdf_objkindstr(obj)); |
754 | if (i < 0 || i > ARRAY(obj)->len) |
755 | fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds" ); |
756 | prepare_object_for_alteration(ctx, obj, item); |
757 | if (ARRAY(obj)->len + 1 > ARRAY(obj)->cap) |
758 | pdf_array_grow(ctx, ARRAY(obj)); |
759 | memmove(ARRAY(obj)->items + i + 1, ARRAY(obj)->items + i, (ARRAY(obj)->len - i) * sizeof(pdf_obj*)); |
760 | ARRAY(obj)->items[i] = pdf_keep_obj(ctx, item); |
761 | ARRAY(obj)->len++; |
762 | } |
763 | |
764 | void |
765 | pdf_array_insert_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *item, int i) |
766 | { |
767 | fz_try(ctx) |
768 | pdf_array_insert(ctx, obj, item, i); |
769 | fz_always(ctx) |
770 | pdf_drop_obj(ctx, item); |
771 | fz_catch(ctx) |
772 | fz_rethrow(ctx); |
773 | } |
774 | |
775 | void |
776 | pdf_array_delete(fz_context *ctx, pdf_obj *obj, int i) |
777 | { |
778 | RESOLVE(obj); |
779 | if (!OBJ_IS_ARRAY(obj)) |
780 | fz_throw(ctx, FZ_ERROR_GENERIC, "not an array (%s)" , pdf_objkindstr(obj)); |
781 | if (i < 0 || i >= ARRAY(obj)->len) |
782 | fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds" ); |
783 | prepare_object_for_alteration(ctx, obj, NULL); |
784 | pdf_drop_obj(ctx, ARRAY(obj)->items[i]); |
785 | ARRAY(obj)->items[i] = 0; |
786 | ARRAY(obj)->len--; |
787 | memmove(ARRAY(obj)->items + i, ARRAY(obj)->items + i + 1, (ARRAY(obj)->len - i) * sizeof(pdf_obj*)); |
788 | } |
789 | |
790 | int |
791 | pdf_array_contains(fz_context *ctx, pdf_obj *arr, pdf_obj *obj) |
792 | { |
793 | int i, len; |
794 | |
795 | len = pdf_array_len(ctx, arr); |
796 | for (i = 0; i < len; i++) |
797 | if (!pdf_objcmp(ctx, pdf_array_get(ctx, arr, i), obj)) |
798 | return 1; |
799 | |
800 | return 0; |
801 | } |
802 | |
803 | int |
804 | pdf_array_find(fz_context *ctx, pdf_obj *arr, pdf_obj *obj) |
805 | { |
806 | int i, len; |
807 | |
808 | len = pdf_array_len(ctx, arr); |
809 | for (i = 0; i < len; i++) |
810 | if (!pdf_objcmp(ctx, pdf_array_get(ctx, arr, i), obj)) |
811 | return i; |
812 | |
813 | return -1; |
814 | } |
815 | |
816 | pdf_obj *pdf_new_rect(fz_context *ctx, pdf_document *doc, fz_rect rect) |
817 | { |
818 | pdf_obj *arr = pdf_new_array(ctx, doc, 4); |
819 | fz_try(ctx) |
820 | { |
821 | pdf_array_push_real(ctx, arr, rect.x0); |
822 | pdf_array_push_real(ctx, arr, rect.y0); |
823 | pdf_array_push_real(ctx, arr, rect.x1); |
824 | pdf_array_push_real(ctx, arr, rect.y1); |
825 | } |
826 | fz_catch(ctx) |
827 | { |
828 | pdf_drop_obj(ctx, arr); |
829 | fz_rethrow(ctx); |
830 | } |
831 | return arr; |
832 | } |
833 | |
834 | pdf_obj *pdf_new_matrix(fz_context *ctx, pdf_document *doc, fz_matrix mtx) |
835 | { |
836 | pdf_obj *arr = pdf_new_array(ctx, doc, 6); |
837 | fz_try(ctx) |
838 | { |
839 | pdf_array_push_real(ctx, arr, mtx.a); |
840 | pdf_array_push_real(ctx, arr, mtx.b); |
841 | pdf_array_push_real(ctx, arr, mtx.c); |
842 | pdf_array_push_real(ctx, arr, mtx.d); |
843 | pdf_array_push_real(ctx, arr, mtx.e); |
844 | pdf_array_push_real(ctx, arr, mtx.f); |
845 | } |
846 | fz_catch(ctx) |
847 | { |
848 | pdf_drop_obj(ctx, arr); |
849 | fz_rethrow(ctx); |
850 | } |
851 | return arr; |
852 | } |
853 | |
854 | /* dicts may only have names as keys! */ |
855 | |
856 | static int keyvalcmp(const void *ap, const void *bp) |
857 | { |
858 | const struct keyval *a = ap; |
859 | const struct keyval *b = bp; |
860 | const char *an; |
861 | const char *bn; |
862 | |
863 | /* We should never get a->k == NULL or b->k == NULL. If we |
864 | * do, then they match. */ |
865 | if (a->k < PDF_LIMIT) |
866 | an = PDF_NAME_LIST[(intptr_t)a->k]; |
867 | else if (a->k >= PDF_LIMIT && a->k->kind == PDF_NAME) |
868 | an = NAME(a->k)->n; |
869 | else |
870 | return 0; |
871 | |
872 | if (b->k < PDF_LIMIT) |
873 | bn = PDF_NAME_LIST[(intptr_t)b->k]; |
874 | else if (b->k >= PDF_LIMIT && b->k->kind == PDF_NAME) |
875 | bn = NAME(b->k)->n; |
876 | else |
877 | return 0; |
878 | |
879 | return strcmp(an, bn); |
880 | } |
881 | |
882 | pdf_obj * |
883 | pdf_new_dict(fz_context *ctx, pdf_document *doc, int initialcap) |
884 | { |
885 | pdf_obj_dict *obj; |
886 | int i; |
887 | |
888 | obj = Memento_label(fz_malloc(ctx, sizeof(pdf_obj_dict)), "pdf_obj(dict)" ); |
889 | obj->super.refs = 1; |
890 | obj->super.kind = PDF_DICT; |
891 | obj->super.flags = 0; |
892 | obj->doc = doc; |
893 | obj->parent_num = 0; |
894 | |
895 | obj->len = 0; |
896 | obj->cap = initialcap > 1 ? initialcap : 10; |
897 | |
898 | fz_try(ctx) |
899 | { |
900 | DICT(obj)->items = fz_malloc_array(ctx, DICT(obj)->cap, struct keyval); |
901 | } |
902 | fz_catch(ctx) |
903 | { |
904 | fz_free(ctx, obj); |
905 | fz_rethrow(ctx); |
906 | } |
907 | for (i = 0; i < DICT(obj)->cap; i++) |
908 | { |
909 | DICT(obj)->items[i].k = NULL; |
910 | DICT(obj)->items[i].v = NULL; |
911 | } |
912 | |
913 | return &obj->super; |
914 | } |
915 | |
916 | static void |
917 | pdf_dict_grow(fz_context *ctx, pdf_obj *obj) |
918 | { |
919 | int i; |
920 | int new_cap = (DICT(obj)->cap * 3) / 2; |
921 | |
922 | DICT(obj)->items = fz_realloc_array(ctx, DICT(obj)->items, new_cap, struct keyval); |
923 | DICT(obj)->cap = new_cap; |
924 | |
925 | for (i = DICT(obj)->len; i < DICT(obj)->cap; i++) |
926 | { |
927 | DICT(obj)->items[i].k = NULL; |
928 | DICT(obj)->items[i].v = NULL; |
929 | } |
930 | } |
931 | |
932 | pdf_obj * |
933 | pdf_copy_dict(fz_context *ctx, pdf_obj *obj) |
934 | { |
935 | pdf_document *doc; |
936 | pdf_obj *dict; |
937 | int i, n; |
938 | |
939 | RESOLVE(obj); |
940 | if (!OBJ_IS_DICT(obj)) |
941 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
942 | |
943 | doc = DICT(obj)->doc; |
944 | n = pdf_dict_len(ctx, obj); |
945 | dict = pdf_new_dict(ctx, doc, n); |
946 | fz_try(ctx) |
947 | for (i = 0; i < n; i++) |
948 | pdf_dict_put(ctx, dict, pdf_dict_get_key(ctx, obj, i), pdf_dict_get_val(ctx, obj, i)); |
949 | fz_catch(ctx) |
950 | { |
951 | pdf_drop_obj(ctx, dict); |
952 | fz_rethrow(ctx); |
953 | } |
954 | |
955 | return dict; |
956 | } |
957 | |
958 | int |
959 | pdf_dict_len(fz_context *ctx, pdf_obj *obj) |
960 | { |
961 | RESOLVE(obj); |
962 | if (!OBJ_IS_DICT(obj)) |
963 | return 0; |
964 | return DICT(obj)->len; |
965 | } |
966 | |
967 | pdf_obj * |
968 | pdf_dict_get_key(fz_context *ctx, pdf_obj *obj, int i) |
969 | { |
970 | RESOLVE(obj); |
971 | if (!OBJ_IS_DICT(obj)) |
972 | return NULL; |
973 | if (i < 0 || i >= DICT(obj)->len) |
974 | return NULL; |
975 | return DICT(obj)->items[i].k; |
976 | } |
977 | |
978 | pdf_obj * |
979 | pdf_dict_get_val(fz_context *ctx, pdf_obj *obj, int i) |
980 | { |
981 | RESOLVE(obj); |
982 | if (!OBJ_IS_DICT(obj)) |
983 | return NULL; |
984 | if (i < 0 || i >= DICT(obj)->len) |
985 | return NULL; |
986 | return DICT(obj)->items[i].v; |
987 | } |
988 | |
989 | void |
990 | pdf_dict_put_val_null(fz_context *ctx, pdf_obj *obj, int idx) |
991 | { |
992 | RESOLVE(obj); |
993 | if (!OBJ_IS_DICT(obj)) |
994 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
995 | if (idx < 0 || idx >= DICT(obj)->len) |
996 | fz_throw(ctx, FZ_ERROR_GENERIC, "index out of bounds" ); |
997 | |
998 | prepare_object_for_alteration(ctx, obj, NULL); |
999 | pdf_drop_obj(ctx, DICT(obj)->items[idx].v); |
1000 | DICT(obj)->items[idx].v = PDF_NULL; |
1001 | } |
1002 | |
1003 | /* Returns 0 <= i < len for key found. Returns -1-len < i <= -1 for key |
1004 | * not found, but with insertion point -1-i. */ |
1005 | static int |
1006 | pdf_dict_finds(fz_context *ctx, pdf_obj *obj, const char *key) |
1007 | { |
1008 | int len = DICT(obj)->len; |
1009 | if ((obj->flags & PDF_FLAGS_SORTED) && len > 0) |
1010 | { |
1011 | int l = 0; |
1012 | int r = len - 1; |
1013 | |
1014 | if (strcmp(pdf_to_name(ctx, DICT(obj)->items[r].k), key) < 0) |
1015 | { |
1016 | return -1 - (r+1); |
1017 | } |
1018 | |
1019 | while (l <= r) |
1020 | { |
1021 | int m = (l + r) >> 1; |
1022 | int c = -strcmp(pdf_to_name(ctx, DICT(obj)->items[m].k), key); |
1023 | if (c < 0) |
1024 | r = m - 1; |
1025 | else if (c > 0) |
1026 | l = m + 1; |
1027 | else |
1028 | return m; |
1029 | } |
1030 | return -1 - l; |
1031 | } |
1032 | |
1033 | else |
1034 | { |
1035 | int i; |
1036 | for (i = 0; i < len; i++) |
1037 | if (strcmp(pdf_to_name(ctx, DICT(obj)->items[i].k), key) == 0) |
1038 | return i; |
1039 | |
1040 | return -1 - len; |
1041 | } |
1042 | } |
1043 | |
1044 | static int |
1045 | pdf_dict_find(fz_context *ctx, pdf_obj *obj, pdf_obj *key) |
1046 | { |
1047 | int len = DICT(obj)->len; |
1048 | if ((obj->flags & PDF_FLAGS_SORTED) && len > 0) |
1049 | { |
1050 | int l = 0; |
1051 | int r = len - 1; |
1052 | pdf_obj *k = DICT(obj)->items[r].k; |
1053 | |
1054 | if (k == key || (k >= PDF_LIMIT && strcmp(NAME(k)->n, PDF_NAME_LIST[(intptr_t)key]) < 0)) |
1055 | { |
1056 | return -1 - (r+1); |
1057 | } |
1058 | |
1059 | while (l <= r) |
1060 | { |
1061 | int m = (l + r) >> 1; |
1062 | int c; |
1063 | |
1064 | k = DICT(obj)->items[m].k; |
1065 | c = (k < PDF_LIMIT ? (char *)key-(char *)k : -strcmp(NAME(k)->n, PDF_NAME_LIST[(intptr_t)key])); |
1066 | if (c < 0) |
1067 | r = m - 1; |
1068 | else if (c > 0) |
1069 | l = m + 1; |
1070 | else |
1071 | return m; |
1072 | } |
1073 | return -1 - l; |
1074 | } |
1075 | else |
1076 | { |
1077 | int i; |
1078 | for (i = 0; i < len; i++) |
1079 | { |
1080 | pdf_obj *k = DICT(obj)->items[i].k; |
1081 | if (k < PDF_LIMIT) |
1082 | { |
1083 | if (k == key) |
1084 | return i; |
1085 | } |
1086 | else |
1087 | { |
1088 | if (!strcmp(PDF_NAME_LIST[(intptr_t)key], NAME(k)->n)) |
1089 | return i; |
1090 | } |
1091 | } |
1092 | |
1093 | return -1 - len; |
1094 | } |
1095 | } |
1096 | |
1097 | pdf_obj * |
1098 | pdf_dict_gets(fz_context *ctx, pdf_obj *obj, const char *key) |
1099 | { |
1100 | int i; |
1101 | |
1102 | RESOLVE(obj); |
1103 | if (!OBJ_IS_DICT(obj)) |
1104 | return NULL; |
1105 | if (!key) |
1106 | return NULL; |
1107 | |
1108 | i = pdf_dict_finds(ctx, obj, key); |
1109 | if (i >= 0) |
1110 | return DICT(obj)->items[i].v; |
1111 | return NULL; |
1112 | } |
1113 | |
1114 | pdf_obj * |
1115 | pdf_dict_getp(fz_context *ctx, pdf_obj *obj, const char *keys) |
1116 | { |
1117 | char buf[256]; |
1118 | char *k, *e; |
1119 | |
1120 | RESOLVE(obj); |
1121 | if (!OBJ_IS_DICT(obj)) |
1122 | return NULL; |
1123 | if (strlen(keys)+1 > 256) |
1124 | fz_throw(ctx, FZ_ERROR_GENERIC, "path too long" ); |
1125 | |
1126 | strcpy(buf, keys); |
1127 | |
1128 | e = buf; |
1129 | while (*e && obj) |
1130 | { |
1131 | k = e; |
1132 | while (*e != '/' && *e != '\0') |
1133 | e++; |
1134 | |
1135 | if (*e == '/') |
1136 | { |
1137 | *e = '\0'; |
1138 | e++; |
1139 | } |
1140 | |
1141 | obj = pdf_dict_gets(ctx, obj, k); |
1142 | } |
1143 | |
1144 | return obj; |
1145 | } |
1146 | |
1147 | pdf_obj * |
1148 | pdf_dict_getl(fz_context *ctx, pdf_obj *obj, ...) |
1149 | { |
1150 | va_list keys; |
1151 | pdf_obj *key; |
1152 | |
1153 | va_start(keys, obj); |
1154 | |
1155 | while (obj != NULL && (key = va_arg(keys, pdf_obj *)) != NULL) |
1156 | { |
1157 | obj = pdf_dict_get(ctx, obj, key); |
1158 | } |
1159 | |
1160 | va_end(keys); |
1161 | return obj; |
1162 | } |
1163 | |
1164 | pdf_obj * |
1165 | pdf_dict_get(fz_context *ctx, pdf_obj *obj, pdf_obj *key) |
1166 | { |
1167 | int i; |
1168 | |
1169 | RESOLVE(obj); |
1170 | if (!OBJ_IS_DICT(obj)) |
1171 | return NULL; |
1172 | if (!OBJ_IS_NAME(key)) |
1173 | return NULL; |
1174 | |
1175 | if (key < PDF_LIMIT) |
1176 | i = pdf_dict_find(ctx, obj, key); |
1177 | else |
1178 | i = pdf_dict_finds(ctx, obj, pdf_to_name(ctx, key)); |
1179 | if (i >= 0) |
1180 | return DICT(obj)->items[i].v; |
1181 | return NULL; |
1182 | } |
1183 | |
1184 | pdf_obj * |
1185 | pdf_dict_getsa(fz_context *ctx, pdf_obj *obj, const char *key, const char *abbrev) |
1186 | { |
1187 | pdf_obj *v; |
1188 | v = pdf_dict_gets(ctx, obj, key); |
1189 | if (v) |
1190 | return v; |
1191 | return pdf_dict_gets(ctx, obj, abbrev); |
1192 | } |
1193 | |
1194 | pdf_obj * |
1195 | pdf_dict_geta(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *abbrev) |
1196 | { |
1197 | pdf_obj *v; |
1198 | v = pdf_dict_get(ctx, obj, key); |
1199 | if (v) |
1200 | return v; |
1201 | return pdf_dict_get(ctx, obj, abbrev); |
1202 | } |
1203 | |
1204 | static void |
1205 | pdf_dict_get_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val, pdf_obj **old_val) |
1206 | { |
1207 | int i; |
1208 | |
1209 | if (old_val) |
1210 | *old_val = NULL; |
1211 | |
1212 | RESOLVE(obj); |
1213 | if (!OBJ_IS_DICT(obj)) |
1214 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1215 | if (!OBJ_IS_NAME(key)) |
1216 | fz_throw(ctx, FZ_ERROR_GENERIC, "key is not a name (%s)" , pdf_objkindstr(obj)); |
1217 | |
1218 | if (DICT(obj)->len > 100 && !(obj->flags & PDF_FLAGS_SORTED)) |
1219 | pdf_sort_dict(ctx, obj); |
1220 | |
1221 | if (key < PDF_LIMIT) |
1222 | i = pdf_dict_find(ctx, obj, key); |
1223 | else |
1224 | i = pdf_dict_finds(ctx, obj, pdf_to_name(ctx, key)); |
1225 | |
1226 | prepare_object_for_alteration(ctx, obj, val); |
1227 | |
1228 | if (i >= 0 && i < DICT(obj)->len) |
1229 | { |
1230 | if (DICT(obj)->items[i].v != val) |
1231 | { |
1232 | pdf_obj *d = DICT(obj)->items[i].v; |
1233 | DICT(obj)->items[i].v = pdf_keep_obj(ctx, val); |
1234 | if (old_val) |
1235 | *old_val = d; |
1236 | else |
1237 | pdf_drop_obj(ctx, d); |
1238 | } |
1239 | } |
1240 | else |
1241 | { |
1242 | if (DICT(obj)->len + 1 > DICT(obj)->cap) |
1243 | pdf_dict_grow(ctx, obj); |
1244 | |
1245 | i = -1-i; |
1246 | if ((obj->flags & PDF_FLAGS_SORTED) && DICT(obj)->len > 0) |
1247 | memmove(&DICT(obj)->items[i + 1], |
1248 | &DICT(obj)->items[i], |
1249 | (DICT(obj)->len - i) * sizeof(struct keyval)); |
1250 | |
1251 | DICT(obj)->items[i].k = pdf_keep_obj(ctx, key); |
1252 | DICT(obj)->items[i].v = pdf_keep_obj(ctx, val); |
1253 | DICT(obj)->len ++; |
1254 | } |
1255 | } |
1256 | |
1257 | void |
1258 | pdf_dict_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) |
1259 | { |
1260 | pdf_dict_get_put(ctx, obj, key, val, NULL); |
1261 | } |
1262 | |
1263 | void |
1264 | pdf_dict_put_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) |
1265 | { |
1266 | fz_try(ctx) |
1267 | pdf_dict_get_put(ctx, obj, key, val, NULL); |
1268 | fz_always(ctx) |
1269 | pdf_drop_obj(ctx, val); |
1270 | fz_catch(ctx) |
1271 | fz_rethrow(ctx); |
1272 | } |
1273 | |
1274 | void |
1275 | pdf_dict_get_put_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val, pdf_obj **old_val) |
1276 | { |
1277 | fz_try(ctx) |
1278 | pdf_dict_get_put(ctx, obj, key, val, old_val); |
1279 | fz_always(ctx) |
1280 | pdf_drop_obj(ctx, val); |
1281 | fz_catch(ctx) |
1282 | fz_rethrow(ctx); |
1283 | } |
1284 | |
1285 | void |
1286 | pdf_dict_puts(fz_context *ctx, pdf_obj *obj, const char *key, pdf_obj *val) |
1287 | { |
1288 | pdf_obj *keyobj; |
1289 | |
1290 | RESOLVE(obj); |
1291 | if (!OBJ_IS_DICT(obj)) |
1292 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1293 | |
1294 | keyobj = pdf_new_name(ctx, key); |
1295 | |
1296 | fz_try(ctx) |
1297 | pdf_dict_put(ctx, obj, keyobj, val); |
1298 | fz_always(ctx) |
1299 | pdf_drop_obj(ctx, keyobj); |
1300 | fz_catch(ctx) |
1301 | fz_rethrow(ctx); |
1302 | } |
1303 | |
1304 | void |
1305 | pdf_dict_puts_drop(fz_context *ctx, pdf_obj *obj, const char *key, pdf_obj *val) |
1306 | { |
1307 | pdf_obj *keyobj; |
1308 | |
1309 | RESOLVE(obj); |
1310 | if (!OBJ_IS_DICT(obj)) |
1311 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1312 | |
1313 | keyobj = pdf_new_name(ctx, key); |
1314 | |
1315 | fz_var(keyobj); |
1316 | |
1317 | fz_try(ctx) |
1318 | pdf_dict_put(ctx, obj, keyobj, val); |
1319 | fz_always(ctx) |
1320 | { |
1321 | pdf_drop_obj(ctx, keyobj); |
1322 | pdf_drop_obj(ctx, val); |
1323 | } |
1324 | fz_catch(ctx) |
1325 | { |
1326 | fz_rethrow(ctx); |
1327 | } |
1328 | } |
1329 | |
1330 | void |
1331 | pdf_dict_putp(fz_context *ctx, pdf_obj *obj, const char *keys, pdf_obj *val) |
1332 | { |
1333 | pdf_document *doc; |
1334 | char buf[256]; |
1335 | char *k, *e; |
1336 | pdf_obj *cobj = NULL; |
1337 | |
1338 | RESOLVE(obj); |
1339 | if (!OBJ_IS_DICT(obj)) |
1340 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1341 | if (strlen(keys)+1 > 256) |
1342 | fz_throw(ctx, FZ_ERROR_GENERIC, "buffer overflow in pdf_dict_putp" ); |
1343 | |
1344 | doc = DICT(obj)->doc; |
1345 | strcpy(buf, keys); |
1346 | |
1347 | e = buf; |
1348 | while (*e) |
1349 | { |
1350 | k = e; |
1351 | while (*e != '/' && *e != '\0') |
1352 | e++; |
1353 | |
1354 | if (*e == '/') |
1355 | { |
1356 | *e = '\0'; |
1357 | e++; |
1358 | } |
1359 | |
1360 | if (*e) |
1361 | { |
1362 | /* Not the last key in the key path. Create subdict if not already there. */ |
1363 | cobj = pdf_dict_gets(ctx, obj, k); |
1364 | if (cobj == NULL) |
1365 | { |
1366 | cobj = pdf_new_dict(ctx, doc, 1); |
1367 | fz_try(ctx) |
1368 | pdf_dict_puts(ctx, obj, k, cobj); |
1369 | fz_always(ctx) |
1370 | pdf_drop_obj(ctx, cobj); |
1371 | fz_catch(ctx) |
1372 | fz_rethrow(ctx); |
1373 | } |
1374 | /* Move to subdict */ |
1375 | obj = cobj; |
1376 | } |
1377 | else |
1378 | { |
1379 | /* Last key. Use it to store the value */ |
1380 | /* Use val = NULL to request delete */ |
1381 | if (val) |
1382 | pdf_dict_puts(ctx, obj, k, val); |
1383 | else |
1384 | pdf_dict_dels(ctx, obj, k); |
1385 | } |
1386 | } |
1387 | } |
1388 | |
1389 | void |
1390 | pdf_dict_putp_drop(fz_context *ctx, pdf_obj *obj, const char *keys, pdf_obj *val) |
1391 | { |
1392 | fz_try(ctx) |
1393 | pdf_dict_putp(ctx, obj, keys, val); |
1394 | fz_always(ctx) |
1395 | pdf_drop_obj(ctx, val); |
1396 | fz_catch(ctx) |
1397 | fz_rethrow(ctx); |
1398 | } |
1399 | |
1400 | static void |
1401 | pdf_dict_vputl(fz_context *ctx, pdf_obj *obj, pdf_obj *val, va_list keys) |
1402 | { |
1403 | pdf_obj *key; |
1404 | pdf_obj *next_key; |
1405 | pdf_obj *next_obj; |
1406 | pdf_document *doc; |
1407 | |
1408 | RESOLVE(obj); |
1409 | if (!OBJ_IS_DICT(obj)) |
1410 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1411 | |
1412 | doc = DICT(obj)->doc; |
1413 | |
1414 | key = va_arg(keys, pdf_obj *); |
1415 | if (key == NULL) |
1416 | return; |
1417 | |
1418 | while ((next_key = va_arg(keys, pdf_obj *)) != NULL) |
1419 | { |
1420 | next_obj = pdf_dict_get(ctx, obj, key); |
1421 | if (next_obj == NULL) |
1422 | goto new_obj; |
1423 | obj = next_obj; |
1424 | key = next_key; |
1425 | } |
1426 | |
1427 | pdf_dict_put(ctx, obj, key, val); |
1428 | return; |
1429 | |
1430 | new_obj: |
1431 | /* We have to create entries */ |
1432 | do |
1433 | { |
1434 | next_obj = pdf_new_dict(ctx, doc, 1); |
1435 | pdf_dict_put_drop(ctx, obj, key, next_obj); |
1436 | obj = next_obj; |
1437 | key = next_key; |
1438 | } |
1439 | while ((next_key = va_arg(keys, pdf_obj *)) != NULL); |
1440 | |
1441 | pdf_dict_put(ctx, obj, key, val); |
1442 | return; |
1443 | } |
1444 | |
1445 | void |
1446 | pdf_dict_putl(fz_context *ctx, pdf_obj *obj, pdf_obj *val, ...) |
1447 | { |
1448 | va_list keys; |
1449 | va_start(keys, val); |
1450 | |
1451 | fz_try(ctx) |
1452 | pdf_dict_vputl(ctx, obj, val, keys); |
1453 | fz_always(ctx) |
1454 | va_end(keys); |
1455 | fz_catch(ctx) |
1456 | fz_rethrow(ctx); |
1457 | } |
1458 | |
1459 | void |
1460 | pdf_dict_putl_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *val, ...) |
1461 | { |
1462 | va_list keys; |
1463 | va_start(keys, val); |
1464 | |
1465 | fz_try(ctx) |
1466 | pdf_dict_vputl(ctx, obj, val, keys); |
1467 | fz_always(ctx) |
1468 | { |
1469 | pdf_drop_obj(ctx, val); |
1470 | va_end(keys); |
1471 | } |
1472 | fz_catch(ctx) |
1473 | fz_rethrow(ctx); |
1474 | } |
1475 | |
1476 | void |
1477 | pdf_dict_dels(fz_context *ctx, pdf_obj *obj, const char *key) |
1478 | { |
1479 | int i; |
1480 | |
1481 | RESOLVE(obj); |
1482 | if (!OBJ_IS_DICT(obj)) |
1483 | fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)" , pdf_objkindstr(obj)); |
1484 | if (!key) |
1485 | fz_throw(ctx, FZ_ERROR_GENERIC, "key is null" ); |
1486 | |
1487 | prepare_object_for_alteration(ctx, obj, NULL); |
1488 | i = pdf_dict_finds(ctx, obj, key); |
1489 | if (i >= 0) |
1490 | { |
1491 | pdf_drop_obj(ctx, DICT(obj)->items[i].k); |
1492 | pdf_drop_obj(ctx, DICT(obj)->items[i].v); |
1493 | obj->flags &= ~PDF_FLAGS_SORTED; |
1494 | DICT(obj)->items[i] = DICT(obj)->items[DICT(obj)->len-1]; |
1495 | DICT(obj)->len --; |
1496 | } |
1497 | } |
1498 | |
1499 | void |
1500 | pdf_dict_del(fz_context *ctx, pdf_obj *obj, pdf_obj *key) |
1501 | { |
1502 | if (!OBJ_IS_NAME(key)) |
1503 | fz_throw(ctx, FZ_ERROR_GENERIC, "key is not a name (%s)" , pdf_objkindstr(key)); |
1504 | |
1505 | if (key < PDF_LIMIT) |
1506 | pdf_dict_dels(ctx, obj, PDF_NAME_LIST[(intptr_t)key]); |
1507 | else |
1508 | pdf_dict_dels(ctx, obj, NAME(key)->n); |
1509 | } |
1510 | |
1511 | void |
1512 | pdf_sort_dict(fz_context *ctx, pdf_obj *obj) |
1513 | { |
1514 | RESOLVE(obj); |
1515 | if (!OBJ_IS_DICT(obj)) |
1516 | return; |
1517 | if (!(obj->flags & PDF_FLAGS_SORTED)) |
1518 | { |
1519 | qsort(DICT(obj)->items, DICT(obj)->len, sizeof(struct keyval), keyvalcmp); |
1520 | obj->flags |= PDF_FLAGS_SORTED; |
1521 | } |
1522 | } |
1523 | |
1524 | pdf_obj * |
1525 | pdf_deep_copy_obj(fz_context *ctx, pdf_obj *obj) |
1526 | { |
1527 | if (obj < PDF_LIMIT) |
1528 | { |
1529 | return obj; |
1530 | } |
1531 | if (obj->kind == PDF_DICT) |
1532 | { |
1533 | pdf_document *doc = DICT(obj)->doc; |
1534 | int n = pdf_dict_len(ctx, obj); |
1535 | pdf_obj *dict = pdf_new_dict(ctx, doc, n); |
1536 | int i; |
1537 | |
1538 | fz_try(ctx) |
1539 | for (i = 0; i < n; i++) |
1540 | { |
1541 | pdf_obj *obj_copy = pdf_deep_copy_obj(ctx, pdf_dict_get_val(ctx, obj, i)); |
1542 | pdf_dict_put_drop(ctx, dict, pdf_dict_get_key(ctx, obj, i), obj_copy); |
1543 | } |
1544 | fz_catch(ctx) |
1545 | { |
1546 | pdf_drop_obj(ctx, dict); |
1547 | fz_rethrow(ctx); |
1548 | } |
1549 | |
1550 | return dict; |
1551 | } |
1552 | else if (obj->kind == PDF_ARRAY) |
1553 | { |
1554 | pdf_document *doc = ARRAY(obj)->doc; |
1555 | int n = pdf_array_len(ctx, obj); |
1556 | pdf_obj *arr = pdf_new_array(ctx, doc, n); |
1557 | int i; |
1558 | |
1559 | fz_try(ctx) |
1560 | for (i = 0; i < n; i++) |
1561 | { |
1562 | pdf_obj *obj_copy = pdf_deep_copy_obj(ctx, pdf_array_get(ctx, obj, i)); |
1563 | pdf_array_push_drop(ctx, arr, obj_copy); |
1564 | } |
1565 | fz_catch(ctx) |
1566 | { |
1567 | pdf_drop_obj(ctx, arr); |
1568 | fz_rethrow(ctx); |
1569 | } |
1570 | |
1571 | return arr; |
1572 | } |
1573 | else |
1574 | { |
1575 | return pdf_keep_obj(ctx, obj); |
1576 | } |
1577 | } |
1578 | |
1579 | /* obj marking and unmarking functions - to avoid infinite recursions. */ |
1580 | int |
1581 | pdf_obj_marked(fz_context *ctx, pdf_obj *obj) |
1582 | { |
1583 | RESOLVE(obj); |
1584 | if (obj < PDF_LIMIT) |
1585 | return 0; |
1586 | return !!(obj->flags & PDF_FLAGS_MARKED); |
1587 | } |
1588 | |
1589 | int |
1590 | pdf_mark_obj(fz_context *ctx, pdf_obj *obj) |
1591 | { |
1592 | int marked; |
1593 | RESOLVE(obj); |
1594 | if (obj < PDF_LIMIT) |
1595 | return 0; |
1596 | marked = !!(obj->flags & PDF_FLAGS_MARKED); |
1597 | obj->flags |= PDF_FLAGS_MARKED; |
1598 | return marked; |
1599 | } |
1600 | |
1601 | void |
1602 | pdf_unmark_obj(fz_context *ctx, pdf_obj *obj) |
1603 | { |
1604 | RESOLVE(obj); |
1605 | if (obj < PDF_LIMIT) |
1606 | return; |
1607 | obj->flags &= ~PDF_FLAGS_MARKED; |
1608 | } |
1609 | |
1610 | void |
1611 | pdf_set_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int memo) |
1612 | { |
1613 | if (obj < PDF_LIMIT) |
1614 | return; |
1615 | bit <<= 1; |
1616 | obj->flags |= PDF_FLAGS_MEMO_BASE << bit; |
1617 | if (memo) |
1618 | obj->flags |= PDF_FLAGS_MEMO_BASE_BOOL << bit; |
1619 | else |
1620 | obj->flags &= ~(PDF_FLAGS_MEMO_BASE_BOOL << bit); |
1621 | } |
1622 | |
1623 | int |
1624 | pdf_obj_memo(fz_context *ctx, pdf_obj *obj, int bit, int *memo) |
1625 | { |
1626 | if (obj < PDF_LIMIT) |
1627 | return 0; |
1628 | bit <<= 1; |
1629 | if (!(obj->flags & (PDF_FLAGS_MEMO_BASE<<bit))) |
1630 | return 0; |
1631 | *memo = !!(obj->flags & (PDF_FLAGS_MEMO_BASE_BOOL<<bit)); |
1632 | return 1; |
1633 | } |
1634 | |
1635 | /* obj dirty bit support. */ |
1636 | int pdf_obj_is_dirty(fz_context *ctx, pdf_obj *obj) |
1637 | { |
1638 | RESOLVE(obj); |
1639 | if (obj < PDF_LIMIT) |
1640 | return 0; |
1641 | return !!(obj->flags & PDF_FLAGS_DIRTY); |
1642 | } |
1643 | |
1644 | void pdf_dirty_obj(fz_context *ctx, pdf_obj *obj) |
1645 | { |
1646 | RESOLVE(obj); |
1647 | if (obj < PDF_LIMIT) |
1648 | return; |
1649 | obj->flags |= PDF_FLAGS_DIRTY; |
1650 | } |
1651 | |
1652 | void pdf_clean_obj(fz_context *ctx, pdf_obj *obj) |
1653 | { |
1654 | RESOLVE(obj); |
1655 | if (obj < PDF_LIMIT) |
1656 | return; |
1657 | obj->flags &= ~PDF_FLAGS_DIRTY; |
1658 | } |
1659 | |
1660 | static void |
1661 | pdf_drop_array(fz_context *ctx, pdf_obj *obj) |
1662 | { |
1663 | int i; |
1664 | |
1665 | for (i = 0; i < DICT(obj)->len; i++) |
1666 | pdf_drop_obj(ctx, ARRAY(obj)->items[i]); |
1667 | |
1668 | fz_free(ctx, DICT(obj)->items); |
1669 | fz_free(ctx, obj); |
1670 | } |
1671 | |
1672 | static void |
1673 | pdf_drop_dict(fz_context *ctx, pdf_obj *obj) |
1674 | { |
1675 | int i; |
1676 | |
1677 | for (i = 0; i < DICT(obj)->len; i++) { |
1678 | pdf_drop_obj(ctx, DICT(obj)->items[i].k); |
1679 | pdf_drop_obj(ctx, DICT(obj)->items[i].v); |
1680 | } |
1681 | |
1682 | fz_free(ctx, DICT(obj)->items); |
1683 | fz_free(ctx, obj); |
1684 | } |
1685 | |
1686 | pdf_obj * |
1687 | pdf_keep_obj(fz_context *ctx, pdf_obj *obj) |
1688 | { |
1689 | if (obj >= PDF_LIMIT) |
1690 | return fz_keep_imp16(ctx, obj, &obj->refs); |
1691 | return obj; |
1692 | } |
1693 | |
1694 | void |
1695 | pdf_drop_obj(fz_context *ctx, pdf_obj *obj) |
1696 | { |
1697 | if (obj >= PDF_LIMIT) |
1698 | { |
1699 | if (fz_drop_imp16(ctx, obj, &obj->refs)) |
1700 | { |
1701 | if (obj->kind == PDF_ARRAY) |
1702 | pdf_drop_array(ctx, obj); |
1703 | else if (obj->kind == PDF_DICT) |
1704 | pdf_drop_dict(ctx, obj); |
1705 | else if (obj->kind == PDF_STRING) |
1706 | { |
1707 | fz_free(ctx, STRING(obj)->text); |
1708 | fz_free(ctx, obj); |
1709 | } |
1710 | else |
1711 | fz_free(ctx, obj); |
1712 | } |
1713 | } |
1714 | } |
1715 | |
1716 | /* |
1717 | Recurse through the object structure setting the node's parent_num to num. |
1718 | parent_num is used when a subobject is to be changed during a document edit. |
1719 | The whole containing hierarchy is moved to the incremental xref section, so |
1720 | to be later written out as an incremental file update. |
1721 | */ |
1722 | void |
1723 | pdf_set_obj_parent(fz_context *ctx, pdf_obj *obj, int num) |
1724 | { |
1725 | int n, i; |
1726 | |
1727 | if (obj < PDF_LIMIT) |
1728 | return; |
1729 | |
1730 | switch (obj->kind) |
1731 | { |
1732 | case PDF_ARRAY: |
1733 | ARRAY(obj)->parent_num = num; |
1734 | n = pdf_array_len(ctx, obj); |
1735 | for (i = 0; i < n; i++) |
1736 | pdf_set_obj_parent(ctx, pdf_array_get(ctx, obj, i), num); |
1737 | break; |
1738 | case PDF_DICT: |
1739 | DICT(obj)->parent_num = num; |
1740 | n = pdf_dict_len(ctx, obj); |
1741 | for (i = 0; i < n; i++) |
1742 | pdf_set_obj_parent(ctx, pdf_dict_get_val(ctx, obj, i), num); |
1743 | break; |
1744 | } |
1745 | } |
1746 | |
1747 | int pdf_obj_parent_num(fz_context *ctx, pdf_obj *obj) |
1748 | { |
1749 | if (obj < PDF_LIMIT) |
1750 | return 0; |
1751 | |
1752 | switch (obj->kind) |
1753 | { |
1754 | case PDF_INDIRECT: |
1755 | return REF(obj)->num; |
1756 | case PDF_ARRAY: |
1757 | return ARRAY(obj)->parent_num; |
1758 | case PDF_DICT: |
1759 | return DICT(obj)->parent_num; |
1760 | default: |
1761 | return 0; |
1762 | } |
1763 | } |
1764 | |
1765 | /* Pretty printing objects */ |
1766 | |
1767 | struct fmt |
1768 | { |
1769 | char *buf; /* original static buffer */ |
1770 | char *ptr; /* buffer we're writing to, maybe dynamically reallocated */ |
1771 | int cap; |
1772 | int len; |
1773 | int indent; |
1774 | int tight; |
1775 | int ascii; |
1776 | int col; |
1777 | int sep; |
1778 | int last; |
1779 | pdf_crypt *crypt; |
1780 | int num; |
1781 | int gen; |
1782 | }; |
1783 | |
1784 | static void fmt_obj(fz_context *ctx, struct fmt *fmt, pdf_obj *obj); |
1785 | |
1786 | static inline int iswhite(int ch) |
1787 | { |
1788 | return |
1789 | ch == '\000' || |
1790 | ch == '\011' || |
1791 | ch == '\012' || |
1792 | ch == '\014' || |
1793 | ch == '\015' || |
1794 | ch == '\040'; |
1795 | } |
1796 | |
1797 | static inline int isdelim(int ch) |
1798 | { |
1799 | return |
1800 | ch == '(' || ch == ')' || |
1801 | ch == '<' || ch == '>' || |
1802 | ch == '[' || ch == ']' || |
1803 | ch == '{' || ch == '}' || |
1804 | ch == '/' || |
1805 | ch == '%'; |
1806 | } |
1807 | |
1808 | static inline void fmt_putc(fz_context *ctx, struct fmt *fmt, int c) |
1809 | { |
1810 | if (fmt->sep && !isdelim(fmt->last) && !isdelim(c)) { |
1811 | fmt->sep = 0; |
1812 | fmt_putc(ctx, fmt, ' '); |
1813 | } |
1814 | fmt->sep = 0; |
1815 | |
1816 | if (fmt->len >= fmt->cap) |
1817 | { |
1818 | fmt->cap *= 2; |
1819 | if (fmt->buf == fmt->ptr) |
1820 | { |
1821 | fmt->ptr = fz_malloc(ctx, fmt->cap); |
1822 | memcpy(fmt->ptr, fmt->buf, fmt->len); |
1823 | } |
1824 | else |
1825 | { |
1826 | fmt->ptr = fz_realloc(ctx, fmt->ptr, fmt->cap); |
1827 | } |
1828 | } |
1829 | |
1830 | fmt->ptr[fmt->len] = c; |
1831 | |
1832 | if (c == '\n') |
1833 | fmt->col = 0; |
1834 | else |
1835 | fmt->col ++; |
1836 | |
1837 | fmt->len ++; |
1838 | |
1839 | fmt->last = c; |
1840 | } |
1841 | |
1842 | static inline void fmt_indent(fz_context *ctx, struct fmt *fmt) |
1843 | { |
1844 | int i = fmt->indent; |
1845 | while (i--) { |
1846 | fmt_putc(ctx, fmt, ' '); |
1847 | fmt_putc(ctx, fmt, ' '); |
1848 | } |
1849 | } |
1850 | |
1851 | static inline void fmt_puts(fz_context *ctx, struct fmt *fmt, char *s) |
1852 | { |
1853 | while (*s) |
1854 | fmt_putc(ctx, fmt, *s++); |
1855 | } |
1856 | |
1857 | static inline void fmt_sep(fz_context *ctx, struct fmt *fmt) |
1858 | { |
1859 | fmt->sep = 1; |
1860 | } |
1861 | |
1862 | static int is_binary_string(fz_context *ctx, pdf_obj *obj) |
1863 | { |
1864 | unsigned char *s = (unsigned char *)pdf_to_str_buf(ctx, obj); |
1865 | int i, n = pdf_to_str_len(ctx, obj); |
1866 | for (i = 0; i < n; ++i) |
1867 | { |
1868 | if (s[i] > 126) return 1; |
1869 | if (s[i] < 32 && (s[i] != '\t' && s[i] != '\n' && s[i] != '\r')) return 1; |
1870 | } |
1871 | return 0; |
1872 | } |
1873 | |
1874 | static int is_longer_than_hex(fz_context *ctx, pdf_obj *obj) |
1875 | { |
1876 | unsigned char *s = (unsigned char *)pdf_to_str_buf(ctx, obj); |
1877 | int i, n = pdf_to_str_len(ctx, obj); |
1878 | int m = 0; |
1879 | for (i = 0; i < n; ++i) |
1880 | { |
1881 | if (s[i] > 126) |
1882 | m += 4; |
1883 | else if (s[i] == 0) |
1884 | m += 4; |
1885 | else if (strchr("\n\r\t\b\f()\\" , s[i])) |
1886 | m += 2; |
1887 | else if (s[i] < 32) |
1888 | m += 4; |
1889 | else |
1890 | m += 1; |
1891 | } |
1892 | return m > (n * 2); |
1893 | } |
1894 | |
1895 | static void fmt_str_out(fz_context *ctx, void *fmt_, const unsigned char *s, int n) |
1896 | { |
1897 | struct fmt *fmt = (struct fmt *)fmt_; |
1898 | int i, c; |
1899 | |
1900 | for (i = 0; i < n; i++) |
1901 | { |
1902 | c = (unsigned char)s[i]; |
1903 | if (c == '\n') |
1904 | fmt_puts(ctx, fmt, "\\n" ); |
1905 | else if (c == '\r') |
1906 | fmt_puts(ctx, fmt, "\\r" ); |
1907 | else if (c == '\t') |
1908 | fmt_puts(ctx, fmt, "\\t" ); |
1909 | else if (c == '\b') |
1910 | fmt_puts(ctx, fmt, "\\b" ); |
1911 | else if (c == '\f') |
1912 | fmt_puts(ctx, fmt, "\\f" ); |
1913 | else if (c == '(') |
1914 | fmt_puts(ctx, fmt, "\\(" ); |
1915 | else if (c == ')') |
1916 | fmt_puts(ctx, fmt, "\\)" ); |
1917 | else if (c == '\\') |
1918 | fmt_puts(ctx, fmt, "\\\\" ); |
1919 | else if (c < 32 || c >= 127) { |
1920 | fmt_putc(ctx, fmt, '\\'); |
1921 | fmt_putc(ctx, fmt, '0' + ((c / 64) & 7)); |
1922 | fmt_putc(ctx, fmt, '0' + ((c / 8) & 7)); |
1923 | fmt_putc(ctx, fmt, '0' + ((c) & 7)); |
1924 | } |
1925 | else |
1926 | fmt_putc(ctx, fmt, c); |
1927 | } |
1928 | } |
1929 | |
1930 | static void fmt_str(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
1931 | { |
1932 | unsigned char *s = (unsigned char *)pdf_to_str_buf(ctx, obj); |
1933 | int n = pdf_to_str_len(ctx, obj); |
1934 | |
1935 | fmt_putc(ctx, fmt, '('); |
1936 | pdf_encrypt_data(ctx, fmt->crypt, fmt->num, fmt->gen, fmt_str_out, fmt, s, n); |
1937 | fmt_putc(ctx, fmt, ')'); |
1938 | } |
1939 | |
1940 | static void fmt_hex_out(fz_context *ctx, void *arg, const unsigned char *s, int n) |
1941 | { |
1942 | struct fmt *fmt = (struct fmt *)arg; |
1943 | int i, b, c; |
1944 | |
1945 | for (i = 0; i < n; i++) { |
1946 | b = (unsigned char) s[i]; |
1947 | c = (b >> 4) & 0x0f; |
1948 | fmt_putc(ctx, fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); |
1949 | c = (b) & 0x0f; |
1950 | fmt_putc(ctx, fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); |
1951 | } |
1952 | } |
1953 | |
1954 | static void fmt_hex(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
1955 | { |
1956 | unsigned char *s = (unsigned char *)pdf_to_str_buf(ctx, obj); |
1957 | int n = pdf_to_str_len(ctx, obj); |
1958 | |
1959 | fmt_putc(ctx, fmt, '<'); |
1960 | pdf_encrypt_data(ctx, fmt->crypt, fmt->num, fmt->gen, fmt_hex_out, fmt, s, n); |
1961 | fmt_putc(ctx, fmt, '>'); |
1962 | } |
1963 | |
1964 | static void fmt_name(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
1965 | { |
1966 | unsigned char *s = (unsigned char *) pdf_to_name(ctx, obj); |
1967 | int i, c; |
1968 | |
1969 | fmt_putc(ctx, fmt, '/'); |
1970 | |
1971 | for (i = 0; s[i]; i++) |
1972 | { |
1973 | if (isdelim(s[i]) || iswhite(s[i]) || |
1974 | s[i] == '#' || s[i] < 32 || s[i] >= 127) |
1975 | { |
1976 | fmt_putc(ctx, fmt, '#'); |
1977 | c = (s[i] >> 4) & 0xf; |
1978 | fmt_putc(ctx, fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); |
1979 | c = s[i] & 0xf; |
1980 | fmt_putc(ctx, fmt, c < 0xA ? c + '0' : c + 'A' - 0xA); |
1981 | } |
1982 | else |
1983 | { |
1984 | fmt_putc(ctx, fmt, s[i]); |
1985 | } |
1986 | } |
1987 | } |
1988 | |
1989 | static void fmt_array(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
1990 | { |
1991 | int i, n; |
1992 | |
1993 | n = pdf_array_len(ctx, obj); |
1994 | if (fmt->tight) { |
1995 | fmt_putc(ctx, fmt, '['); |
1996 | for (i = 0; i < n; i++) { |
1997 | fmt_obj(ctx, fmt, pdf_array_get(ctx, obj, i)); |
1998 | fmt_sep(ctx, fmt); |
1999 | } |
2000 | fmt_putc(ctx, fmt, ']'); |
2001 | } |
2002 | else { |
2003 | fmt_putc(ctx, fmt, '['); |
2004 | fmt->indent ++; |
2005 | for (i = 0; i < n; i++) { |
2006 | if (fmt->col > 60) { |
2007 | fmt_putc(ctx, fmt, '\n'); |
2008 | fmt_indent(ctx, fmt); |
2009 | } else { |
2010 | fmt_putc(ctx, fmt, ' '); |
2011 | } |
2012 | fmt_obj(ctx, fmt, pdf_array_get(ctx, obj, i)); |
2013 | } |
2014 | fmt->indent --; |
2015 | fmt_putc(ctx, fmt, ' '); |
2016 | fmt_putc(ctx, fmt, ']'); |
2017 | fmt_sep(ctx, fmt); |
2018 | } |
2019 | } |
2020 | |
2021 | static void fmt_dict(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
2022 | { |
2023 | int i, n; |
2024 | pdf_obj *key, *val; |
2025 | |
2026 | n = pdf_dict_len(ctx, obj); |
2027 | if (fmt->tight) { |
2028 | fmt_puts(ctx, fmt, "<<" ); |
2029 | for (i = 0; i < n; i++) { |
2030 | fmt_obj(ctx, fmt, pdf_dict_get_key(ctx, obj, i)); |
2031 | fmt_sep(ctx, fmt); |
2032 | fmt_obj(ctx, fmt, pdf_dict_get_val(ctx, obj, i)); |
2033 | fmt_sep(ctx, fmt); |
2034 | } |
2035 | fmt_puts(ctx, fmt, ">>" ); |
2036 | } |
2037 | else { |
2038 | fmt_puts(ctx, fmt, "<<\n" ); |
2039 | fmt->indent ++; |
2040 | for (i = 0; i < n; i++) { |
2041 | key = pdf_dict_get_key(ctx, obj, i); |
2042 | val = pdf_dict_get_val(ctx, obj, i); |
2043 | fmt_indent(ctx, fmt); |
2044 | fmt_obj(ctx, fmt, key); |
2045 | fmt_putc(ctx, fmt, ' '); |
2046 | if (!pdf_is_indirect(ctx, val) && pdf_is_array(ctx, val)) |
2047 | fmt->indent ++; |
2048 | fmt_obj(ctx, fmt, val); |
2049 | fmt_putc(ctx, fmt, '\n'); |
2050 | if (!pdf_is_indirect(ctx, val) && pdf_is_array(ctx, val)) |
2051 | fmt->indent --; |
2052 | } |
2053 | fmt->indent --; |
2054 | fmt_indent(ctx, fmt); |
2055 | fmt_puts(ctx, fmt, ">>" ); |
2056 | } |
2057 | } |
2058 | |
2059 | static void fmt_obj(fz_context *ctx, struct fmt *fmt, pdf_obj *obj) |
2060 | { |
2061 | char buf[256]; |
2062 | |
2063 | if (obj == PDF_NULL) |
2064 | fmt_puts(ctx, fmt, "null" ); |
2065 | else if (obj == PDF_TRUE) |
2066 | fmt_puts(ctx, fmt, "true" ); |
2067 | else if (obj == PDF_FALSE) |
2068 | fmt_puts(ctx, fmt, "false" ); |
2069 | else if (pdf_is_indirect(ctx, obj)) |
2070 | { |
2071 | fz_snprintf(buf, sizeof buf, "%d %d R" , pdf_to_num(ctx, obj), pdf_to_gen(ctx, obj)); |
2072 | fmt_puts(ctx, fmt, buf); |
2073 | } |
2074 | else if (pdf_is_int(ctx, obj)) |
2075 | { |
2076 | fz_snprintf(buf, sizeof buf, "%d" , pdf_to_int(ctx, obj)); |
2077 | fmt_puts(ctx, fmt, buf); |
2078 | } |
2079 | else if (pdf_is_real(ctx, obj)) |
2080 | { |
2081 | fz_snprintf(buf, sizeof buf, "%g" , pdf_to_real(ctx, obj)); |
2082 | fmt_puts(ctx, fmt, buf); |
2083 | } |
2084 | else if (pdf_is_string(ctx, obj)) |
2085 | { |
2086 | unsigned char *str = (unsigned char *)pdf_to_str_buf(ctx, obj); |
2087 | if (fmt->crypt |
2088 | || (fmt->ascii && is_binary_string(ctx, obj)) |
2089 | || (str[0]==0xff && str[1]==0xfe) |
2090 | || (str[0]==0xfe && str[1] == 0xff) |
2091 | || is_longer_than_hex(ctx, obj) |
2092 | ) |
2093 | fmt_hex(ctx, fmt, obj); |
2094 | else |
2095 | fmt_str(ctx, fmt, obj); |
2096 | } |
2097 | else if (pdf_is_name(ctx, obj)) |
2098 | fmt_name(ctx, fmt, obj); |
2099 | else if (pdf_is_array(ctx, obj)) |
2100 | fmt_array(ctx, fmt, obj); |
2101 | else if (pdf_is_dict(ctx, obj)) |
2102 | fmt_dict(ctx, fmt, obj); |
2103 | else |
2104 | fmt_puts(ctx, fmt, "<unknown object>" ); |
2105 | } |
2106 | |
2107 | static char * |
2108 | pdf_sprint_encrypted_obj(fz_context *ctx, char *buf, int cap, int *len, pdf_obj *obj, int tight, int ascii, pdf_crypt *crypt, int num, int gen) |
2109 | { |
2110 | struct fmt fmt; |
2111 | |
2112 | fmt.indent = 0; |
2113 | fmt.col = 0; |
2114 | fmt.sep = 0; |
2115 | fmt.last = 0; |
2116 | |
2117 | if (!buf || cap == 0) |
2118 | { |
2119 | fmt.cap = 1024; |
2120 | fmt.buf = NULL; |
2121 | fmt.ptr = fz_malloc(ctx, fmt.cap); |
2122 | } |
2123 | else |
2124 | { |
2125 | fmt.cap = cap; |
2126 | fmt.buf = buf; |
2127 | fmt.ptr = buf; |
2128 | } |
2129 | |
2130 | fmt.tight = tight; |
2131 | fmt.ascii = ascii; |
2132 | fmt.len = 0; |
2133 | fmt.crypt = crypt; |
2134 | fmt.num = num; |
2135 | fmt.gen = gen; |
2136 | fmt_obj(ctx, &fmt, obj); |
2137 | |
2138 | fmt_putc(ctx, &fmt, 0); |
2139 | |
2140 | return *len = fmt.len-1, fmt.ptr; |
2141 | } |
2142 | |
2143 | char * |
2144 | pdf_sprint_obj(fz_context *ctx, char *buf, int cap, int *len, pdf_obj *obj, int tight, int ascii) |
2145 | { |
2146 | return pdf_sprint_encrypted_obj(ctx, buf, cap, len, obj, tight, ascii, NULL, 0, 0); |
2147 | } |
2148 | |
2149 | void pdf_print_encrypted_obj(fz_context *ctx, fz_output *out, pdf_obj *obj, int tight, int ascii, pdf_crypt *crypt, int num, int gen) |
2150 | { |
2151 | char buf[1024]; |
2152 | char *ptr; |
2153 | int n; |
2154 | |
2155 | ptr = pdf_sprint_encrypted_obj(ctx, buf, sizeof buf, &n, obj, tight, ascii,crypt, num, gen); |
2156 | fz_try(ctx) |
2157 | fz_write_data(ctx, out, ptr, n); |
2158 | fz_always(ctx) |
2159 | if (ptr != buf) |
2160 | fz_free(ctx, ptr); |
2161 | fz_catch(ctx) |
2162 | fz_rethrow(ctx); |
2163 | } |
2164 | |
2165 | void pdf_print_obj(fz_context *ctx, fz_output *out, pdf_obj *obj, int tight, int ascii) |
2166 | { |
2167 | pdf_print_encrypted_obj(ctx, out, obj, tight, ascii, NULL, 0, 0); |
2168 | } |
2169 | |
2170 | static void pdf_debug_encrypted_obj(fz_context *ctx, pdf_obj *obj, int tight, pdf_crypt *crypt, int num, int gen) |
2171 | { |
2172 | char buf[1024]; |
2173 | char *ptr; |
2174 | int n; |
2175 | int ascii = 1; |
2176 | |
2177 | ptr = pdf_sprint_encrypted_obj(ctx, buf, sizeof buf, &n, obj, tight, ascii, crypt, num, gen); |
2178 | fwrite(ptr, 1, n, stdout); |
2179 | if (ptr != buf) |
2180 | fz_free(ctx, ptr); |
2181 | } |
2182 | |
2183 | void pdf_debug_obj(fz_context *ctx, pdf_obj *obj) |
2184 | { |
2185 | pdf_debug_encrypted_obj(ctx, pdf_resolve_indirect(ctx, obj), 0, NULL, 0, 0); |
2186 | putchar('\n'); |
2187 | } |
2188 | |
2189 | void pdf_debug_ref(fz_context *ctx, pdf_obj *obj) |
2190 | { |
2191 | pdf_debug_encrypted_obj(ctx, obj, 0, NULL, 0, 0); |
2192 | putchar('\n'); |
2193 | } |
2194 | |
2195 | int pdf_obj_refs(fz_context *ctx, pdf_obj *obj) |
2196 | { |
2197 | if (obj < PDF_LIMIT) |
2198 | return 0; |
2199 | return obj->refs; |
2200 | } |
2201 | |
2202 | /* Convenience functions */ |
2203 | |
2204 | pdf_obj * |
2205 | pdf_dict_get_inheritable(fz_context *ctx, pdf_obj *node, pdf_obj *key) |
2206 | { |
2207 | pdf_obj *node2 = node; |
2208 | pdf_obj *val = NULL; |
2209 | pdf_obj *marked = NULL; |
2210 | |
2211 | fz_var(node); |
2212 | fz_var(marked); |
2213 | fz_try(ctx) |
2214 | { |
2215 | do |
2216 | { |
2217 | val = pdf_dict_get(ctx, node, key); |
2218 | if (val) |
2219 | break; |
2220 | if (pdf_mark_obj(ctx, node)) |
2221 | fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in tree (parents)" ); |
2222 | marked = node; |
2223 | node = pdf_dict_get(ctx, node, PDF_NAME(Parent)); |
2224 | } |
2225 | while (node); |
2226 | } |
2227 | fz_always(ctx) |
2228 | { |
2229 | /* We assume that if we have marked an object, without an exception |
2230 | * being thrown, that we can always unmark the same object again |
2231 | * without an exception being thrown. */ |
2232 | if (marked) |
2233 | { |
2234 | do |
2235 | { |
2236 | pdf_unmark_obj(ctx, node2); |
2237 | if (node2 == marked) |
2238 | break; |
2239 | node2 = pdf_dict_get(ctx, node2, PDF_NAME(Parent)); |
2240 | } |
2241 | while (node2); |
2242 | } |
2243 | } |
2244 | fz_catch(ctx) |
2245 | { |
2246 | fz_rethrow(ctx); |
2247 | } |
2248 | |
2249 | return val; |
2250 | } |
2251 | |
2252 | void pdf_dict_put_bool(fz_context *ctx, pdf_obj *dict, pdf_obj *key, int x) |
2253 | { |
2254 | pdf_dict_put(ctx, dict, key, x ? PDF_TRUE : PDF_FALSE); |
2255 | } |
2256 | |
2257 | void pdf_dict_put_int(fz_context *ctx, pdf_obj *dict, pdf_obj *key, int64_t x) |
2258 | { |
2259 | pdf_dict_put_drop(ctx, dict, key, pdf_new_int(ctx, x)); |
2260 | } |
2261 | |
2262 | void pdf_dict_put_real(fz_context *ctx, pdf_obj *dict, pdf_obj *key, double x) |
2263 | { |
2264 | pdf_dict_put_drop(ctx, dict, key, pdf_new_real(ctx, x)); |
2265 | } |
2266 | |
2267 | void pdf_dict_put_name(fz_context *ctx, pdf_obj *dict, pdf_obj *key, const char *x) |
2268 | { |
2269 | pdf_dict_put_drop(ctx, dict, key, pdf_new_name(ctx, x)); |
2270 | } |
2271 | |
2272 | void pdf_dict_put_string(fz_context *ctx, pdf_obj *dict, pdf_obj *key, const char *x, size_t n) |
2273 | { |
2274 | pdf_dict_put_drop(ctx, dict, key, pdf_new_string(ctx, x, n)); |
2275 | } |
2276 | |
2277 | void pdf_dict_put_text_string(fz_context *ctx, pdf_obj *dict, pdf_obj *key, const char *x) |
2278 | { |
2279 | pdf_dict_put_drop(ctx, dict, key, pdf_new_text_string(ctx, x)); |
2280 | } |
2281 | |
2282 | void pdf_dict_put_rect(fz_context *ctx, pdf_obj *dict, pdf_obj *key, fz_rect x) |
2283 | { |
2284 | pdf_dict_put_drop(ctx, dict, key, pdf_new_rect(ctx, NULL, x)); |
2285 | } |
2286 | |
2287 | void pdf_dict_put_matrix(fz_context *ctx, pdf_obj *dict, pdf_obj *key, fz_matrix x) |
2288 | { |
2289 | pdf_dict_put_drop(ctx, dict, key, pdf_new_matrix(ctx, NULL, x)); |
2290 | } |
2291 | |
2292 | pdf_obj *pdf_dict_put_array(fz_context *ctx, pdf_obj *dict, pdf_obj *key, int initial) |
2293 | { |
2294 | pdf_obj *obj = pdf_new_array(ctx, pdf_get_bound_document(ctx, dict), initial); |
2295 | pdf_dict_put_drop(ctx, dict, key, obj); |
2296 | return obj; |
2297 | } |
2298 | |
2299 | pdf_obj *pdf_dict_put_dict(fz_context *ctx, pdf_obj *dict, pdf_obj *key, int initial) |
2300 | { |
2301 | pdf_obj *obj = pdf_new_dict(ctx, pdf_get_bound_document(ctx, dict), initial); |
2302 | pdf_dict_put_drop(ctx, dict, key, obj); |
2303 | return obj; |
2304 | } |
2305 | |
2306 | pdf_obj *pdf_dict_puts_dict(fz_context *ctx, pdf_obj *dict, const char *key, int initial) |
2307 | { |
2308 | pdf_obj *obj = pdf_new_dict(ctx, pdf_get_bound_document(ctx, dict), initial); |
2309 | pdf_dict_puts_drop(ctx, dict, key, obj); |
2310 | return obj; |
2311 | } |
2312 | |
2313 | void pdf_array_push_bool(fz_context *ctx, pdf_obj *array, int x) |
2314 | { |
2315 | pdf_array_push(ctx, array, x ? PDF_TRUE : PDF_FALSE); |
2316 | } |
2317 | |
2318 | void pdf_array_push_int(fz_context *ctx, pdf_obj *array, int64_t x) |
2319 | { |
2320 | pdf_array_push_drop(ctx, array, pdf_new_int(ctx, x)); |
2321 | } |
2322 | |
2323 | void pdf_array_push_real(fz_context *ctx, pdf_obj *array, double x) |
2324 | { |
2325 | pdf_array_push_drop(ctx, array, pdf_new_real(ctx, x)); |
2326 | } |
2327 | |
2328 | void pdf_array_push_name(fz_context *ctx, pdf_obj *array, const char *x) |
2329 | { |
2330 | pdf_array_push_drop(ctx, array, pdf_new_name(ctx, x)); |
2331 | } |
2332 | |
2333 | void pdf_array_push_string(fz_context *ctx, pdf_obj *array, const char *x, size_t n) |
2334 | { |
2335 | pdf_array_push_drop(ctx, array, pdf_new_string(ctx, x, n)); |
2336 | } |
2337 | |
2338 | void pdf_array_push_text_string(fz_context *ctx, pdf_obj *array, const char *x) |
2339 | { |
2340 | pdf_array_push_drop(ctx, array, pdf_new_text_string(ctx, x)); |
2341 | } |
2342 | |
2343 | pdf_obj *pdf_array_push_array(fz_context *ctx, pdf_obj *array, int initial) |
2344 | { |
2345 | pdf_obj *obj = pdf_new_array(ctx, pdf_get_bound_document(ctx, array), initial); |
2346 | pdf_array_push_drop(ctx, array, obj); |
2347 | return obj; |
2348 | } |
2349 | |
2350 | pdf_obj *pdf_array_push_dict(fz_context *ctx, pdf_obj *array, int initial) |
2351 | { |
2352 | pdf_obj *obj = pdf_new_dict(ctx, pdf_get_bound_document(ctx, array), initial); |
2353 | pdf_array_push_drop(ctx, array, obj); |
2354 | return obj; |
2355 | } |
2356 | |
2357 | int pdf_dict_get_bool(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2358 | { |
2359 | return pdf_to_bool(ctx, pdf_dict_get(ctx, dict, key)); |
2360 | } |
2361 | |
2362 | int pdf_dict_get_int(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2363 | { |
2364 | return pdf_to_int(ctx, pdf_dict_get(ctx, dict, key)); |
2365 | } |
2366 | |
2367 | float pdf_dict_get_real(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2368 | { |
2369 | return pdf_to_real(ctx, pdf_dict_get(ctx, dict, key)); |
2370 | } |
2371 | |
2372 | const char *pdf_dict_get_name(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2373 | { |
2374 | return pdf_to_name(ctx, pdf_dict_get(ctx, dict, key)); |
2375 | } |
2376 | |
2377 | const char *pdf_dict_get_string(fz_context *ctx, pdf_obj *dict, pdf_obj *key, size_t *sizep) |
2378 | { |
2379 | return pdf_to_string(ctx, pdf_dict_get(ctx, dict, key), sizep); |
2380 | } |
2381 | |
2382 | const char *pdf_dict_get_text_string(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2383 | { |
2384 | return pdf_to_text_string(ctx, pdf_dict_get(ctx, dict, key)); |
2385 | } |
2386 | |
2387 | fz_rect pdf_dict_get_rect(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2388 | { |
2389 | return pdf_to_rect(ctx, pdf_dict_get(ctx, dict, key)); |
2390 | } |
2391 | |
2392 | fz_matrix pdf_dict_get_matrix(fz_context *ctx, pdf_obj *dict, pdf_obj *key) |
2393 | { |
2394 | return pdf_to_matrix(ctx, pdf_dict_get(ctx, dict, key)); |
2395 | } |
2396 | |
2397 | int pdf_array_get_bool(fz_context *ctx, pdf_obj *array, int index) |
2398 | { |
2399 | return pdf_to_bool(ctx, pdf_array_get(ctx, array, index)); |
2400 | } |
2401 | |
2402 | int pdf_array_get_int(fz_context *ctx, pdf_obj *array, int index) |
2403 | { |
2404 | return pdf_to_int(ctx, pdf_array_get(ctx, array, index)); |
2405 | } |
2406 | |
2407 | float pdf_array_get_real(fz_context *ctx, pdf_obj *array, int index) |
2408 | { |
2409 | return pdf_to_real(ctx, pdf_array_get(ctx, array, index)); |
2410 | } |
2411 | |
2412 | const char *pdf_array_get_name(fz_context *ctx, pdf_obj *array, int index) |
2413 | { |
2414 | return pdf_to_name(ctx, pdf_array_get(ctx, array, index)); |
2415 | } |
2416 | |
2417 | const char *pdf_array_get_string(fz_context *ctx, pdf_obj *array, int index, size_t *sizep) |
2418 | { |
2419 | return pdf_to_string(ctx, pdf_array_get(ctx, array, index), sizep); |
2420 | } |
2421 | |
2422 | const char *pdf_array_get_text_string(fz_context *ctx, pdf_obj *array, int index) |
2423 | { |
2424 | return pdf_to_text_string(ctx, pdf_array_get(ctx, array, index)); |
2425 | } |
2426 | |
2427 | fz_rect pdf_array_get_rect(fz_context *ctx, pdf_obj *array, int index) |
2428 | { |
2429 | return pdf_to_rect(ctx, pdf_array_get(ctx, array, index)); |
2430 | } |
2431 | |
2432 | fz_matrix pdf_array_get_matrix(fz_context *ctx, pdf_obj *array, int index) |
2433 | { |
2434 | return pdf_to_matrix(ctx, pdf_array_get(ctx, array, index)); |
2435 | } |
2436 | |