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