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