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