1 #include "mupdf/fitz.h"
2 #include "mupdf/pdf.h"
3 
4 #include <string.h>
5 
6 /* Must be kept in sync with definitions in pdf_util.js */
7 enum
8 {
9 	Display_Visible,
10 	Display_Hidden,
11 	Display_NoPrint,
12 	Display_NoView
13 };
14 
15 enum
16 {
17 	SigFlag_SignaturesExist = 1,
18 	SigFlag_AppendOnly = 2
19 };
20 
pdf_field_value(fz_context * ctx,pdf_obj * field)21 const char *pdf_field_value(fz_context *ctx, pdf_obj *field)
22 {
23 	pdf_obj *v = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
24 	if (pdf_is_name(ctx, v))
25 		return pdf_to_name(ctx, v);
26 	if (pdf_is_stream(ctx, v))
27 	{
28 		// FIXME: pdf_dict_put_inheritable...
29 		char *str = pdf_new_utf8_from_pdf_stream_obj(ctx, v);
30 		fz_try(ctx)
31 			pdf_dict_put_text_string(ctx, field, PDF_NAME(V), str);
32 		fz_always(ctx)
33 			fz_free(ctx, str);
34 		fz_catch(ctx)
35 			fz_rethrow(ctx);
36 		v = pdf_dict_get(ctx, field, PDF_NAME(V));
37 	}
38 	return pdf_to_text_string(ctx, v);
39 }
40 
pdf_field_flags(fz_context * ctx,pdf_obj * obj)41 int pdf_field_flags(fz_context *ctx, pdf_obj *obj)
42 {
43 	return pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, obj, PDF_NAME(Ff)));
44 }
45 
pdf_field_type(fz_context * ctx,pdf_obj * obj)46 int pdf_field_type(fz_context *ctx, pdf_obj *obj)
47 {
48 	pdf_obj *type = pdf_dict_get_inheritable(ctx, obj, PDF_NAME(FT));
49 	int flags = pdf_field_flags(ctx, obj);
50 	if (pdf_name_eq(ctx, type, PDF_NAME(Btn)))
51 	{
52 		if (flags & PDF_BTN_FIELD_IS_PUSHBUTTON)
53 			return PDF_WIDGET_TYPE_BUTTON;
54 		else if (flags & PDF_BTN_FIELD_IS_RADIO)
55 			return PDF_WIDGET_TYPE_RADIOBUTTON;
56 		else
57 			return PDF_WIDGET_TYPE_CHECKBOX;
58 	}
59 	else if (pdf_name_eq(ctx, type, PDF_NAME(Tx)))
60 		return PDF_WIDGET_TYPE_TEXT;
61 	else if (pdf_name_eq(ctx, type, PDF_NAME(Ch)))
62 	{
63 		if (flags & PDF_CH_FIELD_IS_COMBO)
64 			return PDF_WIDGET_TYPE_COMBOBOX;
65 		else
66 			return PDF_WIDGET_TYPE_LISTBOX;
67 	}
68 	else if (pdf_name_eq(ctx, type, PDF_NAME(Sig)))
69 		return PDF_WIDGET_TYPE_SIGNATURE;
70 	else
71 		return PDF_WIDGET_TYPE_BUTTON;
72 }
73 
pdf_field_dirties_document(fz_context * ctx,pdf_document * doc,pdf_obj * field)74 static int pdf_field_dirties_document(fz_context *ctx, pdf_document *doc, pdf_obj *field)
75 {
76 	int ff = pdf_field_flags(ctx, field);
77 	if (ff & PDF_FIELD_IS_NO_EXPORT) return 0;
78 	if (ff & PDF_FIELD_IS_READ_ONLY) return 0;
79 	return 1;
80 }
81 
82 /* Find the point in a field hierarchy where all descendants
83  * share the same name */
find_head_of_field_group(fz_context * ctx,pdf_obj * obj)84 static pdf_obj *find_head_of_field_group(fz_context *ctx, pdf_obj *obj)
85 {
86 	if (obj == NULL || pdf_dict_get(ctx, obj, PDF_NAME(T)))
87 		return obj;
88 	else
89 		return find_head_of_field_group(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Parent)));
90 }
91 
pdf_field_mark_dirty(fz_context * ctx,pdf_obj * field)92 static void pdf_field_mark_dirty(fz_context *ctx, pdf_obj *field)
93 {
94 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
95 	if (kids)
96 	{
97 		int i, n = pdf_array_len(ctx, kids);
98 		for (i = 0; i < n; i++)
99 			pdf_field_mark_dirty(ctx, pdf_array_get(ctx, kids, i));
100 	}
101 	pdf_dirty_obj(ctx, field);
102 }
103 
update_field_value(fz_context * ctx,pdf_document * doc,pdf_obj * obj,const char * text)104 static void update_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *obj, const char *text)
105 {
106 	pdf_obj *grp;
107 
108 	if (!text)
109 		text = "";
110 
111 	/* All fields of the same name should be updated, so
112 	 * set the value at the head of the group */
113 	grp = find_head_of_field_group(ctx, obj);
114 	if (grp)
115 		obj = grp;
116 
117 	pdf_dict_put_text_string(ctx, obj, PDF_NAME(V), text);
118 
119 	pdf_field_mark_dirty(ctx, obj);
120 }
121 
122 static pdf_obj *
lookup_field_sub(fz_context * ctx,pdf_obj * dict,const char * str)123 lookup_field_sub(fz_context *ctx, pdf_obj *dict, const char *str)
124 {
125 	pdf_obj *kids;
126 	pdf_obj *name;
127 
128 	name = pdf_dict_get(ctx, dict, PDF_NAME(T));
129 
130 	/* If we have a name, check it matches. If it matches, consume that
131 	 * portion of str. If not, exit. */
132 	if (name)
133 	{
134 		const char *match = pdf_to_text_string(ctx, name);
135 		const char *e = str;
136 		size_t len;
137 		while (*e && *e != '.')
138 			e++;
139 		len = e-str;
140 		if (strncmp(str, match, len) != 0 || (match[len] != 0 && match[len] != '.'))
141 			/* name doesn't match. */
142 			return NULL;
143 		str = e;
144 		if (*str == '.')
145 			str++;
146 	}
147 
148 	/* If there is a kids array, walk those looking for the appropriate one. */
149 	kids = pdf_dict_get(ctx, dict, PDF_NAME(Kids));
150 	if (kids)
151 		return pdf_lookup_field(ctx, kids, str);
152 
153 	/* No Kids, so we're a terminal node. We accept it as the match if we've
154 	 * exhausted the match string. */
155 	if (*str == 0)
156 		return dict;
157 
158 	return NULL;
159 }
160 
161 pdf_obj *
pdf_lookup_field(fz_context * ctx,pdf_obj * arr,const char * str)162 pdf_lookup_field(fz_context *ctx, pdf_obj *arr, const char *str)
163 {
164 	int len = pdf_array_len(ctx, arr);
165 	int i;
166 	pdf_obj *found = NULL;
167 	pdf_obj *k = NULL;
168 
169 	fz_var(k);
170 
171 	fz_try(ctx)
172 	{
173 		for (i = 0; found == NULL && i < len; i++)
174 		{
175 			k = pdf_array_get(ctx, arr, i);
176 
177 			if (!pdf_mark_obj(ctx, k))
178 			{
179 				found = lookup_field_sub(ctx, k, str);
180 				pdf_unmark_obj(ctx, k);
181 				k = NULL;
182 			}
183 		}
184 	}
185 	fz_always(ctx)
186 	{
187 		pdf_unmark_obj(ctx, k);
188 	}
189 	fz_catch(ctx)
190 		fz_rethrow(ctx);
191 
192 	return found;
193 }
194 
reset_form_field(fz_context * ctx,pdf_document * doc,pdf_obj * field)195 static void reset_form_field(fz_context *ctx, pdf_document *doc, pdf_obj *field)
196 {
197 	/* Set V to DV wherever DV is present, and delete V where DV is not.
198 	 * FIXME: we assume for now that V has not been set unequal
199 	 * to DV higher in the hierarchy than "field".
200 	 *
201 	 * At the bottom of the hierarchy we may find widget annotations
202 	 * that aren't also fields, but DV and V will not be present in their
203 	 * dictionaries, and attempts to remove V will be harmless. */
204 	pdf_obj *dv = pdf_dict_get(ctx, field, PDF_NAME(DV));
205 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
206 
207 	if (dv)
208 		pdf_dict_put(ctx, field, PDF_NAME(V), dv);
209 	else
210 		pdf_dict_del(ctx, field, PDF_NAME(V));
211 
212 	if (kids == NULL)
213 	{
214 		/* The leaves of the tree are widget annotations
215 		 * In some cases we need to update the appearance state;
216 		 * in others we need to mark the field as dirty so that
217 		 * the appearance stream will be regenerated. */
218 		switch (pdf_field_type(ctx, field))
219 		{
220 		case PDF_WIDGET_TYPE_CHECKBOX:
221 		case PDF_WIDGET_TYPE_RADIOBUTTON:
222 			{
223 				pdf_obj *leafv = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
224 				if (!leafv)
225 					leafv = PDF_NAME(Off);
226 				pdf_dict_put(ctx, field, PDF_NAME(AS), leafv);
227 			}
228 			pdf_field_mark_dirty(ctx, field);
229 			break;
230 
231 		case PDF_WIDGET_TYPE_BUTTON:
232 		case PDF_WIDGET_TYPE_SIGNATURE:
233 			/* Pushbuttons and signatures have no value to reset. */
234 			break;
235 
236 		default:
237 			pdf_field_mark_dirty(ctx, field);
238 			break;
239 		}
240 	}
241 
242 	if (pdf_field_dirties_document(ctx, doc, field))
243 		doc->dirty = 1;
244 }
245 
pdf_field_reset(fz_context * ctx,pdf_document * doc,pdf_obj * field)246 void pdf_field_reset(fz_context *ctx, pdf_document *doc, pdf_obj *field)
247 {
248 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
249 
250 	reset_form_field(ctx, doc, field);
251 
252 	if (kids)
253 	{
254 		int i, n = pdf_array_len(ctx, kids);
255 
256 		for (i = 0; i < n; i++)
257 			pdf_field_reset(ctx, doc, pdf_array_get(ctx, kids, i));
258 	}
259 }
260 
add_field_hierarchy_to_array(fz_context * ctx,pdf_obj * array,pdf_obj * field)261 static void add_field_hierarchy_to_array(fz_context *ctx, pdf_obj *array, pdf_obj *field)
262 {
263 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
264 	pdf_obj *exclude = pdf_dict_get(ctx, field, PDF_NAME(Exclude));
265 
266 	if (exclude)
267 		return;
268 
269 	pdf_array_push(ctx, array, field);
270 
271 	if (kids)
272 	{
273 		int i, n = pdf_array_len(ctx, kids);
274 
275 		for (i = 0; i < n; i++)
276 			add_field_hierarchy_to_array(ctx, array, pdf_array_get(ctx, kids, i));
277 	}
278 }
279 
280 /*
281 	When resetting or submitting a form, the fields to act upon are defined
282 	by an array of either field references or field names, plus a flag determining
283 	whether to act upon the fields in the array, or all fields other than those in
284 	the array. specified_fields interprets this information and produces the array
285 	of fields to be acted upon.
286 */
specified_fields(fz_context * ctx,pdf_document * doc,pdf_obj * fields,int exclude)287 static pdf_obj *specified_fields(fz_context *ctx, pdf_document *doc, pdf_obj *fields, int exclude)
288 {
289 	pdf_obj *form = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(Fields), NULL);
290 	int i, n;
291 	pdf_obj *result = pdf_new_array(ctx, doc, 0);
292 
293 	fz_try(ctx)
294 	{
295 		/* The 'fields' array not being present signals that all fields
296 		* should be acted upon, so handle it using the exclude case - excluding none */
297 		if (exclude || !fields)
298 		{
299 			/* mark the fields we don't want to act upon */
300 			n = pdf_array_len(ctx, fields);
301 			for (i = 0; i < n; i++)
302 			{
303 				pdf_obj *field = pdf_array_get(ctx, fields, i);
304 
305 				if (pdf_is_string(ctx, field))
306 					field = pdf_lookup_field(ctx, form, pdf_to_str_buf(ctx, field));
307 
308 				if (field)
309 					pdf_dict_put(ctx, field, PDF_NAME(Exclude), PDF_NULL);
310 			}
311 
312 			/* Act upon all unmarked fields */
313 			n = pdf_array_len(ctx, form);
314 
315 			for (i = 0; i < n; i++)
316 				add_field_hierarchy_to_array(ctx, result, pdf_array_get(ctx, form, i));
317 
318 			/* Unmark the marked fields */
319 			n = pdf_array_len(ctx, fields);
320 
321 			for (i = 0; i < n; i++)
322 			{
323 				pdf_obj *field = pdf_array_get(ctx, fields, i);
324 
325 				if (pdf_is_string(ctx, field))
326 					field = pdf_lookup_field(ctx, form, pdf_to_str_buf(ctx, field));
327 
328 				if (field)
329 					pdf_dict_del(ctx, field, PDF_NAME(Exclude));
330 			}
331 		}
332 		else
333 		{
334 			n = pdf_array_len(ctx, fields);
335 
336 			for (i = 0; i < n; i++)
337 			{
338 				pdf_obj *field = pdf_array_get(ctx, fields, i);
339 
340 				if (pdf_is_string(ctx, field))
341 					field = pdf_lookup_field(ctx, form, pdf_to_str_buf(ctx, field));
342 
343 				if (field)
344 					add_field_hierarchy_to_array(ctx, result, field);
345 			}
346 		}
347 	}
348 	fz_catch(ctx)
349 	{
350 		pdf_drop_obj(ctx, result);
351 		fz_rethrow(ctx);
352 	}
353 
354 	return result;
355 }
356 
pdf_reset_form(fz_context * ctx,pdf_document * doc,pdf_obj * fields,int exclude)357 void pdf_reset_form(fz_context *ctx, pdf_document *doc, pdf_obj *fields, int exclude)
358 {
359 	pdf_obj *sfields = specified_fields(ctx, doc, fields, exclude);
360 	fz_try(ctx)
361 	{
362 		int i, n = pdf_array_len(ctx, sfields);
363 		for (i = 0; i < n; i++)
364 			reset_form_field(ctx, doc, pdf_array_get(ctx, sfields, i));
365 		doc->recalculate = 1;
366 	}
367 	fz_always(ctx)
368 		pdf_drop_obj(ctx, sfields);
369 	fz_catch(ctx)
370 		fz_rethrow(ctx);
371 }
372 
set_check(fz_context * ctx,pdf_document * doc,pdf_obj * chk,pdf_obj * name)373 static void set_check(fz_context *ctx, pdf_document *doc, pdf_obj *chk, pdf_obj *name)
374 {
375 	pdf_obj *n = pdf_dict_getp(ctx, chk, "AP/N");
376 	pdf_obj *val;
377 
378 	/* If name is a possible value of this check
379 	* box then use it, otherwise use "Off" */
380 	if (pdf_dict_get(ctx, n, name))
381 		val = name;
382 	else
383 		val = PDF_NAME(Off);
384 
385 	pdf_dict_put(ctx, chk, PDF_NAME(AS), val);
386 }
387 
388 /* Set the values of all fields in a group defined by a node
389  * in the hierarchy */
set_check_grp(fz_context * ctx,pdf_document * doc,pdf_obj * grp,pdf_obj * val)390 static void set_check_grp(fz_context *ctx, pdf_document *doc, pdf_obj *grp, pdf_obj *val)
391 {
392 	pdf_obj *kids = pdf_dict_get(ctx, grp, PDF_NAME(Kids));
393 
394 	if (kids == NULL)
395 	{
396 		set_check(ctx, doc, grp, val);
397 	}
398 	else
399 	{
400 		int i, n = pdf_array_len(ctx, kids);
401 
402 		for (i = 0; i < n; i++)
403 			set_check_grp(ctx, doc, pdf_array_get(ctx, kids, i), val);
404 	}
405 }
406 
pdf_calculate_form(fz_context * ctx,pdf_document * doc)407 void pdf_calculate_form(fz_context *ctx, pdf_document *doc)
408 {
409 	if (doc->js)
410 	{
411 		fz_try(ctx)
412 		{
413 			pdf_obj *co = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/CO");
414 			int i, n = pdf_array_len(ctx, co);
415 			for (i = 0; i < n; i++)
416 			{
417 				pdf_obj *field = pdf_array_get(ctx, co, i);
418 				pdf_field_event_calculate(ctx, doc, field);
419 			}
420 		}
421 		fz_always(ctx)
422 			doc->recalculate = 0;
423 		fz_catch(ctx)
424 			fz_rethrow(ctx);
425 	}
426 }
427 
find_on_state(fz_context * ctx,pdf_obj * dict)428 static pdf_obj *find_on_state(fz_context *ctx, pdf_obj *dict)
429 {
430 	int i, n = pdf_dict_len(ctx, dict);
431 	for (i = 0; i < n; ++i)
432 	{
433 		pdf_obj *key = pdf_dict_get_key(ctx, dict, i);
434 		if (key != PDF_NAME(Off))
435 			return key;
436 	}
437 	return NULL;
438 }
439 
pdf_button_field_on_state(fz_context * ctx,pdf_obj * field)440 pdf_obj *pdf_button_field_on_state(fz_context *ctx, pdf_obj *field)
441 {
442 	pdf_obj *ap = pdf_dict_get(ctx, field, PDF_NAME(AP));
443 	pdf_obj *on = find_on_state(ctx, pdf_dict_get(ctx, ap, PDF_NAME(N)));
444 	if (!on) on = find_on_state(ctx, pdf_dict_get(ctx, ap, PDF_NAME(D)));
445 	if (!on) on = PDF_NAME(Yes);
446 	return on;
447 }
448 
toggle_check_box(fz_context * ctx,pdf_document * doc,pdf_obj * field)449 static void toggle_check_box(fz_context *ctx, pdf_document *doc, pdf_obj *field)
450 {
451 	int ff = pdf_field_flags(ctx, field);
452 	int is_radio = (ff & PDF_BTN_FIELD_IS_RADIO);
453 	int is_no_toggle_to_off = (ff & PDF_BTN_FIELD_IS_NO_TOGGLE_TO_OFF);
454 	pdf_obj *grp, *as, *val;
455 
456 	grp = find_head_of_field_group(ctx, field);
457 	if (!grp)
458 		grp = field;
459 
460 	/* TODO: check V value as well as or instead of AS? */
461 	as = pdf_dict_get(ctx, field, PDF_NAME(AS));
462 	if (as && as != PDF_NAME(Off))
463 	{
464 		if (is_radio && is_no_toggle_to_off)
465 			return;
466 		val = PDF_NAME(Off);
467 	}
468 	else
469 	{
470 		val = pdf_button_field_on_state(ctx, field);
471 	}
472 
473 	pdf_dict_put(ctx, grp, PDF_NAME(V), val);
474 	set_check_grp(ctx, doc, grp, val);
475 	doc->recalculate = 1;
476 }
477 
pdf_has_unsaved_changes(fz_context * ctx,pdf_document * doc)478 int pdf_has_unsaved_changes(fz_context *ctx, pdf_document *doc)
479 {
480 	return doc->dirty;
481 }
482 
pdf_was_repaired(fz_context * ctx,pdf_document * doc)483 int pdf_was_repaired(fz_context *ctx, pdf_document *doc)
484 {
485 	return doc->repair_attempted;
486 }
487 
pdf_toggle_widget(fz_context * ctx,pdf_widget * widget)488 int pdf_toggle_widget(fz_context *ctx, pdf_widget *widget)
489 {
490 	switch (pdf_widget_type(ctx, widget))
491 	{
492 	default:
493 		return 0;
494 	case PDF_WIDGET_TYPE_CHECKBOX:
495 	case PDF_WIDGET_TYPE_RADIOBUTTON:
496 		toggle_check_box(ctx, widget->page->doc, widget->obj);
497 		return 1;
498 	}
499 	return 0;
500 }
501 
502 int
pdf_update_page(fz_context * ctx,pdf_page * page)503 pdf_update_page(fz_context *ctx, pdf_page *page)
504 {
505 	pdf_annot *annot;
506 	pdf_widget *widget;
507 	int changed = 0;
508 
509 	if (page->doc->recalculate)
510 		pdf_calculate_form(ctx, page->doc);
511 
512 	for (annot = page->annots; annot; annot = annot->next)
513 		if (pdf_update_annot(ctx, annot))
514 			changed = 1;
515 	for (widget = page->widgets; widget; widget = widget->next)
516 		if (pdf_update_annot(ctx, widget))
517 			changed = 1;
518 
519 	return changed;
520 }
521 
pdf_first_widget(fz_context * ctx,pdf_page * page)522 pdf_widget *pdf_first_widget(fz_context *ctx, pdf_page *page)
523 {
524 	return page->widgets;
525 }
526 
pdf_next_widget(fz_context * ctx,pdf_widget * widget)527 pdf_widget *pdf_next_widget(fz_context *ctx, pdf_widget *widget)
528 {
529 	return widget->next;
530 }
531 
pdf_widget_type(fz_context * ctx,pdf_widget * widget)532 enum pdf_widget_type pdf_widget_type(fz_context *ctx, pdf_widget *widget)
533 {
534 	pdf_obj *subtype = pdf_dict_get(ctx, widget->obj, PDF_NAME(Subtype));
535 	if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget)))
536 		return pdf_field_type(ctx, widget->obj);
537 	return PDF_WIDGET_TYPE_BUTTON;
538 }
539 
set_validated_field_value(fz_context * ctx,pdf_document * doc,pdf_obj * field,const char * text,int ignore_trigger_events)540 static int set_validated_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *text, int ignore_trigger_events)
541 {
542 	if (!ignore_trigger_events)
543 	{
544 		if (!pdf_field_event_validate(ctx, doc, field, text))
545 			return 0;
546 	}
547 
548 	if (pdf_field_dirties_document(ctx, doc, field))
549 		doc->dirty = 1;
550 	update_field_value(ctx, doc, field, text);
551 
552 	return 1;
553 }
554 
update_checkbox_selector(fz_context * ctx,pdf_document * doc,pdf_obj * field,const char * val)555 static void update_checkbox_selector(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *val)
556 {
557 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
558 
559 	if (kids)
560 	{
561 		int i, n = pdf_array_len(ctx, kids);
562 
563 		for (i = 0; i < n; i++)
564 			update_checkbox_selector(ctx, doc, pdf_array_get(ctx, kids, i), val);
565 	}
566 	else
567 	{
568 		pdf_obj *n = pdf_dict_getp(ctx, field, "AP/N");
569 		pdf_obj *oval;
570 
571 		if (pdf_dict_gets(ctx, n, val))
572 			oval = pdf_new_name(ctx, val);
573 		else
574 			oval = PDF_NAME(Off);
575 		pdf_dict_put_drop(ctx, field, PDF_NAME(AS), oval);
576 	}
577 }
578 
set_checkbox_value(fz_context * ctx,pdf_document * doc,pdf_obj * field,const char * val)579 static int set_checkbox_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *val)
580 {
581 	update_checkbox_selector(ctx, doc, field, val);
582 	update_field_value(ctx, doc, field, val);
583 	return 1;
584 }
585 
pdf_set_field_value(fz_context * ctx,pdf_document * doc,pdf_obj * field,const char * text,int ignore_trigger_events)586 int pdf_set_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *text, int ignore_trigger_events)
587 {
588 	int accepted = 0;
589 
590 	switch (pdf_field_type(ctx, field))
591 	{
592 	case PDF_WIDGET_TYPE_TEXT:
593 	case PDF_WIDGET_TYPE_COMBOBOX:
594 	case PDF_WIDGET_TYPE_LISTBOX:
595 		accepted = set_validated_field_value(ctx, doc, field, text, ignore_trigger_events);
596 		break;
597 
598 	case PDF_WIDGET_TYPE_CHECKBOX:
599 	case PDF_WIDGET_TYPE_RADIOBUTTON:
600 		accepted = set_checkbox_value(ctx, doc, field, text);
601 		break;
602 
603 	default:
604 		update_field_value(ctx, doc, field, text);
605 		accepted = 1;
606 		break;
607 	}
608 
609 	if (!ignore_trigger_events)
610 		doc->recalculate = 1;
611 
612 	return accepted;
613 }
614 
pdf_field_border_style(fz_context * ctx,pdf_obj * field)615 char *pdf_field_border_style(fz_context *ctx, pdf_obj *field)
616 {
617 	const char *bs = pdf_to_name(ctx, pdf_dict_getl(ctx, field, PDF_NAME(BS), PDF_NAME(S), NULL));
618 	switch (*bs)
619 	{
620 	case 'S': return "Solid";
621 	case 'D': return "Dashed";
622 	case 'B': return "Beveled";
623 	case 'I': return "Inset";
624 	case 'U': return "Underline";
625 	}
626 	return "Solid";
627 }
628 
pdf_field_set_border_style(fz_context * ctx,pdf_obj * field,const char * text)629 void pdf_field_set_border_style(fz_context *ctx, pdf_obj *field, const char *text)
630 {
631 	pdf_obj *val;
632 
633 	if (!strcmp(text, "Solid"))
634 		val = PDF_NAME(S);
635 	else if (!strcmp(text, "Dashed"))
636 		val = PDF_NAME(D);
637 	else if (!strcmp(text, "Beveled"))
638 		val = PDF_NAME(B);
639 	else if (!strcmp(text, "Inset"))
640 		val = PDF_NAME(I);
641 	else if (!strcmp(text, "Underline"))
642 		val = PDF_NAME(U);
643 	else
644 		return;
645 
646 	pdf_dict_putl_drop(ctx, field, val, PDF_NAME(BS), PDF_NAME(S), NULL);
647 	pdf_field_mark_dirty(ctx, field);
648 }
649 
pdf_field_set_button_caption(fz_context * ctx,pdf_obj * field,const char * text)650 void pdf_field_set_button_caption(fz_context *ctx, pdf_obj *field, const char *text)
651 {
652 	if (pdf_field_type(ctx, field) == PDF_WIDGET_TYPE_BUTTON)
653 	{
654 		pdf_obj *val = pdf_new_text_string(ctx, text);
655 		pdf_dict_putl_drop(ctx, field, val, PDF_NAME(MK), PDF_NAME(CA), NULL);
656 		pdf_field_mark_dirty(ctx, field);
657 	}
658 }
659 
pdf_field_display(fz_context * ctx,pdf_obj * field)660 int pdf_field_display(fz_context *ctx, pdf_obj *field)
661 {
662 	pdf_obj *kids;
663 	int f, res = Display_Visible;
664 
665 	/* Base response on first of children. Not ideal,
666 	 * but not clear how to handle children with
667 	 * differing values */
668 	while ((kids = pdf_dict_get(ctx, field, PDF_NAME(Kids))) != NULL)
669 		field = pdf_array_get(ctx, kids, 0);
670 
671 	f = pdf_dict_get_int(ctx, field, PDF_NAME(F));
672 
673 	if (f & PDF_ANNOT_IS_HIDDEN)
674 	{
675 		res = Display_Hidden;
676 	}
677 	else if (f & PDF_ANNOT_IS_PRINT)
678 	{
679 		if (f & PDF_ANNOT_IS_NO_VIEW)
680 			res = Display_NoView;
681 	}
682 	else
683 	{
684 		if (f & PDF_ANNOT_IS_NO_VIEW)
685 			res = Display_Hidden;
686 		else
687 			res = Display_NoPrint;
688 	}
689 
690 	return res;
691 }
692 
693 /*
694  * get the field name in a char buffer that has spare room to
695  * add more characters at the end.
696  */
get_field_name(fz_context * ctx,pdf_obj * field,int spare)697 static char *get_field_name(fz_context *ctx, pdf_obj *field, int spare)
698 {
699 	char *res = NULL;
700 	pdf_obj *parent;
701 	const char *lname;
702 	int llen;
703 
704 	fz_try(ctx)
705 	{
706 		if (pdf_mark_obj(ctx, field))
707 			fz_throw(ctx, FZ_ERROR_GENERIC, "Cycle in field parents");
708 
709 		parent = pdf_dict_get(ctx, field, PDF_NAME(Parent));
710 		lname = pdf_dict_get_text_string(ctx, field, PDF_NAME(T));
711 		llen = (int)strlen(lname);
712 
713 		/*
714 		 * If we found a name at this point in the field hierarchy
715 		 * then we'll need extra space for it and a dot
716 		 */
717 		if (llen)
718 			spare += llen+1;
719 
720 		if (parent)
721 		{
722 			res = get_field_name(ctx, parent, spare);
723 		}
724 		else
725 		{
726 			res = Memento_label(fz_malloc(ctx, spare+1), "form_field_name");
727 			res[0] = 0;
728 		}
729 
730 		if (llen)
731 		{
732 			if (res[0])
733 				strcat(res, ".");
734 
735 			strcat(res, lname);
736 		}
737 	}
738 	fz_always(ctx)
739 		pdf_unmark_obj(ctx, field);
740 	fz_catch(ctx)
741 		fz_rethrow(ctx);
742 
743 	return res;
744 }
745 
pdf_field_name(fz_context * ctx,pdf_obj * field)746 char *pdf_field_name(fz_context *ctx, pdf_obj *field)
747 {
748 	return get_field_name(ctx, field, 0);
749 }
750 
pdf_field_label(fz_context * ctx,pdf_obj * field)751 const char *pdf_field_label(fz_context *ctx, pdf_obj *field)
752 {
753 	pdf_obj *label = pdf_dict_get_inheritable(ctx, field, PDF_NAME(TU));
754 	if (!label)
755 		label = pdf_dict_get_inheritable(ctx, field, PDF_NAME(T));
756 	if (label)
757 		return pdf_to_text_string(ctx, label);
758 	return "Unnamed";
759 }
760 
pdf_field_set_display(fz_context * ctx,pdf_obj * field,int d)761 void pdf_field_set_display(fz_context *ctx, pdf_obj *field, int d)
762 {
763 	pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
764 
765 	if (!kids)
766 	{
767 		int mask = (PDF_ANNOT_IS_HIDDEN|PDF_ANNOT_IS_PRINT|PDF_ANNOT_IS_NO_VIEW);
768 		int f = pdf_dict_get_int(ctx, field, PDF_NAME(F)) & ~mask;
769 		pdf_obj *fo;
770 
771 		switch (d)
772 		{
773 		case Display_Visible:
774 			f |= PDF_ANNOT_IS_PRINT;
775 			break;
776 		case Display_Hidden:
777 			f |= PDF_ANNOT_IS_HIDDEN;
778 			break;
779 		case Display_NoView:
780 			f |= (PDF_ANNOT_IS_PRINT|PDF_ANNOT_IS_NO_VIEW);
781 			break;
782 		case Display_NoPrint:
783 			break;
784 		}
785 
786 		fo = pdf_new_int(ctx, f);
787 		pdf_dict_put_drop(ctx, field, PDF_NAME(F), fo);
788 	}
789 	else
790 	{
791 		int i, n = pdf_array_len(ctx, kids);
792 
793 		for (i = 0; i < n; i++)
794 			pdf_field_set_display(ctx, pdf_array_get(ctx, kids, i), d);
795 	}
796 }
797 
pdf_field_set_fill_color(fz_context * ctx,pdf_obj * field,pdf_obj * col)798 void pdf_field_set_fill_color(fz_context *ctx, pdf_obj *field, pdf_obj *col)
799 {
800 	/* col == NULL mean transparent, but we can simply pass it on as with
801 	 * non-NULL values because pdf_dict_putp interprets a NULL value as
802 	 * delete */
803 	pdf_dict_putl(ctx, field, col, PDF_NAME(MK), PDF_NAME(BG), NULL);
804 	pdf_field_mark_dirty(ctx, field);
805 }
806 
pdf_field_set_text_color(fz_context * ctx,pdf_obj * field,pdf_obj * col)807 void pdf_field_set_text_color(fz_context *ctx, pdf_obj *field, pdf_obj *col)
808 {
809 	char buf[100];
810 	const char *font;
811 	float size, color[3], black;
812 	const char *da = pdf_to_str_buf(ctx, pdf_dict_get_inheritable(ctx, field, PDF_NAME(DA)));
813 
814 	pdf_parse_default_appearance(ctx, da, &font, &size, color);
815 
816 	switch (pdf_array_len(ctx, col))
817 	{
818 	default:
819 		color[0] = color[1] = color[2] = 0;
820 		break;
821 	case 1:
822 		color[0] = color[1] = color[2] = pdf_array_get_real(ctx, col, 0);
823 		break;
824 	case 3:
825 		color[0] = pdf_array_get_real(ctx, col, 0);
826 		color[1] = pdf_array_get_real(ctx, col, 1);
827 		color[2] = pdf_array_get_real(ctx, col, 2);
828 		break;
829 	case 4:
830 		black = pdf_array_get_real(ctx, col, 3);
831 		color[0] = 1 - fz_min(1, pdf_array_get_real(ctx, col, 0) + black);
832 		color[1] = 1 - fz_min(1, pdf_array_get_real(ctx, col, 1) + black);
833 		color[2] = 1 - fz_min(1, pdf_array_get_real(ctx, col, 2) + black);
834 		break;
835 	}
836 
837 	pdf_print_default_appearance(ctx, buf, sizeof buf, font, size, color);
838 	pdf_dict_put_string(ctx, field, PDF_NAME(DA), buf, strlen(buf));
839 	pdf_field_mark_dirty(ctx, field);
840 }
841 
842 pdf_widget *
pdf_keep_widget(fz_context * ctx,pdf_widget * widget)843 pdf_keep_widget(fz_context *ctx, pdf_widget *widget)
844 {
845 	return pdf_keep_annot(ctx, widget);
846 }
847 
848 void
pdf_drop_widget(fz_context * ctx,pdf_widget * widget)849 pdf_drop_widget(fz_context *ctx, pdf_widget *widget)
850 {
851 	pdf_drop_annot(ctx, widget);
852 }
853 
854 void
pdf_drop_widgets(fz_context * ctx,pdf_widget * widget)855 pdf_drop_widgets(fz_context *ctx, pdf_widget *widget)
856 {
857 	while (widget)
858 	{
859 		pdf_widget *next = widget->next;
860 		pdf_drop_widget(ctx, widget);
861 		widget = next;
862 	}
863 }
864 
865 pdf_widget *
pdf_create_signature_widget(fz_context * ctx,pdf_page * page,char * name)866 pdf_create_signature_widget(fz_context *ctx, pdf_page *page, char *name)
867 {
868 	fz_rect rect = { 12, 12, 12+100, 12+50 };
869 	pdf_annot *annot = pdf_create_annot_raw(ctx, page, PDF_ANNOT_WIDGET);
870 	fz_try(ctx)
871 	{
872 		pdf_obj *obj = annot->obj;
873 		pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, page->doc), PDF_NAME(Root));
874 		pdf_obj *acroform = pdf_dict_get(ctx, root, PDF_NAME(AcroForm));
875 		pdf_obj *fields, *lock;
876 		if (!acroform)
877 		{
878 			acroform = pdf_new_dict(ctx, page->doc, 1);
879 			pdf_dict_put_drop(ctx, root, PDF_NAME(AcroForm), acroform);
880 		}
881 		fields = pdf_dict_get(ctx, acroform, PDF_NAME(Fields));
882 		if (!fields)
883 		{
884 			fields = pdf_new_array(ctx, page->doc, 1);
885 			pdf_dict_put_drop(ctx, acroform, PDF_NAME(Fields), fields);
886 		}
887 		pdf_set_annot_rect(ctx, annot, rect);
888 		pdf_dict_put(ctx, obj, PDF_NAME(FT), PDF_NAME(Sig));
889 		pdf_dict_put_int(ctx, obj, PDF_NAME(F), PDF_ANNOT_IS_PRINT);
890 		pdf_dict_put_text_string(ctx, obj, PDF_NAME(DA), "/Helv 0 Tf 0 g");
891 		pdf_dict_put_text_string(ctx, obj, PDF_NAME(T), name);
892 		pdf_array_push(ctx, fields, obj);
893 		lock = pdf_dict_put_dict(ctx, obj, PDF_NAME(Lock), 1);
894 		pdf_dict_put(ctx, lock, PDF_NAME(Action), PDF_NAME(All));
895 	}
896 	fz_catch(ctx)
897 	{
898 		pdf_delete_annot(ctx, page, annot);
899 	}
900 	return (pdf_widget *)annot;
901 }
902 
903 fz_rect
pdf_bound_widget(fz_context * ctx,pdf_widget * widget)904 pdf_bound_widget(fz_context *ctx, pdf_widget *widget)
905 {
906 	return pdf_bound_annot(ctx, widget);
907 }
908 
909 int
pdf_update_widget(fz_context * ctx,pdf_widget * widget)910 pdf_update_widget(fz_context *ctx, pdf_widget *widget)
911 {
912 	return pdf_update_annot(ctx, widget);
913 }
914 
pdf_text_widget_max_len(fz_context * ctx,pdf_widget * tw)915 int pdf_text_widget_max_len(fz_context *ctx, pdf_widget *tw)
916 {
917 	pdf_annot *annot = (pdf_annot *)tw;
918 	return pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(MaxLen)));
919 }
920 
pdf_text_widget_format(fz_context * ctx,pdf_widget * tw)921 int pdf_text_widget_format(fz_context *ctx, pdf_widget *tw)
922 {
923 	pdf_annot *annot = (pdf_annot *)tw;
924 	int type = PDF_WIDGET_TX_FORMAT_NONE;
925 	pdf_obj *js = pdf_dict_getl(ctx, annot->obj, PDF_NAME(AA), PDF_NAME(F), PDF_NAME(JS), NULL);
926 	if (js)
927 	{
928 		char *code = pdf_load_stream_or_string_as_utf8(ctx, js);
929 		if (strstr(code, "AFNumber_Format"))
930 			type = PDF_WIDGET_TX_FORMAT_NUMBER;
931 		else if (strstr(code, "AFSpecial_Format"))
932 			type = PDF_WIDGET_TX_FORMAT_SPECIAL;
933 		else if (strstr(code, "AFDate_FormatEx"))
934 			type = PDF_WIDGET_TX_FORMAT_DATE;
935 		else if (strstr(code, "AFTime_FormatEx"))
936 			type = PDF_WIDGET_TX_FORMAT_TIME;
937 		fz_free(ctx, code);
938 	}
939 
940 	return type;
941 }
942 
pdf_set_text_field_value(fz_context * ctx,pdf_widget * widget,const char * new_value)943 int pdf_set_text_field_value(fz_context *ctx, pdf_widget *widget, const char *new_value)
944 {
945 	pdf_document *doc = widget->page->doc;
946 	pdf_keystroke_event event;
947 	char *newChange = NULL;
948 	int rc = 1;
949 
950 	event.newChange = NULL;
951 
952 	fz_var(newChange);
953 	fz_var(event.newChange);
954 	fz_try(ctx)
955 	{
956 		if (!widget->ignore_trigger_events)
957 		{
958 			event.value = pdf_field_value(ctx, widget->obj);
959 			event.change = new_value;
960 			event.selStart = 0;
961 			event.selEnd = (int)strlen(event.value);
962 			event.willCommit = 0;
963 			rc = pdf_field_event_keystroke(ctx, doc, widget->obj, &event);
964 			if (rc)
965 			{
966 				if (event.newChange)
967 					event.value = newChange = event.newChange;
968 				else
969 					event.value = new_value;
970 				event.change = "";
971 				event.selStart = -1;
972 				event.selEnd = -1;
973 				event.willCommit = 1;
974 				event.newChange = NULL;
975 				rc = pdf_field_event_keystroke(ctx, doc, widget->obj, &event);
976 				if (rc)
977 					rc = pdf_set_field_value(ctx, doc, widget->obj, event.value, 0);
978 			}
979 		}
980 		else
981 		{
982 			rc = pdf_set_field_value(ctx, doc, widget->obj, new_value, 1);
983 		}
984 	}
985 	fz_always(ctx)
986 	{
987 		fz_free(ctx, newChange);
988 		fz_free(ctx, event.newChange);
989 	}
990 	fz_catch(ctx)
991 	{
992 		fz_warn(ctx, "could not set widget text");
993 		rc = 0;
994 	}
995 	return rc;
996 }
997 
pdf_set_choice_field_value(fz_context * ctx,pdf_widget * widget,const char * new_value)998 int pdf_set_choice_field_value(fz_context *ctx, pdf_widget *widget, const char *new_value)
999 {
1000 	/* Choice widgets use almost the same keystroke processing as text fields. */
1001 	return pdf_set_text_field_value(ctx, widget, new_value);
1002 }
1003 
pdf_choice_widget_options(fz_context * ctx,pdf_widget * tw,int exportval,const char * opts[])1004 int pdf_choice_widget_options(fz_context *ctx, pdf_widget *tw, int exportval, const char *opts[])
1005 {
1006 	pdf_annot *annot = (pdf_annot *)tw;
1007 	pdf_obj *optarr;
1008 	int i, n, m;
1009 
1010 	optarr = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(Opt));
1011 	n = pdf_array_len(ctx, optarr);
1012 
1013 	if (opts)
1014 	{
1015 		for (i = 0; i < n; i++)
1016 		{
1017 			m = pdf_array_len(ctx, pdf_array_get(ctx, optarr, i));
1018 			/* If it is a two element array, the second item is the one that we want if we want the listing value. */
1019 			if (m == 2)
1020 				if (exportval)
1021 					opts[i] = pdf_array_get_text_string(ctx, pdf_array_get(ctx, optarr, i), 0);
1022 				else
1023 					opts[i] = pdf_array_get_text_string(ctx, pdf_array_get(ctx, optarr, i), 1);
1024 			else
1025 				opts[i] = pdf_array_get_text_string(ctx, optarr, i);
1026 		}
1027 	}
1028 	return n;
1029 }
1030 
pdf_choice_field_option_count(fz_context * ctx,pdf_obj * field)1031 int pdf_choice_field_option_count(fz_context *ctx, pdf_obj *field)
1032 {
1033 	pdf_obj *opt = pdf_dict_get_inheritable(ctx, field, PDF_NAME(Opt));
1034 	return pdf_array_len(ctx, opt);
1035 }
1036 
pdf_choice_field_option(fz_context * ctx,pdf_obj * field,int export,int i)1037 const char *pdf_choice_field_option(fz_context *ctx, pdf_obj *field, int export, int i)
1038 {
1039 	pdf_obj *opt = pdf_dict_get_inheritable(ctx, field, PDF_NAME(Opt));
1040 	pdf_obj *ent = pdf_array_get(ctx, opt, i);
1041 	if (pdf_array_len(ctx, ent) == 2)
1042 		return pdf_array_get_text_string(ctx, ent, export ? 0 : 1);
1043 	else
1044 		return pdf_to_text_string(ctx, ent);
1045 }
1046 
pdf_choice_widget_is_multiselect(fz_context * ctx,pdf_widget * tw)1047 int pdf_choice_widget_is_multiselect(fz_context *ctx, pdf_widget *tw)
1048 {
1049 	pdf_annot *annot = (pdf_annot *)tw;
1050 
1051 	if (!annot) return 0;
1052 
1053 	switch (pdf_field_type(ctx, annot->obj))
1054 	{
1055 	case PDF_WIDGET_TYPE_LISTBOX:
1056 		return (pdf_field_flags(ctx, annot->obj) & PDF_CH_FIELD_IS_MULTI_SELECT) != 0;
1057 	default:
1058 		return 0;
1059 	}
1060 }
1061 
pdf_choice_widget_value(fz_context * ctx,pdf_widget * tw,const char * opts[])1062 int pdf_choice_widget_value(fz_context *ctx, pdf_widget *tw, const char *opts[])
1063 {
1064 	pdf_annot *annot = (pdf_annot *)tw;
1065 	pdf_obj *optarr;
1066 	int i, n;
1067 
1068 	if (!annot)
1069 		return 0;
1070 
1071 	optarr = pdf_dict_get(ctx, annot->obj, PDF_NAME(V));
1072 
1073 	if (pdf_is_string(ctx, optarr))
1074 	{
1075 		if (opts)
1076 			opts[0] = pdf_to_text_string(ctx, optarr);
1077 		return 1;
1078 	}
1079 	else
1080 	{
1081 		n = pdf_array_len(ctx, optarr);
1082 		if (opts)
1083 		{
1084 			for (i = 0; i < n; i++)
1085 			{
1086 				pdf_obj *elem = pdf_array_get(ctx, optarr, i);
1087 				if (pdf_is_array(ctx, elem))
1088 					elem = pdf_array_get(ctx, elem, 1);
1089 				opts[i] = pdf_to_text_string(ctx, elem);
1090 			}
1091 		}
1092 		return n;
1093 	}
1094 }
1095 
pdf_choice_widget_set_value(fz_context * ctx,pdf_widget * tw,int n,const char * opts[])1096 void pdf_choice_widget_set_value(fz_context *ctx, pdf_widget *tw, int n, const char *opts[])
1097 {
1098 	pdf_annot *annot = (pdf_annot *)tw;
1099 	pdf_obj *optarr = NULL, *opt;
1100 	int i;
1101 
1102 	if (!annot)
1103 		return;
1104 
1105 	fz_var(optarr);
1106 	fz_try(ctx)
1107 	{
1108 		if (n != 1)
1109 		{
1110 			optarr = pdf_new_array(ctx, annot->page->doc, n);
1111 
1112 			for (i = 0; i < n; i++)
1113 			{
1114 				opt = pdf_new_text_string(ctx, opts[i]);
1115 				pdf_array_push_drop(ctx, optarr, opt);
1116 			}
1117 
1118 			pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(V), optarr);
1119 		}
1120 		else
1121 		{
1122 			opt = pdf_new_text_string(ctx, opts[0]);
1123 			pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(V), opt);
1124 		}
1125 
1126 		/* FIXME: when n > 1, we should be regenerating the indexes */
1127 		pdf_dict_del(ctx, annot->obj, PDF_NAME(I));
1128 
1129 		pdf_field_mark_dirty(ctx, annot->obj);
1130 		if (pdf_field_dirties_document(ctx, annot->page->doc, annot->obj))
1131 			annot->page->doc->dirty = 1;
1132 	}
1133 	fz_catch(ctx)
1134 	{
1135 		pdf_drop_obj(ctx, optarr);
1136 		fz_rethrow(ctx);
1137 	}
1138 }
1139 
pdf_signature_byte_range(fz_context * ctx,pdf_document * doc,pdf_obj * signature,fz_range * byte_range)1140 int pdf_signature_byte_range(fz_context *ctx, pdf_document *doc, pdf_obj *signature, fz_range *byte_range)
1141 {
1142 	pdf_obj *br = pdf_dict_getl(ctx, signature, PDF_NAME(V), PDF_NAME(ByteRange), NULL);
1143 	int i, n = pdf_array_len(ctx, br)/2;
1144 
1145 	if (byte_range)
1146 	{
1147 		for (i = 0; i < n; i++)
1148 		{
1149 			int64_t offset = pdf_array_get_int(ctx, br, 2*i);
1150 			int length = pdf_array_get_int(ctx, br, 2*i+1);
1151 
1152 			if (offset < 0 || offset > doc->file_size)
1153 				fz_throw(ctx, FZ_ERROR_GENERIC, "offset of signature byte range outside of file");
1154 			else if (length < 0)
1155 				fz_throw(ctx, FZ_ERROR_GENERIC, "length of signature byte range negative");
1156 			else if (offset + length > doc->file_size)
1157 				fz_throw(ctx, FZ_ERROR_GENERIC, "signature byte range extends past end of file");
1158 
1159 			byte_range[i].offset = offset;
1160 			byte_range[i].length = length;
1161 		}
1162 	}
1163 
1164 	return n;
1165 }
1166 
is_white(int c)1167 static int is_white(int c)
1168 {
1169 	return c == '\x00' || c == '\x09' || c == '\x0a' || c == '\x0c' || c == '\x0d' || c == '\x20';
1170 }
1171 
is_hex_or_white(int c)1172 static int is_hex_or_white(int c)
1173 {
1174 	return (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') || is_white(c);
1175 }
1176 
validate_certificate_data(fz_context * ctx,pdf_document * doc,fz_range * hole)1177 static void validate_certificate_data(fz_context *ctx, pdf_document *doc, fz_range *hole)
1178 {
1179 	fz_stream *stm;
1180 	int c;
1181 
1182 	stm = fz_open_range_filter(ctx, doc->file, hole, 1);
1183 	fz_try(ctx)
1184 	{
1185 		while (is_white((c = fz_read_byte(ctx, stm))))
1186 			;
1187 
1188 		if (c == '<')
1189 			c = fz_read_byte(ctx, stm);
1190 
1191 		while (is_hex_or_white((c = fz_read_byte(ctx, stm))))
1192 			;
1193 
1194 		if (c == '>')
1195 			c = fz_read_byte(ctx, stm);
1196 
1197 		while (is_white((c = fz_read_byte(ctx, stm))))
1198 			;
1199 
1200 		if (c != EOF)
1201 			fz_throw(ctx, FZ_ERROR_GENERIC, "signature certificate data contains invalid character");
1202 		if ((size_t)fz_tell(ctx, stm) != hole->length)
1203 			fz_throw(ctx, FZ_ERROR_GENERIC, "premature end of signature certificate data");
1204 	}
1205 	fz_always(ctx)
1206 		fz_drop_stream(ctx, stm);
1207 	fz_catch(ctx)
1208 		fz_rethrow(ctx);
1209 }
1210 
rangecmp(const void * a_,const void * b_)1211 static int rangecmp(const void *a_, const void *b_)
1212 {
1213 	const fz_range *a = (const fz_range *) a_;
1214 	const fz_range *b = (const fz_range *) b_;
1215 	return (int) (a->offset - b->offset);
1216 }
1217 
validate_byte_ranges(fz_context * ctx,pdf_document * doc,fz_range * unsorted,int nranges)1218 static void validate_byte_ranges(fz_context *ctx, pdf_document *doc, fz_range *unsorted, int nranges)
1219 {
1220 	int64_t offset = 0;
1221 	fz_range *sorted;
1222 	int i;
1223 
1224 	sorted = fz_calloc(ctx, nranges, sizeof(*sorted));
1225 	memcpy(sorted, unsorted, nranges * sizeof(*sorted));
1226 	qsort(sorted, nranges, sizeof(*sorted), rangecmp);
1227 
1228 	fz_try(ctx)
1229 	{
1230 		offset = 0;
1231 
1232 		for (i = 0; i < nranges; i++)
1233 		{
1234 			if (sorted[i].offset > offset)
1235 			{
1236 				fz_range hole;
1237 
1238 				hole.offset = offset;
1239 				hole.length = sorted[i].offset - offset;
1240 
1241 				validate_certificate_data(ctx, doc, &hole);
1242 			}
1243 
1244 			offset = fz_maxi64(offset, sorted[i].offset + sorted[i].length);
1245 		}
1246 	}
1247 	fz_always(ctx)
1248 		fz_free(ctx, sorted);
1249 	fz_catch(ctx)
1250 		fz_rethrow(ctx);
1251 }
1252 
pdf_signature_hash_bytes(fz_context * ctx,pdf_document * doc,pdf_obj * signature)1253 fz_stream *pdf_signature_hash_bytes(fz_context *ctx, pdf_document *doc, pdf_obj *signature)
1254 {
1255 	fz_range *byte_range = NULL;
1256 	int byte_range_len;
1257 	fz_stream *bytes = NULL;
1258 
1259 	fz_var(byte_range);
1260 	fz_try(ctx)
1261 	{
1262 		byte_range_len = pdf_signature_byte_range(ctx, doc, signature, NULL);
1263 		if (byte_range_len)
1264 		{
1265 			byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
1266 			pdf_signature_byte_range(ctx, doc, signature, byte_range);
1267 		}
1268 
1269 		validate_byte_ranges(ctx, doc, byte_range, byte_range_len);
1270 		bytes = fz_open_range_filter(ctx, doc->file, byte_range, byte_range_len);
1271 	}
1272 	fz_always(ctx)
1273 	{
1274 		fz_free(ctx, byte_range);
1275 	}
1276 	fz_catch(ctx)
1277 	{
1278 		fz_rethrow(ctx);
1279 	}
1280 
1281 	return bytes;
1282 }
1283 
pdf_signature_incremental_change_since_signing(fz_context * ctx,pdf_document * doc,pdf_obj * signature)1284 int pdf_signature_incremental_change_since_signing(fz_context *ctx, pdf_document *doc, pdf_obj *signature)
1285 {
1286 	fz_range *byte_range = NULL;
1287 	int byte_range_len;
1288 	int changed = 0;
1289 
1290 	fz_var(byte_range);
1291 	fz_try(ctx)
1292 	{
1293 		byte_range_len = pdf_signature_byte_range(ctx, doc, signature, NULL);
1294 		if (byte_range_len)
1295 		{
1296 			fz_range *last_range;
1297 			int64_t end_of_range;
1298 
1299 			byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
1300 			pdf_signature_byte_range(ctx, doc, signature, byte_range);
1301 
1302 			last_range = &byte_range[byte_range_len -1];
1303 			end_of_range = last_range->offset + last_range->length;
1304 
1305 			/* We can see how long the document was when signed by inspecting the byte
1306 			 * ranges of the signature.  The document, when read in, may have already
1307 			 * had changes tagged on to it, past its extent when signed, or we may have
1308 			 * made changes since reading it, which will be held in a new incremental
1309 			 * xref section. */
1310 			if (doc->file_size > end_of_range || doc->num_incremental_sections > 0)
1311 				changed = 1;
1312 		}
1313 	}
1314 	fz_always(ctx)
1315 	{
1316 		fz_free(ctx, byte_range);
1317 	}
1318 	fz_catch(ctx)
1319 	{
1320 		fz_rethrow(ctx);
1321 	}
1322 
1323 	return changed;
1324 }
1325 
pdf_signature_is_signed(fz_context * ctx,pdf_document * doc,pdf_obj * field)1326 int pdf_signature_is_signed(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1327 {
1328 	pdf_obj *v;
1329 	pdf_obj* vtype;
1330 
1331 	if (pdf_dict_get_inheritable(ctx, field, PDF_NAME(FT)) != PDF_NAME(Sig))
1332 		return 0;
1333 	/* Signatures can only be signed if the value is a dictionary,
1334 	 * and if the value has a Type, it should be Sig. */
1335 	v = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
1336 	vtype = pdf_dict_get(ctx, v, PDF_NAME(Type));
1337 	return pdf_is_dict(ctx, v) && (vtype ? pdf_name_eq(ctx, vtype, PDF_NAME(Sig)) : 1);
1338 }
1339 
pdf_widget_is_signed(fz_context * ctx,pdf_widget * widget)1340 int pdf_widget_is_signed(fz_context *ctx, pdf_widget *widget)
1341 {
1342 	if (widget == NULL)
1343 		return 0;
1344 	return pdf_signature_is_signed(ctx, widget->page->doc, widget->obj);
1345 }
1346 
pdf_signature_contents(fz_context * ctx,pdf_document * doc,pdf_obj * signature,char ** contents)1347 size_t pdf_signature_contents(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char **contents)
1348 {
1349 	pdf_obj *v_ref = pdf_dict_get_inheritable(ctx, signature, PDF_NAME(V));
1350 	pdf_obj *v_obj = pdf_load_unencrypted_object(ctx, doc, pdf_to_num(ctx, v_ref));
1351 	char *copy = NULL;
1352 	size_t len;
1353 
1354 	fz_var(copy);
1355 	fz_try(ctx)
1356 	{
1357 		pdf_obj *c = pdf_dict_get(ctx, v_obj, PDF_NAME(Contents));
1358 		char *s;
1359 
1360 		s = pdf_to_str_buf(ctx, c);
1361 		len = pdf_to_str_len(ctx, c);
1362 
1363 		if (contents)
1364 		{
1365 			copy = Memento_label(fz_malloc(ctx, len), "sig_contents");
1366 			memcpy(copy, s, len);
1367 		}
1368 	}
1369 	fz_always(ctx)
1370 		pdf_drop_obj(ctx, v_obj);
1371 	fz_catch(ctx)
1372 	{
1373 		fz_free(ctx, copy);
1374 		fz_rethrow(ctx);
1375 	}
1376 
1377 	if (contents)
1378 		*contents = copy;
1379 	return len;
1380 }
1381 
1382 static fz_xml_doc *
pdf_parse_xml(fz_context * ctx,pdf_obj * obj)1383 pdf_parse_xml(fz_context *ctx, pdf_obj *obj)
1384 {
1385 	fz_buffer *buf = pdf_load_stream(ctx, obj);
1386 	fz_xml_doc *xml = NULL;
1387 
1388 	fz_try(ctx)
1389 		xml = fz_parse_xml(ctx, buf, 0);
1390 	fz_always(ctx)
1391 		fz_drop_buffer(ctx, buf);
1392 	fz_catch(ctx)
1393 		fz_rethrow(ctx);
1394 
1395 	return xml;
1396 }
1397 
load_xfa(fz_context * ctx,pdf_document * doc)1398 static int load_xfa(fz_context *ctx, pdf_document *doc)
1399 {
1400 	pdf_obj *xfa;
1401 	int i, len;
1402 
1403 	if (doc->xfa.count)
1404 		return 1; /* Already loaded, and present. */
1405 
1406 	xfa = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/XFA");
1407 	if (!pdf_is_array(ctx, xfa))
1408 		return 0; /* No XFA */
1409 
1410 	len = (pdf_array_len(ctx, xfa)+1)>>1;
1411 	doc->xfa.entries = fz_calloc(ctx, len, sizeof(pdf_xfa_entry));
1412 	doc->xfa.count = len;
1413 
1414 	for(i = 0; i < len; i++)
1415 	{
1416 		doc->xfa.entries[i].key = fz_strdup(ctx, pdf_to_text_string(ctx, pdf_array_get(ctx, xfa, i*2)));
1417 		doc->xfa.entries[i].value = pdf_parse_xml(ctx, pdf_array_get(ctx, xfa, i*2+1));
1418 	}
1419 
1420 	return len > 0;
1421 }
1422 
1423 static fz_xml *
get_xfa_root(fz_context * ctx,pdf_document * doc,const char * str)1424 get_xfa_root(fz_context *ctx, pdf_document *doc, const char *str)
1425 {
1426 	int i;
1427 
1428 	if (load_xfa(ctx, doc) == 0)
1429 		return NULL;
1430 
1431 	for (i = 0; i < doc->xfa.count; i++)
1432 		if (strcmp(doc->xfa.entries[i].key, str) == 0)
1433 			return fz_xml_root(doc->xfa.entries[i].value);
1434 
1435 	return NULL;
1436 }
1437 
1438 static int
find_name_component(char ** np,char ** sp,char ** ep)1439 find_name_component(char **np, char **sp, char **ep)
1440 {
1441 	char *n = *np;
1442 	char *s, *e;
1443 	int idx = 0;
1444 
1445 	if (*n == '.')
1446 		n++;
1447 
1448 	/* Find the next name we are looking for. */
1449 	s = e = n;
1450 	while (*e && *e != '[' && *e != '.')
1451 		e++;
1452 
1453 	/* So the next name is s..e */
1454 	n = e;
1455 	if (*n == '[')
1456 	{
1457 		n++;
1458 		while (*n >= '0' && *n <= '9')
1459 			idx = idx*10 + *n++ - '0';
1460 		while (*n && *n != ']')
1461 			n++;
1462 		if (*n == ']')
1463 			n++;
1464 	}
1465 	*np = n;
1466 	*sp = s;
1467 	*ep = e;
1468 
1469 	return idx;
1470 }
1471 
1472 static pdf_obj *
annot_from_name(fz_context * ctx,pdf_document * doc,const char * str)1473 annot_from_name(fz_context *ctx, pdf_document *doc, const char *str)
1474 {
1475 	pdf_obj *fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
1476 
1477 	if (strncmp(str, "xfa[0].", 7) == 0)
1478 		str += 7;
1479 	if (strncmp(str, "template[0].", 12) == 0)
1480 		str += 12;
1481 
1482 	return pdf_lookup_field(ctx, fields, str);
1483 }
1484 
1485 static pdf_obj *
get_locked_fields_from_xfa(fz_context * ctx,pdf_document * doc,pdf_obj * field)1486 get_locked_fields_from_xfa(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1487 {
1488 	char *name = pdf_field_name(ctx, field);
1489 	char *n = name;
1490 	const char *use;
1491 	fz_xml *root, *node;
1492 
1493 	if (name == NULL)
1494 		return NULL;
1495 
1496 	root = get_xfa_root(ctx, doc, "template");
1497 	node = fz_xml_find(root, "template");
1498 
1499 	do
1500 	{
1501 		char c, *s, *e;
1502 		int idx = 0;
1503 		char *key;
1504 
1505 		idx = find_name_component(&n, &s, &e);
1506 		/* We want the idx'th occurrence of s..e */
1507 
1508 		/* Hacky */
1509 		c = *e;
1510 		*e = 0;
1511 		key = *n ? "subform" : "field";
1512 		node = fz_xml_find_down_match(node, key, "name", s);
1513 		while (node && idx > 0)
1514 		{
1515 			node = fz_xml_find_next_match(node, key, "name", s);
1516 			idx--;
1517 		}
1518 		*e = c;
1519 	}
1520 	while (node && *n == '.');
1521 
1522 	fz_free(ctx, name);
1523 	if (node == NULL)
1524 		return NULL;
1525 
1526 	node = fz_xml_find_down(node, "ui");
1527 	node = fz_xml_find_down(node, "signature");
1528 	node = fz_xml_find_down(node, "manifest");
1529 
1530 	use = fz_xml_att(node, "use");
1531 	if (use == NULL)
1532 		return NULL;
1533 	if (*use == '#')
1534 		use++;
1535 
1536 	/* Now look for a variables entry in a subform that defines this. */
1537 	while (node)
1538 	{
1539 		fz_xml *variables, *manifest, *ref;
1540 		pdf_obj *arr;
1541 
1542 		/* Find the enclosing subform */
1543 		do {
1544 			node = fz_xml_up(node);
1545 		} while (node && strcmp(fz_xml_tag(node), "subform"));
1546 
1547 		/* Look for a variables within that. */
1548 		variables = fz_xml_find_down(node, "variables");
1549 		if (variables == NULL)
1550 			continue;
1551 
1552 		manifest = fz_xml_find_down_match(variables, "manifest", "id", use);
1553 		if (manifest == NULL)
1554 			continue;
1555 
1556 		arr = pdf_new_array(ctx, doc, 16);
1557 		fz_try(ctx)
1558 		{
1559 			ref = fz_xml_find_down(manifest, "ref");
1560 			while (ref)
1561 			{
1562 				const char *s = fz_xml_text(fz_xml_down(ref));
1563 				pdf_array_push(ctx, arr, annot_from_name(ctx, doc, s));
1564 				ref = fz_xml_find_next(ref, "ref");
1565 			}
1566 		}
1567 		fz_catch(ctx)
1568 		{
1569 			pdf_drop_obj(ctx, arr);
1570 			fz_rethrow(ctx);
1571 		}
1572 		return arr;
1573 	}
1574 
1575 	return NULL;
1576 }
1577 
1578 static void
lock_field(fz_context * ctx,pdf_obj * f)1579 lock_field(fz_context *ctx, pdf_obj *f)
1580 {
1581 	int ff = pdf_to_int(ctx, pdf_dict_get_inheritable(ctx, f, PDF_NAME(Ff)));
1582 
1583 	if ((ff & PDF_FIELD_IS_READ_ONLY) ||
1584 		!pdf_name_eq(ctx, pdf_dict_get(ctx, f, PDF_NAME(Type)), PDF_NAME(Annot)) ||
1585 		!pdf_name_eq(ctx, pdf_dict_get(ctx, f, PDF_NAME(Subtype)), PDF_NAME(Widget)))
1586 		return;
1587 
1588 	pdf_dict_put(ctx, f, PDF_NAME(Ff), pdf_new_int(ctx, ff | PDF_FIELD_IS_READ_ONLY));
1589 }
1590 
1591 static void
lock_xfa_locked_fields(fz_context * ctx,pdf_obj * a)1592 lock_xfa_locked_fields(fz_context *ctx, pdf_obj *a)
1593 {
1594 	int i;
1595 	int len = pdf_array_len(ctx, a);
1596 
1597 	for (i = 0; i < len; i++)
1598 	{
1599 		lock_field(ctx, pdf_array_get(ctx, a, i));
1600 	}
1601 }
1602 
1603 
pdf_signature_set_value(fz_context * ctx,pdf_document * doc,pdf_obj * field,pdf_pkcs7_signer * signer,int64_t stime)1604 void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer, int64_t stime)
1605 {
1606 	pdf_obj *v = NULL;
1607 	pdf_obj *o = NULL;
1608 	pdf_obj *r = NULL;
1609 	pdf_obj *t = NULL;
1610 	pdf_obj *a = NULL;
1611 	pdf_obj *b = NULL;
1612 	pdf_obj *l = NULL;
1613 	pdf_obj *indv;
1614 	int vnum;
1615 	size_t max_digest_size;
1616 	char *buf = NULL;
1617 
1618 	vnum = pdf_create_object(ctx, doc);
1619 	indv = pdf_new_indirect(ctx, doc, vnum, 0);
1620 	pdf_dict_put_drop(ctx, field, PDF_NAME(V), indv);
1621 
1622 	max_digest_size = signer->max_digest_size(ctx, signer);
1623 
1624 	fz_var(v);
1625 	fz_var(o);
1626 	fz_var(r);
1627 	fz_var(t);
1628 	fz_var(a);
1629 	fz_var(b);
1630 	fz_var(l);
1631 	fz_var(buf);
1632 	fz_try(ctx)
1633 	{
1634 		v = pdf_new_dict(ctx, doc, 4);
1635 		pdf_update_object(ctx, doc, vnum, v);
1636 
1637 		buf = fz_calloc(ctx, max_digest_size, 1);
1638 
1639 		/* Ensure that the /Filter entry is the first entry in the
1640 		   dictionary after the digest contents since we look for
1641 		   this tag when completing signatures in pdf-write.c in order
1642 		   to generate the correct byte range. */
1643 		pdf_dict_put_array(ctx, v, PDF_NAME(ByteRange), 4);
1644 		pdf_dict_put_string(ctx, v, PDF_NAME(Contents), buf, max_digest_size);
1645 		pdf_dict_put(ctx, v, PDF_NAME(Filter), PDF_NAME(Adobe_PPKLite));
1646 		pdf_dict_put(ctx, v, PDF_NAME(SubFilter), PDF_NAME(adbe_pkcs7_detached));
1647 		pdf_dict_put(ctx, v, PDF_NAME(Type), PDF_NAME(Sig));
1648 		pdf_dict_put_date(ctx, v, PDF_NAME(M), stime);
1649 
1650 		o = pdf_new_array(ctx, doc, 1);
1651 		pdf_dict_put(ctx, v, PDF_NAME(Reference), o);
1652 		r = pdf_new_dict(ctx, doc, 4);
1653 		pdf_array_put(ctx, o, 0, r);
1654 		pdf_dict_put(ctx, r, PDF_NAME(Data), pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root)));
1655 		pdf_dict_put(ctx, r, PDF_NAME(TransformMethod), PDF_NAME(FieldMDP));
1656 		pdf_dict_put(ctx, r, PDF_NAME(Type), PDF_NAME(SigRef));
1657 		t = pdf_new_dict(ctx, doc, 5);
1658 		pdf_dict_put(ctx, r, PDF_NAME(TransformParams), t);
1659 
1660 		l = pdf_dict_getp(ctx, field, "Lock/Action");
1661 		if (l)
1662 		{
1663 			a = pdf_dict_getp(ctx, field, "Lock/Fields");
1664 		}
1665 		else
1666 		{
1667 			/* Lock action wasn't specified so we need to encode an Include.
1668 			 * Before we just use an empty array, check in the XFA for locking
1669 			 * details. */
1670 			a = get_locked_fields_from_xfa(ctx, doc, field);
1671 			if (a)
1672 				lock_xfa_locked_fields(ctx, a);
1673 
1674 			/* If we don't get a result from the XFA, just encode an empty array
1675 			 * (leave a == NULL), even if Lock/Fields exists because we don't really
1676 			 * know what to do with the information if the action isn't defined. */
1677 			l = PDF_NAME(Include);
1678 		}
1679 
1680 		pdf_dict_put(ctx, t, PDF_NAME(Action), l);
1681 
1682 		if (pdf_name_eq(ctx, l, PDF_NAME(Include)) || pdf_name_eq(ctx, l, PDF_NAME(Exclude)))
1683 		{
1684 			/* For action Include and Exclude, we need to encode a Fields array */
1685 			if (!a)
1686 			{
1687 				/* If one wasn't defined or we chose to ignore it because no action
1688 				 * was defined then use an empty one. */
1689 				b = pdf_new_array(ctx, doc, 0);
1690 				a = b;
1691 			}
1692 
1693 			pdf_dict_put_drop(ctx, t, PDF_NAME(Fields), pdf_copy_array(ctx, a));
1694 		}
1695 
1696 		pdf_dict_put(ctx, t, PDF_NAME(Type), PDF_NAME(TransformParams));
1697 		pdf_dict_put(ctx, t, PDF_NAME(V), PDF_NAME(1_2));
1698 
1699 		/* Record details within the document structure so that contents
1700 		* and byte_range can be updated with their correct values at
1701 		* saving time */
1702 		pdf_xref_store_unsaved_signature(ctx, doc, field, signer);
1703 	}
1704 	fz_always(ctx)
1705 	{
1706 		pdf_drop_obj(ctx, v);
1707 		pdf_drop_obj(ctx, o);
1708 		pdf_drop_obj(ctx, r);
1709 		pdf_drop_obj(ctx, t);
1710 		pdf_drop_obj(ctx, b);
1711 		fz_free(ctx, buf);
1712 	}
1713 	fz_catch(ctx)
1714 	{
1715 		fz_rethrow(ctx);
1716 	}
1717 }
1718 
pdf_set_widget_editing_state(fz_context * ctx,pdf_widget * widget,int editing)1719 void pdf_set_widget_editing_state(fz_context *ctx, pdf_widget *widget, int editing)
1720 {
1721 	widget->ignore_trigger_events = editing;
1722 }
1723 
pdf_get_widget_editing_state(fz_context * ctx,pdf_widget * widget)1724 int pdf_get_widget_editing_state(fz_context *ctx, pdf_widget *widget)
1725 {
1726 	return widget->ignore_trigger_events;
1727 }
1728 
pdf_execute_js_action(fz_context * ctx,pdf_document * doc,pdf_obj * target,const char * path,pdf_obj * js)1729 static void pdf_execute_js_action(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *js)
1730 {
1731 	if (js)
1732 	{
1733 		char *code = pdf_load_stream_or_string_as_utf8(ctx, js);
1734 		fz_try(ctx)
1735 		{
1736 			char buf[100];
1737 			fz_snprintf(buf, sizeof buf, "%d/%s", pdf_to_num(ctx, target), path);
1738 			pdf_js_execute(doc->js, buf, code);
1739 		}
1740 		fz_always(ctx)
1741 			fz_free(ctx, code);
1742 		fz_catch(ctx)
1743 			fz_rethrow(ctx);
1744 	}
1745 }
1746 
pdf_execute_action_imp(fz_context * ctx,pdf_document * doc,pdf_obj * target,const char * path,pdf_obj * action)1747 static void pdf_execute_action_imp(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *action)
1748 {
1749 	pdf_obj *S = pdf_dict_get(ctx, action, PDF_NAME(S));
1750 	if (pdf_name_eq(ctx, S, PDF_NAME(JavaScript)))
1751 	{
1752 		if (doc->js)
1753 			pdf_execute_js_action(ctx, doc, target, path, pdf_dict_get(ctx, action, PDF_NAME(JS)));
1754 	}
1755 	if (pdf_name_eq(ctx, S, PDF_NAME(ResetForm)))
1756 	{
1757 		pdf_obj *fields = pdf_dict_get(ctx, action, PDF_NAME(Fields));
1758 		int flags = pdf_dict_get_int(ctx, action, PDF_NAME(Flags));
1759 		pdf_reset_form(ctx, doc, fields, flags & 1);
1760 	}
1761 }
1762 
pdf_execute_action_chain(fz_context * ctx,pdf_document * doc,pdf_obj * target,const char * path,pdf_obj * action)1763 static void pdf_execute_action_chain(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *action)
1764 {
1765 	pdf_obj *next;
1766 
1767 	if (pdf_mark_obj(ctx, action))
1768 		fz_throw(ctx, FZ_ERROR_GENERIC, "cycle in action chain");
1769 	fz_try(ctx)
1770 	{
1771 		if (pdf_is_array(ctx, action))
1772 		{
1773 			int i, n = pdf_array_len(ctx, action);
1774 			for (i = 0; i < n; ++i)
1775 				pdf_execute_action_chain(ctx, doc, target, path, pdf_array_get(ctx, action, i));
1776 		}
1777 		else
1778 		{
1779 			pdf_execute_action_imp(ctx, doc, target, path, action);
1780 			next = pdf_dict_get(ctx, action, PDF_NAME(Next));
1781 			if (next)
1782 				pdf_execute_action_chain(ctx, doc, target, path, next);
1783 		}
1784 	}
1785 	fz_always(ctx)
1786 		pdf_unmark_obj(ctx, action);
1787 	fz_catch(ctx)
1788 		fz_rethrow(ctx);
1789 }
1790 
pdf_execute_action(fz_context * ctx,pdf_document * doc,pdf_obj * target,const char * path)1791 static void pdf_execute_action(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path)
1792 {
1793 	pdf_obj *action = pdf_dict_getp(ctx, target, path);
1794 	if (action)
1795 		pdf_execute_action_chain(ctx, doc, target, path, action);
1796 }
1797 
pdf_document_event_will_close(fz_context * ctx,pdf_document * doc)1798 void pdf_document_event_will_close(fz_context *ctx, pdf_document *doc)
1799 {
1800 	pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WC");
1801 }
1802 
pdf_document_event_will_save(fz_context * ctx,pdf_document * doc)1803 void pdf_document_event_will_save(fz_context *ctx, pdf_document *doc)
1804 {
1805 	pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WS");
1806 }
1807 
pdf_document_event_did_save(fz_context * ctx,pdf_document * doc)1808 void pdf_document_event_did_save(fz_context *ctx, pdf_document *doc)
1809 {
1810 	pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/DS");
1811 }
1812 
pdf_document_event_will_print(fz_context * ctx,pdf_document * doc)1813 void pdf_document_event_will_print(fz_context *ctx, pdf_document *doc)
1814 {
1815 	pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WP");
1816 }
1817 
pdf_document_event_did_print(fz_context * ctx,pdf_document * doc)1818 void pdf_document_event_did_print(fz_context *ctx, pdf_document *doc)
1819 {
1820 	pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/DP");
1821 }
1822 
pdf_page_event_open(fz_context * ctx,pdf_page * page)1823 void pdf_page_event_open(fz_context *ctx, pdf_page *page)
1824 {
1825 	pdf_execute_action(ctx, page->doc, page->obj, "AA/O");
1826 }
1827 
pdf_page_event_close(fz_context * ctx,pdf_page * page)1828 void pdf_page_event_close(fz_context *ctx, pdf_page *page)
1829 {
1830 	pdf_execute_action(ctx, page->doc, page->obj, "AA/C");
1831 }
1832 
pdf_annot_event_enter(fz_context * ctx,pdf_annot * annot)1833 void pdf_annot_event_enter(fz_context *ctx, pdf_annot *annot)
1834 {
1835 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/E");
1836 }
1837 
pdf_annot_event_exit(fz_context * ctx,pdf_annot * annot)1838 void pdf_annot_event_exit(fz_context *ctx, pdf_annot *annot)
1839 {
1840 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/X");
1841 }
1842 
pdf_annot_event_down(fz_context * ctx,pdf_annot * annot)1843 void pdf_annot_event_down(fz_context *ctx, pdf_annot *annot)
1844 {
1845 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/D");
1846 }
1847 
pdf_annot_event_up(fz_context * ctx,pdf_annot * annot)1848 void pdf_annot_event_up(fz_context *ctx, pdf_annot *annot)
1849 {
1850 	pdf_obj *action = pdf_dict_get(ctx, annot->obj, PDF_NAME(A));
1851 	if (action)
1852 		pdf_execute_action_chain(ctx, annot->page->doc, annot->obj, "A", action);
1853 	else
1854 		pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/U");
1855 }
1856 
pdf_annot_event_focus(fz_context * ctx,pdf_annot * annot)1857 void pdf_annot_event_focus(fz_context *ctx, pdf_annot *annot)
1858 {
1859 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/Fo");
1860 }
1861 
pdf_annot_event_blur(fz_context * ctx,pdf_annot * annot)1862 void pdf_annot_event_blur(fz_context *ctx, pdf_annot *annot)
1863 {
1864 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/Bl");
1865 }
1866 
pdf_annot_event_page_open(fz_context * ctx,pdf_annot * annot)1867 void pdf_annot_event_page_open(fz_context *ctx, pdf_annot *annot)
1868 {
1869 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/PO");
1870 }
1871 
pdf_annot_event_page_close(fz_context * ctx,pdf_annot * annot)1872 void pdf_annot_event_page_close(fz_context *ctx, pdf_annot *annot)
1873 {
1874 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/PC");
1875 }
1876 
pdf_annot_event_page_visible(fz_context * ctx,pdf_annot * annot)1877 void pdf_annot_event_page_visible(fz_context *ctx, pdf_annot *annot)
1878 {
1879 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/PV");
1880 }
1881 
pdf_annot_event_page_invisible(fz_context * ctx,pdf_annot * annot)1882 void pdf_annot_event_page_invisible(fz_context *ctx, pdf_annot *annot)
1883 {
1884 	pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/PI");
1885 }
1886 
pdf_field_event_keystroke(fz_context * ctx,pdf_document * doc,pdf_obj * field,pdf_keystroke_event * evt)1887 int pdf_field_event_keystroke(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_keystroke_event *evt)
1888 {
1889 	pdf_js *js = doc->js;
1890 	if (js)
1891 	{
1892 		pdf_obj *action = pdf_dict_getp(ctx, field, "AA/K/JS");
1893 		if (action)
1894 		{
1895 			pdf_js_event_init_keystroke(js, field, evt);
1896 			pdf_execute_js_action(ctx, doc, field, "AA/K/JS", action);
1897 			return pdf_js_event_result_keystroke(js, evt);
1898 		}
1899 	}
1900 	return 1;
1901 }
1902 
pdf_field_event_format(fz_context * ctx,pdf_document * doc,pdf_obj * field)1903 char *pdf_field_event_format(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1904 {
1905 	pdf_js *js = doc->js;
1906 	if (js)
1907 	{
1908 		pdf_obj *action = pdf_dict_getp(ctx, field, "AA/F/JS");
1909 		if (action)
1910 		{
1911 			const char *value = pdf_field_value(ctx, field);
1912 			pdf_js_event_init(js, field, value, 1);
1913 			pdf_execute_js_action(ctx, doc, field, "AA/F/JS", action);
1914 			return pdf_js_event_value(js);
1915 		}
1916 	}
1917 	return NULL;
1918 }
1919 
pdf_field_event_validate(fz_context * ctx,pdf_document * doc,pdf_obj * field,const char * value)1920 int pdf_field_event_validate(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *value)
1921 {
1922 	pdf_js *js = doc->js;
1923 	if (js)
1924 	{
1925 		pdf_obj *action = pdf_dict_getp(ctx, field, "AA/V/JS");
1926 		if (action)
1927 		{
1928 			pdf_js_event_init(js, field, value, 1);
1929 			pdf_execute_js_action(ctx, doc, field, "AA/V/JS", action);
1930 			return pdf_js_event_result(js);
1931 		}
1932 	}
1933 	return 1;
1934 }
1935 
pdf_field_event_calculate(fz_context * ctx,pdf_document * doc,pdf_obj * field)1936 void pdf_field_event_calculate(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1937 {
1938 	pdf_js *js = doc->js;
1939 	if (js)
1940 	{
1941 		pdf_obj *action = pdf_dict_getp(ctx, field, "AA/C/JS");
1942 		if (action)
1943 		{
1944 			char *old_value = fz_strdup(ctx, pdf_field_value(ctx, field));
1945 			char *new_value = NULL;
1946 			fz_var(new_value);
1947 			fz_try(ctx)
1948 			{
1949 				pdf_js_event_init(js, field, old_value, 1);
1950 				pdf_execute_js_action(ctx, doc, field, "AA/C/JS", action);
1951 				if (pdf_js_event_result(js))
1952 				{
1953 					char *new_value = pdf_js_event_value(js);
1954 					if (strcmp(old_value, new_value))
1955 						pdf_set_field_value(ctx, doc, field, new_value, 0);
1956 				}
1957 			}
1958 			fz_always(ctx)
1959 			{
1960 				fz_free(ctx, old_value);
1961 				fz_free(ctx, new_value);
1962 			}
1963 			fz_catch(ctx)
1964 				fz_rethrow(ctx);
1965 		}
1966 	}
1967 }
1968 
1969 static void
count_sigs(fz_context * ctx,pdf_obj * field,void * arg,pdf_obj ** ft)1970 count_sigs(fz_context *ctx, pdf_obj *field, void *arg, pdf_obj **ft)
1971 {
1972 	int *n = (int *)arg;
1973 
1974 	if (!pdf_name_eq(ctx, pdf_dict_get(ctx, field, PDF_NAME(Type)), PDF_NAME(Annot)) ||
1975 		!pdf_name_eq(ctx, pdf_dict_get(ctx, field, PDF_NAME(Subtype)), PDF_NAME(Widget)) ||
1976 		!pdf_name_eq(ctx, *ft, PDF_NAME(Sig)))
1977 		return;
1978 
1979 	(*n)++;
1980 }
1981 
1982 static pdf_obj *ft_name[2] = { PDF_NAME(FT), NULL };
1983 
pdf_count_signatures(fz_context * ctx,pdf_document * doc)1984 int pdf_count_signatures(fz_context *ctx, pdf_document *doc)
1985 {
1986 	int n = 0;
1987 	pdf_obj *ft = NULL;
1988 	pdf_obj *form_fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
1989 	pdf_walk_tree(ctx, form_fields, PDF_NAME(Kids), count_sigs, NULL, &n, ft_name, &ft);
1990 	return n;
1991 }
1992