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,
10static 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
16typedef 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
27struct keyval
28{
29 pdf_obj *k;
30 pdf_obj *v;
31};
32
33enum
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
42struct pdf_obj_s
43{
44 short refs;
45 unsigned char kind;
46 unsigned char flags;
47};
48
49typedef 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
59typedef 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
67typedef struct pdf_obj_name_s
68{
69 pdf_obj super;
70 char n[1];
71} pdf_obj_name;
72
73typedef 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
83typedef 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
93typedef 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
108pdf_obj *
109pdf_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
120pdf_obj *
121pdf_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
132pdf_obj *
133pdf_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
152pdf_obj *
153pdf_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
178pdf_obj *
179pdf_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
214int pdf_is_indirect(fz_context *ctx, pdf_obj *obj)
215{
216 return OBJ_IS_INDIRECT(obj);
217}
218
219int pdf_is_null(fz_context *ctx, pdf_obj *obj)
220{
221 RESOLVE(obj);
222 return OBJ_IS_NULL(obj);
223}
224
225int pdf_is_bool(fz_context *ctx, pdf_obj *obj)
226{
227 RESOLVE(obj);
228 return OBJ_IS_BOOL(obj);
229}
230
231int pdf_is_int(fz_context *ctx, pdf_obj *obj)
232{
233 RESOLVE(obj);
234 return OBJ_IS_INT(obj);
235}
236
237int pdf_is_real(fz_context *ctx, pdf_obj *obj)
238{
239 RESOLVE(obj);
240 return OBJ_IS_REAL(obj);
241}
242
243int pdf_is_number(fz_context *ctx, pdf_obj *obj)
244{
245 RESOLVE(obj);
246 return OBJ_IS_NUMBER(obj);
247}
248
249int pdf_is_string(fz_context *ctx, pdf_obj *obj)
250{
251 RESOLVE(obj);
252 return OBJ_IS_STRING(obj);
253}
254
255int pdf_is_name(fz_context *ctx, pdf_obj *obj)
256{
257 RESOLVE(obj);
258 return OBJ_IS_NAME(obj);
259}
260
261int pdf_is_array(fz_context *ctx, pdf_obj *obj)
262{
263 RESOLVE(obj);
264 return OBJ_IS_ARRAY(obj);
265}
266
267int 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 */
274int pdf_to_bool(fz_context *ctx, pdf_obj *obj)
275{
276 RESOLVE(obj);
277 return obj == PDF_TRUE;
278}
279
280int 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
292int64_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
304float 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
316const 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
326char *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
334int 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
342const 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
356const 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
368void 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 */
375void 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
386int 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
393int 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
400pdf_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
407pdf_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
420int 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
427int
428pdf_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
519int 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
532static char *
533pdf_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
554pdf_obj *
555pdf_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
585static void
586pdf_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
598pdf_obj *
599pdf_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
626int
627pdf_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
635pdf_obj *
636pdf_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
646static 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
695void
696pdf_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
713void
714pdf_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
724void
725pdf_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
737void
738pdf_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
748void
749pdf_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
764void
765pdf_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
775void
776pdf_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
790int
791pdf_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
803int
804pdf_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
816pdf_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
834pdf_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
856static 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
882pdf_obj *
883pdf_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
916static void
917pdf_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
932pdf_obj *
933pdf_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
958int
959pdf_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
967pdf_obj *
968pdf_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
978pdf_obj *
979pdf_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
989void
990pdf_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. */
1005static int
1006pdf_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
1044static int
1045pdf_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
1097pdf_obj *
1098pdf_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
1114pdf_obj *
1115pdf_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
1147pdf_obj *
1148pdf_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
1164pdf_obj *
1165pdf_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
1184pdf_obj *
1185pdf_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
1194pdf_obj *
1195pdf_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
1204static void
1205pdf_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
1257void
1258pdf_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
1263void
1264pdf_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
1274void
1275pdf_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
1285void
1286pdf_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
1304void
1305pdf_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
1330void
1331pdf_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
1389void
1390pdf_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
1400static void
1401pdf_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
1430new_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
1445void
1446pdf_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
1459void
1460pdf_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
1476void
1477pdf_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
1499void
1500pdf_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
1511void
1512pdf_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
1524pdf_obj *
1525pdf_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. */
1580int
1581pdf_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
1589int
1590pdf_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
1601void
1602pdf_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
1610void
1611pdf_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
1623int
1624pdf_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. */
1636int 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
1644void 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
1652void 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
1660static void
1661pdf_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
1672static void
1673pdf_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
1686pdf_obj *
1687pdf_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
1694void
1695pdf_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*/
1722void
1723pdf_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
1747int 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
1767struct 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
1784static void fmt_obj(fz_context *ctx, struct fmt *fmt, pdf_obj *obj);
1785
1786static 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
1797static 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
1808static 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
1842static 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
1851static inline void fmt_puts(fz_context *ctx, struct fmt *fmt, char *s)
1852{
1853 while (*s)
1854 fmt_putc(ctx, fmt, *s++);
1855}
1856
1857static inline void fmt_sep(fz_context *ctx, struct fmt *fmt)
1858{
1859 fmt->sep = 1;
1860}
1861
1862static 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
1874static 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
1895static 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
1930static 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
1940static 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
1954static 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
1964static 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
1989static 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
2021static 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
2059static 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
2107static char *
2108pdf_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
2143char *
2144pdf_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
2149void 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
2165void 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
2170static 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
2183void 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
2189void 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
2195int 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
2204pdf_obj *
2205pdf_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
2252void 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
2257void 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
2262void 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
2267void 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
2272void 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
2277void 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
2282void 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
2287void 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
2292pdf_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
2299pdf_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
2306pdf_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
2313void 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
2318void 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
2323void 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
2328void 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
2333void 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
2338void 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
2343pdf_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
2350pdf_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
2357int 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
2362int 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
2367float 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
2372const 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
2377const 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
2382const 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
2387fz_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
2392fz_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
2397int 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
2402int 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
2407float 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
2412const 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
2417const 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
2422const 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
2427fz_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
2432fz_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