Coverage Report

Created: 2026-06-30 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mupdf/source/pdf/pdf-form.c
Line
Count
Source
1
// Copyright (C) 2004-2026 Artifex Software, Inc.
2
//
3
// This file is part of MuPDF.
4
//
5
// MuPDF is free software: you can redistribute it and/or modify it under the
6
// terms of the GNU Affero General Public License as published by the Free
7
// Software Foundation, either version 3 of the License, or (at your option)
8
// any later version.
9
//
10
// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13
// details.
14
//
15
// You should have received a copy of the GNU Affero General Public License
16
// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17
//
18
// Alternative licensing terms are available from the licensor.
19
// For commercial licensing, see <https://www.artifex.com/> or contact
20
// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21
// CA 94129, USA, for further information.
22
23
#include "mupdf/fitz.h"
24
#include "pdf-annot-imp.h"
25
26
#include <string.h>
27
28
/* Must be kept in sync with definitions in pdf_util.js */
29
enum
30
{
31
  Display_Visible,
32
  Display_Hidden,
33
  Display_NoPrint,
34
  Display_NoView
35
};
36
37
enum
38
{
39
  SigFlag_SignaturesExist = 1,
40
  SigFlag_AppendOnly = 2
41
};
42
43
const char *pdf_field_value(fz_context *ctx, pdf_obj *field)
44
152
{
45
152
  pdf_obj *v = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
46
152
  if (pdf_is_name(ctx, v))
47
0
    return pdf_to_name(ctx, v);
48
152
  if (pdf_is_stream(ctx, v))
49
0
  {
50
    // FIXME: pdf_dict_put_inheritable...
51
0
    char *str = pdf_new_utf8_from_pdf_stream_obj(ctx, v);
52
0
    fz_try(ctx)
53
0
      pdf_dict_put_text_string(ctx, field, PDF_NAME(V), str);
54
0
    fz_always(ctx)
55
0
      fz_free(ctx, str);
56
0
    fz_catch(ctx)
57
0
      fz_rethrow(ctx);
58
0
    v = pdf_dict_get(ctx, field, PDF_NAME(V));
59
0
  }
60
152
  return pdf_to_text_string(ctx, v);
61
152
}
62
63
int pdf_field_flags(fz_context *ctx, pdf_obj *obj)
64
166
{
65
166
  return pdf_dict_get_inheritable_int(ctx, obj, PDF_NAME(Ff));
66
166
}
67
68
int pdf_field_type(fz_context *ctx, pdf_obj *obj)
69
0
{
70
0
  pdf_obj *type = pdf_dict_get_inheritable(ctx, obj, PDF_NAME(FT));
71
0
  int flags = pdf_field_flags(ctx, obj);
72
0
  if (pdf_name_eq(ctx, type, PDF_NAME(Btn)))
73
0
  {
74
0
    if (flags & PDF_BTN_FIELD_IS_PUSHBUTTON)
75
0
      return PDF_WIDGET_TYPE_BUTTON;
76
0
    else if (flags & PDF_BTN_FIELD_IS_RADIO)
77
0
      return PDF_WIDGET_TYPE_RADIOBUTTON;
78
0
    else
79
0
      return PDF_WIDGET_TYPE_CHECKBOX;
80
0
  }
81
0
  else if (pdf_name_eq(ctx, type, PDF_NAME(Tx)))
82
0
    return PDF_WIDGET_TYPE_TEXT;
83
0
  else if (pdf_name_eq(ctx, type, PDF_NAME(Ch)))
84
0
  {
85
0
    if (flags & PDF_CH_FIELD_IS_COMBO)
86
0
      return PDF_WIDGET_TYPE_COMBOBOX;
87
0
    else
88
0
      return PDF_WIDGET_TYPE_LISTBOX;
89
0
  }
90
0
  else if (pdf_name_eq(ctx, type, PDF_NAME(Sig)))
91
0
    return PDF_WIDGET_TYPE_SIGNATURE;
92
0
  else
93
0
    return PDF_WIDGET_TYPE_BUTTON;
94
0
}
95
96
const char *pdf_field_type_string(fz_context *ctx, pdf_obj *obj)
97
0
{
98
0
  switch (pdf_field_type(ctx, obj))
99
0
  {
100
0
  default:
101
0
  case PDF_WIDGET_TYPE_BUTTON: return "button";
102
0
  case PDF_WIDGET_TYPE_CHECKBOX: return "checkbox";
103
0
  case PDF_WIDGET_TYPE_COMBOBOX: return "combobox";
104
0
  case PDF_WIDGET_TYPE_LISTBOX: return "listbox";
105
0
  case PDF_WIDGET_TYPE_RADIOBUTTON: return "radiobutton";
106
0
  case PDF_WIDGET_TYPE_SIGNATURE: return "signature";
107
0
  case PDF_WIDGET_TYPE_TEXT: return "text";
108
0
  }
109
0
}
110
111
/* Find the point in a field hierarchy where all descendants
112
 * share the same name */
113
static pdf_obj *find_head_of_field_group(fz_context *ctx, pdf_obj *obj)
114
0
{
115
0
  if (obj == NULL || pdf_dict_get(ctx, obj, PDF_NAME(T)))
116
0
    return obj;
117
0
  else
118
0
    return find_head_of_field_group(ctx, pdf_dict_get(ctx, obj, PDF_NAME(Parent)));
119
0
}
120
121
static void pdf_field_mark_dirty(fz_context *ctx, pdf_obj *field)
122
0
{
123
0
  pdf_document *doc = pdf_get_bound_document(ctx, field);
124
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
125
0
  if (kids)
126
0
  {
127
0
    int i, n = pdf_array_len(ctx, kids);
128
0
    for (i = 0; i < n; i++)
129
0
      pdf_field_mark_dirty(ctx, pdf_array_get(ctx, kids, i));
130
0
  }
131
0
  pdf_dirty_obj(ctx, field);
132
0
  if (doc)
133
0
    doc->resynth_required = 1;
134
0
}
135
136
static void update_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *obj, const char *text)
137
0
{
138
0
  const char *old_text;
139
0
  pdf_obj *grp;
140
141
0
  if (!text)
142
0
    text = "";
143
144
  /* All fields of the same name should be updated, so
145
   * set the value at the head of the group */
146
0
  grp = find_head_of_field_group(ctx, obj);
147
0
  if (grp)
148
0
    obj = grp;
149
150
  /* Only update if we change the actual value. */
151
0
  old_text = pdf_dict_get_text_string(ctx, obj, PDF_NAME(V));
152
0
  if (old_text && !strcmp(old_text, text))
153
0
    return;
154
155
  // TODO: if field is a checkbox, V should be a name and not a string!
156
0
  pdf_dict_put_text_string(ctx, obj, PDF_NAME(V), text);
157
158
0
  pdf_field_mark_dirty(ctx, obj);
159
0
}
160
161
static pdf_obj *
162
pdf_lookup_field_imp(fz_context *ctx, pdf_obj *arr, const char *str, pdf_cycle_list *cycle_up);
163
164
static pdf_obj *
165
lookup_field_sub(fz_context *ctx, pdf_obj *dict, const char *str, pdf_cycle_list *cycle_up)
166
0
{
167
0
  pdf_obj *kids;
168
0
  pdf_obj *name;
169
170
0
  name = pdf_dict_get(ctx, dict, PDF_NAME(T));
171
172
  /* If we have a name, check it matches. If it matches, consume that
173
   * portion of str. If not, exit. */
174
0
  if (name)
175
0
  {
176
0
    const char *match = pdf_to_text_string(ctx, name);
177
0
    const char *e = str;
178
0
    size_t len;
179
0
    while (*e && *e != '.')
180
0
      e++;
181
0
    len = e-str;
182
0
    if (strncmp(str, match, len) != 0 || (match[len] != 0 && match[len] != '.'))
183
      /* name doesn't match. */
184
0
      return NULL;
185
0
    str = e;
186
0
    if (*str == '.')
187
0
      str++;
188
0
  }
189
190
  /* If there is a kids array, but the search string is not empty, we have
191
  encountered an internal field which represents a set of terminal fields. */
192
193
  /* If there is a kids array and the search string is not empty,
194
  walk those looking for the appropriate one. */
195
0
  kids = pdf_dict_get(ctx, dict, PDF_NAME(Kids));
196
0
  if (kids && *str != 0)
197
0
    return pdf_lookup_field_imp(ctx, kids, str, cycle_up);
198
199
  /* The field may be a terminal or an internal field at this point.
200
  Accept it as the match if the match string is exhausted. */
201
0
  if (*str == 0)
202
0
    return dict;
203
204
0
  return NULL;
205
0
}
206
207
static pdf_obj *
208
pdf_lookup_field_imp(fz_context *ctx, pdf_obj *arr, const char *str, pdf_cycle_list *cycle_up)
209
0
{
210
0
  pdf_cycle_list cycle;
211
0
  int len = pdf_array_len(ctx, arr);
212
0
  int i;
213
214
0
  for (i = 0; i < len; i++)
215
0
  {
216
0
    pdf_obj *k = pdf_array_get(ctx, arr, i);
217
0
    pdf_obj *found;
218
0
    if (pdf_cycle(ctx, &cycle, cycle_up, k))
219
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in fields");
220
0
    found = lookup_field_sub(ctx, k, str, &cycle);
221
0
    if (found)
222
0
      return found;
223
0
  }
224
225
0
  return NULL;
226
0
}
227
228
pdf_obj *
229
pdf_lookup_field(fz_context *ctx, pdf_obj *arr, const char *str)
230
0
{
231
0
  return pdf_lookup_field_imp(ctx, arr, str, NULL);
232
0
}
233
234
static void reset_form_field(fz_context *ctx, pdf_document *doc, pdf_obj *field)
235
0
{
236
  /* Set V to DV wherever DV is present, and delete V where DV is not.
237
   * FIXME: we assume for now that V has not been set unequal
238
   * to DV higher in the hierarchy than "field".
239
   *
240
   * At the bottom of the hierarchy we may find widget annotations
241
   * that aren't also fields, but DV and V will not be present in their
242
   * dictionaries, and attempts to remove V will be harmless. */
243
0
  pdf_obj *dv = pdf_dict_get(ctx, field, PDF_NAME(DV));
244
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
245
246
0
  if (dv)
247
0
    pdf_dict_put(ctx, field, PDF_NAME(V), dv);
248
0
  else
249
0
    pdf_dict_del(ctx, field, PDF_NAME(V));
250
251
0
  if (kids == NULL)
252
0
  {
253
    /* The leaves of the tree are widget annotations
254
     * In some cases we need to update the appearance state;
255
     * in others we need to mark the field as dirty so that
256
     * the appearance stream will be regenerated. */
257
0
    switch (pdf_field_type(ctx, field))
258
0
    {
259
0
    case PDF_WIDGET_TYPE_CHECKBOX:
260
0
    case PDF_WIDGET_TYPE_RADIOBUTTON:
261
0
      {
262
0
        pdf_obj *leafv = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
263
0
        pdf_obj *ap = pdf_dict_get(ctx, field, PDF_NAME(AP));
264
0
        pdf_obj *n = pdf_dict_get(ctx, ap, PDF_NAME(N));
265
266
        /* Value does not refer to any appearance state in the
267
        normal appearance stream dictionary, default to Off instead. */
268
0
        if (pdf_is_dict(ctx, n) && !pdf_dict_get(ctx, n, leafv))
269
0
          leafv = NULL;
270
271
0
        if (!pdf_is_name(ctx, leafv))
272
0
          leafv = PDF_NAME(Off);
273
0
        pdf_dict_put(ctx, field, PDF_NAME(AS), leafv);
274
0
      }
275
0
      pdf_field_mark_dirty(ctx, field);
276
0
      break;
277
278
0
    case PDF_WIDGET_TYPE_BUTTON:
279
0
    case PDF_WIDGET_TYPE_SIGNATURE:
280
      /* Pushbuttons and signatures have no value to reset. */
281
0
      break;
282
283
0
    default:
284
0
      pdf_field_mark_dirty(ctx, field);
285
0
      break;
286
0
    }
287
0
  }
288
0
}
289
290
void pdf_field_reset(fz_context *ctx, pdf_document *doc, pdf_obj *field)
291
0
{
292
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
293
294
0
  reset_form_field(ctx, doc, field);
295
296
0
  if (kids)
297
0
  {
298
0
    int i, n = pdf_array_len(ctx, kids);
299
300
0
    for (i = 0; i < n; i++)
301
0
      pdf_field_reset(ctx, doc, pdf_array_get(ctx, kids, i));
302
0
  }
303
0
}
304
305
static void add_field_hierarchy_to_array(fz_context *ctx, pdf_obj *array, pdf_obj *field, pdf_obj *fields, int exclude)
306
0
{
307
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
308
0
  int i, n;
309
310
0
  if (fields)
311
0
  {
312
0
    char *needle = pdf_load_field_name(ctx, field);
313
0
    fz_try(ctx)
314
0
    {
315
0
      n = pdf_array_len(ctx, fields);
316
0
      for (i = 0; i < n; i++)
317
0
      {
318
0
        char *name = pdf_load_field_name(ctx, pdf_array_get(ctx, fields, i));
319
0
        int found = !strcmp(needle, name);
320
0
        fz_free(ctx, name);
321
0
        if (found)
322
0
          break;
323
0
      }
324
0
    }
325
0
    fz_always(ctx)
326
0
      fz_free(ctx, needle);
327
0
    fz_catch(ctx)
328
0
      fz_rethrow(ctx);
329
330
0
    if ((exclude && i < n) || (!exclude && i == n))
331
0
      return;
332
0
  }
333
334
0
  pdf_array_push(ctx, array, field);
335
336
0
  if (kids)
337
0
  {
338
0
    n = pdf_array_len(ctx, kids);
339
340
0
    for (i = 0; i < n; i++)
341
0
      add_field_hierarchy_to_array(ctx, array, pdf_array_get(ctx, kids, i), fields, exclude);
342
0
  }
343
0
}
344
345
/*
346
  When resetting or submitting a form, the fields to act upon are defined
347
  by an array of either field references or field names, plus a flag determining
348
  whether to act upon the fields in the array, or all fields other than those in
349
  the array. specified_fields interprets this information and produces the array
350
  of fields to be acted upon.
351
*/
352
static pdf_obj *specified_fields(fz_context *ctx, pdf_document *doc, pdf_obj *fields, int exclude)
353
0
{
354
0
  pdf_obj *form = pdf_dict_getl(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(Fields), NULL);
355
0
  int i, n;
356
0
  pdf_obj *result;
357
358
0
  result = pdf_new_array(ctx, doc, 0);
359
0
  fz_try(ctx)
360
0
  {
361
0
    if (fields)
362
0
    {
363
0
      n = pdf_array_len(ctx, fields);
364
0
      for (i = 0; i < n; i++)
365
0
      {
366
0
        pdf_obj *field = pdf_array_get(ctx, fields, i);
367
0
        if (pdf_is_string(ctx, field))
368
0
          field = pdf_lookup_field(ctx, form, pdf_to_str_buf(ctx, field));
369
0
        if (field)
370
0
          add_field_hierarchy_to_array(ctx, result, field, fields, exclude);
371
0
      }
372
0
    }
373
0
    else
374
0
    {
375
0
      n = pdf_array_len(ctx, form);
376
0
      for (i = 0; i < n; i++)
377
0
      {
378
0
        pdf_obj *field = pdf_array_get(ctx, form, i);
379
0
        add_field_hierarchy_to_array(ctx, result, field, fields, exclude);
380
0
      }
381
0
    }
382
0
  }
383
0
  fz_catch(ctx)
384
0
  {
385
0
    pdf_drop_obj(ctx, result);
386
0
    fz_rethrow(ctx);
387
0
  }
388
389
0
  return result;
390
0
}
391
392
void pdf_reset_form(fz_context *ctx, pdf_document *doc, pdf_obj *fields, int exclude)
393
0
{
394
0
  pdf_obj *sfields = specified_fields(ctx, doc, fields, exclude);
395
0
  fz_try(ctx)
396
0
  {
397
0
    int i, n = pdf_array_len(ctx, sfields);
398
0
    for (i = 0; i < n; i++)
399
0
      reset_form_field(ctx, doc, pdf_array_get(ctx, sfields, i));
400
0
    doc->recalculate = 1;
401
0
  }
402
0
  fz_always(ctx)
403
0
    pdf_drop_obj(ctx, sfields);
404
0
  fz_catch(ctx)
405
0
    fz_rethrow(ctx);
406
0
}
407
408
typedef struct
409
{
410
  pdf_obj *pageobj;
411
  pdf_obj *chk;
412
} lookup_state;
413
414
static void *find_widget_on_page(fz_context *ctx, fz_page *page_, void *state_)
415
0
{
416
0
  lookup_state *state = (lookup_state *) state_;
417
0
  pdf_page *page = (pdf_page *) page_;
418
0
  pdf_annot *widget;
419
420
0
  if (state->pageobj && pdf_objcmp_resolve(ctx, state->pageobj, page->obj))
421
0
    return NULL;
422
423
0
  for (widget = pdf_first_widget(ctx, page); widget != NULL; widget = pdf_next_widget(ctx, widget))
424
0
  {
425
0
    if (!pdf_objcmp_resolve(ctx, state->chk, widget->obj))
426
0
      return widget;
427
0
  }
428
429
0
  return NULL;
430
0
}
431
432
static pdf_annot *find_widget(fz_context *ctx, pdf_document *doc, pdf_obj *chk)
433
0
{
434
0
  lookup_state state;
435
436
0
  state.pageobj = pdf_dict_get(ctx, chk, PDF_NAME(P));
437
0
  state.chk = chk;
438
439
0
  return fz_process_opened_pages(ctx, (fz_document *) doc, find_widget_on_page, &state);
440
0
}
441
442
static void set_check(fz_context *ctx, pdf_document *doc, pdf_obj *chk, pdf_obj *name)
443
0
{
444
0
  pdf_obj *val;
445
446
  /* If name is the "On" value of this check
447
  * box then use it, otherwise use "Off" */
448
0
  if (pdf_name_eq(ctx, pdf_button_field_on_state(ctx, chk), name))
449
0
    val = name;
450
0
  else
451
0
    val = PDF_NAME(Off);
452
453
0
  if (!pdf_name_eq(ctx, pdf_dict_get(ctx, chk, PDF_NAME(AS)), val))
454
0
  {
455
0
    pdf_dict_put(ctx, chk, PDF_NAME(AS), val);
456
0
    pdf_set_annot_has_changed(ctx, find_widget(ctx, doc, chk));
457
0
  }
458
0
}
459
460
/* Set the values of all fields in a group defined by a node
461
 * in the hierarchy */
462
static void set_check_grp(fz_context *ctx, pdf_document *doc, pdf_obj *grp, pdf_obj *val)
463
0
{
464
0
  pdf_obj *kids = pdf_dict_get(ctx, grp, PDF_NAME(Kids));
465
466
0
  if (kids == NULL)
467
0
  {
468
0
    set_check(ctx, doc, grp, val);
469
0
  }
470
0
  else
471
0
  {
472
0
    int i, n = pdf_array_len(ctx, kids);
473
474
0
    for (i = 0; i < n; i++)
475
0
      set_check_grp(ctx, doc, pdf_array_get(ctx, kids, i), val);
476
0
  }
477
0
}
478
479
void pdf_calculate_form(fz_context *ctx, pdf_document *doc)
480
0
{
481
0
  if (doc->js)
482
0
  {
483
0
    fz_try(ctx)
484
0
    {
485
0
      pdf_obj *co = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/CO");
486
0
      int i, n = pdf_array_len(ctx, co);
487
0
      for (i = 0; i < n; i++)
488
0
      {
489
0
        pdf_obj *field = pdf_array_get(ctx, co, i);
490
0
        pdf_field_event_calculate(ctx, doc, field);
491
0
      }
492
0
    }
493
0
    fz_always(ctx)
494
0
      doc->recalculate = 0;
495
0
    fz_catch(ctx)
496
0
      fz_rethrow(ctx);
497
0
  }
498
0
}
499
500
static pdf_obj *find_on_state(fz_context *ctx, pdf_obj *dict)
501
14
{
502
14
  int i, n = pdf_dict_len(ctx, dict);
503
14
  for (i = 0; i < n; ++i)
504
14
  {
505
14
    pdf_obj *key = pdf_dict_get_key(ctx, dict, i);
506
14
    if (key != PDF_NAME(Off))
507
14
      return key;
508
14
  }
509
0
  return NULL;
510
14
}
511
512
pdf_obj *pdf_button_field_on_state(fz_context *ctx, pdf_obj *field)
513
14
{
514
14
  pdf_obj *ap = pdf_dict_get(ctx, field, PDF_NAME(AP));
515
14
  pdf_obj *on = find_on_state(ctx, pdf_dict_get(ctx, ap, PDF_NAME(N)));
516
14
  if (!on) on = find_on_state(ctx, pdf_dict_get(ctx, ap, PDF_NAME(D)));
517
14
  if (!on) on = PDF_NAME(Yes);
518
14
  return on;
519
14
}
520
521
static void
522
begin_annot_op(fz_context *ctx, pdf_annot *annot, const char *op)
523
0
{
524
0
  if (!annot->page)
525
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
526
527
0
  pdf_begin_operation(ctx, annot->page->doc, op);
528
0
}
529
530
static void
531
end_annot_op(fz_context *ctx, pdf_annot *annot)
532
0
{
533
0
  pdf_end_operation(ctx, annot->page->doc);
534
0
}
535
536
static void
537
abandon_annot_op(fz_context *ctx, pdf_annot *annot)
538
0
{
539
0
  pdf_abandon_operation(ctx, annot->page->doc);
540
0
}
541
542
static void toggle_check_box(fz_context *ctx, pdf_annot *annot)
543
0
{
544
0
  pdf_document *doc = annot->page->doc;
545
0
  int changed = 1;
546
547
0
  begin_annot_op(ctx, annot, "Toggle checkbox");
548
549
0
  fz_try(ctx)
550
0
  {
551
0
    pdf_obj *field = annot->obj;
552
0
    int ff = pdf_field_flags(ctx, field);
553
0
    int is_radio = (ff & PDF_BTN_FIELD_IS_RADIO);
554
0
    int is_no_toggle_to_off = (ff & PDF_BTN_FIELD_IS_NO_TOGGLE_TO_OFF);
555
0
    pdf_obj *grp, *as, *val;
556
557
0
    grp = find_head_of_field_group(ctx, field);
558
0
    if (!grp)
559
0
      grp = field;
560
561
    /* TODO: check V value as well as or instead of AS? */
562
0
    as = pdf_dict_get(ctx, field, PDF_NAME(AS));
563
0
    if (pdf_is_name(ctx, as) && !pdf_name_eq(ctx, as, PDF_NAME(Off)))
564
0
    {
565
0
      if (is_radio && is_no_toggle_to_off)
566
0
      {
567
0
        changed = 0;
568
0
        end_annot_op(ctx, annot);
569
0
        break;
570
0
      }
571
0
      val = PDF_NAME(Off);
572
0
    }
573
0
    else
574
0
    {
575
0
      val = pdf_button_field_on_state(ctx, field);
576
0
    }
577
578
0
    pdf_dict_put(ctx, grp, PDF_NAME(V), val);
579
0
    set_check_grp(ctx, doc, grp, val);
580
0
    doc->recalculate = 1;
581
0
    end_annot_op(ctx, annot);
582
0
  }
583
0
  fz_catch(ctx)
584
0
  {
585
0
    abandon_annot_op(ctx, annot);
586
0
    fz_rethrow(ctx);
587
0
  }
588
589
0
  if (changed)
590
0
    pdf_set_annot_has_changed(ctx, annot);
591
0
}
592
593
int pdf_has_unsaved_changes(fz_context *ctx, pdf_document *doc)
594
0
{
595
0
  int i;
596
597
0
  if (doc->num_incremental_sections == 0)
598
0
    return 0;
599
600
0
  for (i = 0; i < doc->xref_sections->num_objects; i++)
601
0
    if (doc->xref_sections->subsec->table[i].type != 0)
602
0
      break;
603
0
  return i != doc->xref_sections->num_objects;
604
0
}
605
606
int pdf_was_repaired(fz_context *ctx, pdf_document *doc)
607
0
{
608
0
  return doc->repair_attempted;
609
0
}
610
611
int pdf_toggle_widget(fz_context *ctx, pdf_annot *widget)
612
0
{
613
0
  switch (pdf_widget_type(ctx, widget))
614
0
  {
615
0
  default:
616
0
    return 0;
617
0
  case PDF_WIDGET_TYPE_CHECKBOX:
618
0
  case PDF_WIDGET_TYPE_RADIOBUTTON:
619
0
    toggle_check_box(ctx, widget);
620
0
    return 1;
621
0
  }
622
0
}
623
624
int
625
pdf_update_page(fz_context *ctx, pdf_page *page)
626
693
{
627
693
  pdf_annot *annot;
628
693
  pdf_annot *widget;
629
693
  int changed = 0;
630
631
693
  if (page->doc == NULL)
632
0
    return 0;
633
634
693
  if (!page->doc->resynth_required && !page->doc->recalculate)
635
432
    return 0;
636
637
522
  fz_try(ctx)
638
522
  {
639
261
    pdf_begin_implicit_operation(ctx, page->doc);
640
641
261
    if (page->doc->recalculate)
642
0
      pdf_calculate_form(ctx, page->doc);
643
644
346
    for (annot = page->annots; annot; annot = annot->next)
645
85
      if (pdf_update_annot(ctx, annot))
646
5
        changed = 1;
647
621
    for (widget = page->widgets; widget; widget = widget->next)
648
360
      if (pdf_update_annot(ctx, widget))
649
166
        changed = 1;
650
651
261
    pdf_end_operation(ctx, page->doc);
652
261
  }
653
522
  fz_catch(ctx)
654
0
  {
655
0
    pdf_abandon_operation(ctx, page->doc);
656
0
    fz_rethrow(ctx);
657
0
  }
658
659
261
  return changed;
660
261
}
661
662
int
663
pdf_update_open_pages(fz_context *ctx, pdf_document *doc)
664
0
{
665
0
  fz_page *page;
666
0
  int changed = 0;
667
0
  for (page = doc->super.open; page; page = page->next)
668
0
    if (pdf_update_page(ctx, (pdf_page*)page))
669
0
      changed = 1;
670
0
  return changed;
671
0
}
672
673
pdf_annot *pdf_first_widget(fz_context *ctx, pdf_page *page)
674
62
{
675
62
  return page->widgets;
676
62
}
677
678
pdf_annot *pdf_next_widget(fz_context *ctx, pdf_annot *widget)
679
720
{
680
720
  return widget->next;
681
720
}
682
683
enum pdf_widget_type pdf_widget_type(fz_context *ctx, pdf_annot *widget)
684
0
{
685
0
  enum pdf_widget_type ret = PDF_WIDGET_TYPE_BUTTON;
686
687
0
  pdf_annot_push_local_xref(ctx, widget);
688
689
0
  fz_try(ctx)
690
0
  {
691
0
    pdf_obj *subtype = pdf_dict_get(ctx, widget->obj, PDF_NAME(Subtype));
692
0
    if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget)))
693
0
      ret = pdf_field_type(ctx, widget->obj);
694
0
  }
695
0
  fz_always(ctx)
696
0
    pdf_annot_pop_local_xref(ctx, widget);
697
0
  fz_catch(ctx)
698
0
    fz_rethrow(ctx);
699
700
0
  return ret;
701
0
}
702
703
static int set_validated_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *text, int ignore_trigger_events)
704
0
{
705
0
  char *newtext = NULL;
706
707
0
  if (!ignore_trigger_events)
708
0
  {
709
0
    if (!pdf_field_event_validate(ctx, doc, field, text, &newtext))
710
0
      return 0;
711
0
  }
712
713
0
  update_field_value(ctx, doc, field, newtext ? newtext : text);
714
715
0
  fz_free(ctx, newtext);
716
717
0
  return 1;
718
0
}
719
720
static void update_checkbox_selector(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *val)
721
0
{
722
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
723
724
0
  if (kids)
725
0
  {
726
0
    int i, n = pdf_array_len(ctx, kids);
727
728
0
    for (i = 0; i < n; i++)
729
0
      update_checkbox_selector(ctx, doc, pdf_array_get(ctx, kids, i), val);
730
0
  }
731
0
  else
732
0
  {
733
0
    pdf_obj *n = pdf_dict_getp(ctx, field, "AP/N");
734
0
    pdf_obj *oval;
735
736
0
    if (pdf_dict_gets(ctx, n, val))
737
0
      oval = pdf_new_name(ctx, val);
738
0
    else
739
0
      oval = PDF_NAME(Off);
740
0
    pdf_dict_put_drop(ctx, field, PDF_NAME(AS), oval);
741
0
  }
742
0
}
743
744
static int set_checkbox_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *val)
745
0
{
746
0
  update_checkbox_selector(ctx, doc, field, val);
747
0
  update_field_value(ctx, doc, field, val);
748
0
  return 1;
749
0
}
750
751
int pdf_set_field_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *text, int ignore_trigger_events)
752
0
{
753
0
  int accepted = 0;
754
755
0
  switch (pdf_field_type(ctx, field))
756
0
  {
757
0
  case PDF_WIDGET_TYPE_TEXT:
758
0
  case PDF_WIDGET_TYPE_COMBOBOX:
759
0
  case PDF_WIDGET_TYPE_LISTBOX:
760
0
    accepted = set_validated_field_value(ctx, doc, field, text, ignore_trigger_events);
761
0
    break;
762
763
0
  case PDF_WIDGET_TYPE_CHECKBOX:
764
0
  case PDF_WIDGET_TYPE_RADIOBUTTON:
765
0
    accepted = set_checkbox_value(ctx, doc, field, text);
766
0
    break;
767
768
0
  default:
769
0
    update_field_value(ctx, doc, field, text);
770
0
    accepted = 1;
771
0
    break;
772
0
  }
773
774
0
  if (!ignore_trigger_events)
775
0
    doc->recalculate = 1;
776
777
0
  return accepted;
778
0
}
779
780
char *pdf_field_border_style(fz_context *ctx, pdf_obj *field)
781
0
{
782
0
  const char *bs = pdf_to_name(ctx, pdf_dict_getl(ctx, field, PDF_NAME(BS), PDF_NAME(S), NULL));
783
0
  switch (*bs)
784
0
  {
785
0
  case 'S': return "Solid";
786
0
  case 'D': return "Dashed";
787
0
  case 'B': return "Beveled";
788
0
  case 'I': return "Inset";
789
0
  case 'U': return "Underline";
790
0
  }
791
0
  return "Solid";
792
0
}
793
794
void pdf_field_set_border_style(fz_context *ctx, pdf_obj *field, const char *text)
795
0
{
796
0
  pdf_obj *val;
797
798
0
  if (!strcmp(text, "Solid"))
799
0
    val = PDF_NAME(S);
800
0
  else if (!strcmp(text, "Dashed"))
801
0
    val = PDF_NAME(D);
802
0
  else if (!strcmp(text, "Beveled"))
803
0
    val = PDF_NAME(B);
804
0
  else if (!strcmp(text, "Inset"))
805
0
    val = PDF_NAME(I);
806
0
  else if (!strcmp(text, "Underline"))
807
0
    val = PDF_NAME(U);
808
0
  else
809
0
    return;
810
811
0
  pdf_dict_putl_drop(ctx, field, val, PDF_NAME(BS), PDF_NAME(S), NULL);
812
0
  pdf_field_mark_dirty(ctx, field);
813
0
}
814
815
void pdf_field_set_button_caption(fz_context *ctx, pdf_obj *field, const char *text)
816
0
{
817
0
  if (pdf_field_type(ctx, field) == PDF_WIDGET_TYPE_BUTTON)
818
0
  {
819
0
    pdf_obj *val = pdf_new_text_string(ctx, text);
820
0
    pdf_dict_putl_drop(ctx, field, val, PDF_NAME(MK), PDF_NAME(CA), NULL);
821
0
    pdf_field_mark_dirty(ctx, field);
822
0
  }
823
0
}
824
825
int pdf_field_display(fz_context *ctx, pdf_obj *field)
826
0
{
827
0
  pdf_obj *kids;
828
0
  int f, res = Display_Visible;
829
830
  /* Base response on first of children. Not ideal,
831
   * but not clear how to handle children with
832
   * differing values */
833
0
  while ((kids = pdf_dict_get(ctx, field, PDF_NAME(Kids))) != NULL)
834
0
    field = pdf_array_get(ctx, kids, 0);
835
836
0
  f = pdf_dict_get_int(ctx, field, PDF_NAME(F));
837
838
0
  if (f & PDF_ANNOT_IS_HIDDEN)
839
0
  {
840
0
    res = Display_Hidden;
841
0
  }
842
0
  else if (f & PDF_ANNOT_IS_PRINT)
843
0
  {
844
0
    if (f & PDF_ANNOT_IS_NO_VIEW)
845
0
      res = Display_NoView;
846
0
  }
847
0
  else
848
0
  {
849
0
    if (f & PDF_ANNOT_IS_NO_VIEW)
850
0
      res = Display_Hidden;
851
0
    else
852
0
      res = Display_NoPrint;
853
0
  }
854
855
0
  return res;
856
0
}
857
858
/*
859
 * get the field name in a char buffer that has spare room to
860
 * add more characters at the end.
861
 */
862
static char *load_field_name(fz_context *ctx, pdf_obj *field, int spare, pdf_cycle_list *cycle_up)
863
0
{
864
0
  pdf_cycle_list cycle;
865
0
  char *res = NULL;
866
0
  pdf_obj *parent;
867
0
  const char *lname;
868
0
  int llen;
869
870
0
  if (pdf_cycle(ctx, &cycle, cycle_up, field))
871
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "Cycle in field parents");
872
873
0
  parent = pdf_dict_get(ctx, field, PDF_NAME(Parent));
874
0
  lname = pdf_dict_get_text_string(ctx, field, PDF_NAME(T));
875
0
  llen = (int)strlen(lname);
876
877
  // Limit fields to 16K
878
0
  if (llen > (16 << 10) || llen + spare > (16 << 10))
879
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "Field name too long");
880
881
  /*
882
   * If we found a name at this point in the field hierarchy
883
   * then we'll need extra space for it and a dot
884
   */
885
0
  if (llen)
886
0
    spare += llen+1;
887
888
0
  if (parent)
889
0
  {
890
0
    res = load_field_name(ctx, parent, spare, &cycle);
891
0
  }
892
0
  else
893
0
  {
894
0
    res = Memento_label(fz_malloc(ctx, spare+1), "form_field_name");
895
0
    res[0] = 0;
896
0
  }
897
898
0
  if (llen)
899
0
  {
900
0
    if (res[0])
901
0
      strcat(res, ".");
902
903
0
    strcat(res, lname);
904
0
  }
905
906
0
  return res;
907
0
}
908
909
char *pdf_load_field_name(fz_context *ctx, pdf_obj *field)
910
0
{
911
0
  return load_field_name(ctx, field, 0, NULL);
912
0
}
913
914
void pdf_create_field_name(fz_context *ctx, pdf_document *doc, const char *prefix, char *buf, size_t len)
915
0
{
916
0
  pdf_obj *form = pdf_dict_getl(ctx, pdf_trailer(ctx, doc),
917
0
    PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(Fields), NULL);
918
0
  int i;
919
0
  for (i = 0; i < 65536; ++i) {
920
0
    fz_snprintf(buf, len, "%s%d", prefix, i);
921
0
    if (!pdf_lookup_field(ctx, form, buf))
922
0
      return;
923
0
  }
924
0
  fz_throw(ctx, FZ_ERROR_LIMIT, "Could not create unique field name.");
925
0
}
926
927
const char *pdf_field_label(fz_context *ctx, pdf_obj *field)
928
0
{
929
0
  pdf_obj *label = pdf_dict_get_inheritable(ctx, field, PDF_NAME(TU));
930
0
  if (!label)
931
0
    label = pdf_dict_get_inheritable(ctx, field, PDF_NAME(T));
932
0
  if (label)
933
0
    return pdf_to_text_string(ctx, label);
934
0
  return "Unnamed";
935
0
}
936
937
void pdf_field_set_display(fz_context *ctx, pdf_obj *field, int d)
938
0
{
939
0
  pdf_obj *kids = pdf_dict_get(ctx, field, PDF_NAME(Kids));
940
941
0
  if (!kids)
942
0
  {
943
0
    int mask = (PDF_ANNOT_IS_HIDDEN|PDF_ANNOT_IS_PRINT|PDF_ANNOT_IS_NO_VIEW);
944
0
    int f = pdf_dict_get_int(ctx, field, PDF_NAME(F)) & ~mask;
945
946
0
    switch (d)
947
0
    {
948
0
    case Display_Visible:
949
0
      f |= PDF_ANNOT_IS_PRINT;
950
0
      break;
951
0
    case Display_Hidden:
952
0
      f |= PDF_ANNOT_IS_HIDDEN;
953
0
      break;
954
0
    case Display_NoView:
955
0
      f |= (PDF_ANNOT_IS_PRINT|PDF_ANNOT_IS_NO_VIEW);
956
0
      break;
957
0
    case Display_NoPrint:
958
0
      break;
959
0
    }
960
961
0
    pdf_dict_put_int(ctx, field, PDF_NAME(F), f);
962
0
  }
963
0
  else
964
0
  {
965
0
    int i, n = pdf_array_len(ctx, kids);
966
967
0
    for (i = 0; i < n; i++)
968
0
      pdf_field_set_display(ctx, pdf_array_get(ctx, kids, i), d);
969
0
  }
970
0
}
971
972
void pdf_field_set_fill_color(fz_context *ctx, pdf_obj *field, pdf_obj *col)
973
0
{
974
  /* col == NULL mean transparent, but we can simply pass it on as with
975
   * non-NULL values because pdf_dict_putp interprets a NULL value as
976
   * delete */
977
0
  pdf_dict_putl(ctx, field, col, PDF_NAME(MK), PDF_NAME(BG), NULL);
978
0
  pdf_field_mark_dirty(ctx, field);
979
0
}
980
981
void pdf_field_set_text_color(fz_context *ctx, pdf_obj *field, pdf_obj *col)
982
0
{
983
0
  char buf[100];
984
0
  const char *font;
985
0
  float size, color[4];
986
  /* TODO? */
987
0
  const char *da = pdf_to_str_buf(ctx, pdf_dict_get_inheritable(ctx, field, PDF_NAME(DA)));
988
0
  int n;
989
990
0
  pdf_parse_default_appearance(ctx, da, &font, &size, &n, color);
991
992
0
  switch (pdf_array_len(ctx, col))
993
0
  {
994
0
  default:
995
0
    n = 0;
996
0
    color[0] = color[1] = color[2] = color[3] = 0;
997
0
    break;
998
0
  case 1:
999
0
    n = 1;
1000
0
    color[0] = pdf_array_get_real(ctx, col, 0);
1001
0
    break;
1002
0
  case 3:
1003
0
    n = 3;
1004
0
    color[0] = pdf_array_get_real(ctx, col, 0);
1005
0
    color[1] = pdf_array_get_real(ctx, col, 1);
1006
0
    color[2] = pdf_array_get_real(ctx, col, 2);
1007
0
    break;
1008
0
  case 4:
1009
0
    n = 4;
1010
0
    color[0] = pdf_array_get_real(ctx, col, 0);
1011
0
    color[1] = pdf_array_get_real(ctx, col, 1);
1012
0
    color[2] = pdf_array_get_real(ctx, col, 2);
1013
0
    color[3] = pdf_array_get_real(ctx, col, 3);
1014
0
    break;
1015
0
  }
1016
1017
0
  pdf_print_default_appearance(ctx, buf, sizeof buf, font, size, n, color);
1018
0
  pdf_dict_put_string(ctx, field, PDF_NAME(DA), buf, strlen(buf));
1019
0
  pdf_field_mark_dirty(ctx, field);
1020
0
}
1021
1022
pdf_annot *
1023
pdf_keep_widget(fz_context *ctx, pdf_annot *widget)
1024
0
{
1025
0
  return pdf_keep_annot(ctx, widget);
1026
0
}
1027
1028
void
1029
pdf_drop_widget(fz_context *ctx, pdf_annot *widget)
1030
360
{
1031
360
  pdf_drop_annot(ctx, widget);
1032
360
}
1033
1034
void
1035
pdf_drop_widgets(fz_context *ctx, pdf_annot *widget)
1036
335
{
1037
695
  while (widget)
1038
360
  {
1039
360
    pdf_annot *next = widget->next;
1040
360
    pdf_drop_widget(ctx, widget);
1041
360
    widget = next;
1042
360
  }
1043
335
}
1044
1045
pdf_annot *
1046
pdf_create_signature_widget(fz_context *ctx, pdf_page *page, char *name)
1047
0
{
1048
0
  fz_rect rect = { 12, 12, 12+100, 12+50 };
1049
0
  pdf_annot *annot;
1050
1051
0
  pdf_begin_operation(ctx, page->doc, "Create signature");
1052
1053
0
  annot = pdf_create_annot_raw(ctx, page, PDF_ANNOT_WIDGET);
1054
1055
0
  fz_try(ctx)
1056
0
  {
1057
0
    pdf_obj *obj = annot->obj;
1058
0
    pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, page->doc), PDF_NAME(Root));
1059
0
    pdf_obj *acroform = pdf_dict_get(ctx, root, PDF_NAME(AcroForm));
1060
0
    pdf_obj *fields, *lock;
1061
0
    if (!acroform)
1062
0
    {
1063
0
      acroform = pdf_new_dict(ctx, page->doc, 1);
1064
0
      pdf_dict_put_drop(ctx, root, PDF_NAME(AcroForm), acroform);
1065
0
    }
1066
0
    fields = pdf_dict_get(ctx, acroform, PDF_NAME(Fields));
1067
0
    if (!fields)
1068
0
    {
1069
0
      fields = pdf_new_array(ctx, page->doc, 1);
1070
0
      pdf_dict_put_drop(ctx, acroform, PDF_NAME(Fields), fields);
1071
0
    }
1072
0
    pdf_set_annot_rect(ctx, annot, rect);
1073
0
    pdf_dict_put(ctx, obj, PDF_NAME(FT), PDF_NAME(Sig));
1074
0
    pdf_dict_put_int(ctx, obj, PDF_NAME(F), PDF_ANNOT_IS_PRINT);
1075
0
    pdf_dict_put_text_string(ctx, obj, PDF_NAME(DA), "/Helv 0 Tf 0 g");
1076
0
    pdf_dict_put_text_string(ctx, obj, PDF_NAME(T), name);
1077
0
    pdf_array_push(ctx, fields, obj);
1078
0
    lock = pdf_dict_put_dict(ctx, obj, PDF_NAME(Lock), 1);
1079
0
    pdf_dict_put(ctx, lock, PDF_NAME(Action), PDF_NAME(All));
1080
0
    pdf_end_operation(ctx, page->doc);
1081
0
  }
1082
0
  fz_catch(ctx)
1083
0
  {
1084
0
    pdf_abandon_operation(ctx, page->doc);
1085
0
    pdf_delete_annot(ctx, page, annot);
1086
0
  }
1087
0
  return (pdf_annot *)annot;
1088
0
}
1089
1090
fz_rect
1091
pdf_bound_widget(fz_context *ctx, pdf_annot *widget)
1092
0
{
1093
0
  return pdf_bound_annot(ctx, widget);
1094
0
}
1095
1096
int
1097
pdf_update_widget(fz_context *ctx, pdf_annot *widget)
1098
0
{
1099
0
  return pdf_update_annot(ctx, widget);
1100
0
}
1101
1102
int pdf_text_widget_max_len(fz_context *ctx, pdf_annot *tw)
1103
0
{
1104
0
  pdf_annot *annot = (pdf_annot *)tw;
1105
0
  return pdf_dict_get_inheritable_int(ctx, annot->obj, PDF_NAME(MaxLen));
1106
0
}
1107
1108
int pdf_text_widget_format(fz_context *ctx, pdf_annot *tw)
1109
0
{
1110
0
  pdf_annot *annot = (pdf_annot *)tw;
1111
0
  int type = PDF_WIDGET_TX_FORMAT_NONE;
1112
0
  pdf_obj *js = pdf_dict_getl(ctx, annot->obj, PDF_NAME(AA), PDF_NAME(F), PDF_NAME(JS), NULL);
1113
0
  if (js)
1114
0
  {
1115
0
    char *code = pdf_load_stream_or_string_as_utf8(ctx, js);
1116
0
    if (strstr(code, "AFNumber_Format"))
1117
0
      type = PDF_WIDGET_TX_FORMAT_NUMBER;
1118
0
    else if (strstr(code, "AFSpecial_Format"))
1119
0
      type = PDF_WIDGET_TX_FORMAT_SPECIAL;
1120
0
    else if (strstr(code, "AFDate_FormatEx"))
1121
0
      type = PDF_WIDGET_TX_FORMAT_DATE;
1122
0
    else if (strstr(code, "AFTime_FormatEx"))
1123
0
      type = PDF_WIDGET_TX_FORMAT_TIME;
1124
0
    fz_free(ctx, code);
1125
0
  }
1126
1127
0
  return type;
1128
0
}
1129
1130
static char *
1131
merge_changes(fz_context *ctx, const char *value, int start, int end, const char *change)
1132
0
{
1133
0
  int changelen = change ? (int)strlen(change) : 0;
1134
0
  int valuelen = value ? (int)strlen(value) : 0;
1135
0
  int prelen = (start >= 0 ? (start < valuelen ? start : valuelen) : 0);
1136
0
  int postlen = (end >= 0 && end <= valuelen ? valuelen - end : 0);
1137
0
  int newlen =  prelen + changelen + postlen + 1;
1138
0
  char *merged = fz_malloc(ctx, newlen);
1139
0
  char *m = merged;
1140
1141
0
  if (prelen)
1142
0
  {
1143
0
    memcpy(m, value, prelen);
1144
0
    m += prelen;
1145
0
  }
1146
0
  if (changelen)
1147
0
  {
1148
0
    memcpy(m, change, changelen);
1149
0
    m += changelen;
1150
0
  }
1151
0
  if (postlen)
1152
0
  {
1153
0
    memcpy(m, &value[end], postlen);
1154
0
    m += postlen;
1155
0
  }
1156
0
  *m = 0;
1157
1158
0
  return merged;
1159
0
}
1160
1161
int pdf_set_text_field_value(fz_context *ctx, pdf_annot *widget, const char *update)
1162
0
{
1163
0
  pdf_document *doc;
1164
0
  pdf_keystroke_event evt = { 0 };
1165
0
  char *new_change = NULL;
1166
0
  char *new_value = NULL;
1167
0
  char *merged_value = NULL;
1168
0
  int rc = 1;
1169
1170
0
  begin_annot_op(ctx, widget, "Edit text field");
1171
0
  doc = widget->page->doc;
1172
1173
0
  fz_var(new_value);
1174
0
  fz_var(new_change);
1175
0
  fz_var(merged_value);
1176
0
  fz_try(ctx)
1177
0
  {
1178
0
    if (!widget->ignore_trigger_events)
1179
0
    {
1180
0
      evt.value = pdf_annot_field_value(ctx, widget);
1181
0
      evt.change = update;
1182
0
      evt.selStart = 0;
1183
0
      evt.selEnd = (int)strlen(evt.value);
1184
0
      evt.willCommit = 0;
1185
0
      rc = pdf_annot_field_event_keystroke(ctx, doc, widget, &evt);
1186
0
      new_change = evt.newChange;
1187
0
      new_value = evt.newValue;
1188
0
      evt.newValue = NULL;
1189
0
      evt.newChange = NULL;
1190
0
      if (rc)
1191
0
      {
1192
0
        merged_value = merge_changes(ctx, new_value, evt.selStart, evt.selEnd, new_change);
1193
0
        evt.value = merged_value;
1194
0
        evt.change = "";
1195
0
        evt.selStart = -1;
1196
0
        evt.selEnd = -1;
1197
0
        evt.willCommit = 1;
1198
0
        rc = pdf_annot_field_event_keystroke(ctx, doc, widget, &evt);
1199
0
        if (rc)
1200
0
          rc = pdf_set_annot_field_value(ctx, doc, widget, evt.newValue, 0);
1201
0
      }
1202
0
    }
1203
0
    else
1204
0
    {
1205
0
      rc = pdf_set_annot_field_value(ctx, doc, widget, update, 1);
1206
0
    }
1207
0
    end_annot_op(ctx, widget);
1208
0
  }
1209
0
  fz_always(ctx)
1210
0
  {
1211
0
    fz_free(ctx, new_value);
1212
0
    fz_free(ctx, evt.newValue);
1213
0
    fz_free(ctx, new_change);
1214
0
    fz_free(ctx, evt.newChange);
1215
0
    fz_free(ctx, merged_value);
1216
0
  }
1217
0
  fz_catch(ctx)
1218
0
  {
1219
0
    abandon_annot_op(ctx, widget);
1220
0
    fz_warn(ctx, "could not set widget text");
1221
0
    rc = 0;
1222
0
  }
1223
0
  return rc;
1224
0
}
1225
1226
int pdf_edit_text_field_value(fz_context *ctx, pdf_annot *widget, const char *value, const char *change, int *selStart, int *selEnd, char **result)
1227
0
{
1228
0
  pdf_document *doc = widget->page->doc;
1229
0
  pdf_keystroke_event evt = {0};
1230
0
  int rc = 1;
1231
1232
0
  pdf_begin_operation(ctx, doc, "Text field keystroke");
1233
1234
0
  fz_try(ctx)
1235
0
  {
1236
0
    if (!widget->ignore_trigger_events)
1237
0
    {
1238
0
      evt.value = value;
1239
0
      evt.change = change;
1240
0
      evt.selStart = *selStart;
1241
0
      evt.selEnd = *selEnd;
1242
0
      evt.willCommit = 0;
1243
0
      rc = pdf_annot_field_event_keystroke(ctx, doc, widget, &evt);
1244
0
      if (rc)
1245
0
      {
1246
0
        *result = merge_changes(ctx, evt.newValue, evt.selStart, evt.selEnd, evt.newChange);
1247
0
        *selStart = evt.selStart + (int)strlen(evt.newChange);
1248
0
        *selEnd = *selStart;
1249
0
      }
1250
0
    }
1251
0
    else
1252
0
    {
1253
0
      *result = merge_changes(ctx, value, *selStart, *selEnd, change);
1254
0
      *selStart = evt.selStart + (int)strlen(change);
1255
0
      *selEnd = *selStart;
1256
0
    }
1257
0
    pdf_end_operation(ctx, doc);
1258
0
  }
1259
0
  fz_always(ctx)
1260
0
  {
1261
0
    fz_free(ctx, evt.newValue);
1262
0
    fz_free(ctx, evt.newChange);
1263
0
  }
1264
0
  fz_catch(ctx)
1265
0
  {
1266
0
    pdf_abandon_operation(ctx, doc);
1267
0
    fz_warn(ctx, "could not process text widget keystroke");
1268
0
    rc = 0;
1269
0
  }
1270
0
  return rc;
1271
0
}
1272
1273
int pdf_set_choice_field_value(fz_context *ctx, pdf_annot *widget, const char *new_value)
1274
0
{
1275
  /* Choice widgets use almost the same keystroke processing as text fields. */
1276
0
  return pdf_set_text_field_value(ctx, widget, new_value);
1277
0
}
1278
1279
int pdf_choice_widget_options(fz_context *ctx, pdf_annot *tw, int exportval, const char *opts[])
1280
0
{
1281
0
  pdf_annot *annot = (pdf_annot *)tw;
1282
0
  pdf_obj *optarr;
1283
0
  int i, n, m;
1284
1285
0
  optarr = pdf_dict_get_inheritable(ctx, annot->obj, PDF_NAME(Opt));
1286
0
  n = pdf_array_len(ctx, optarr);
1287
1288
0
  if (opts)
1289
0
  {
1290
0
    for (i = 0; i < n; i++)
1291
0
    {
1292
0
      m = pdf_array_len(ctx, pdf_array_get(ctx, optarr, i));
1293
      /* If it is a two element array, the second item is the one that we want if we want the listing value. */
1294
0
      if (m == 2)
1295
0
        if (exportval)
1296
0
          opts[i] = pdf_array_get_text_string(ctx, pdf_array_get(ctx, optarr, i), 0);
1297
0
        else
1298
0
          opts[i] = pdf_array_get_text_string(ctx, pdf_array_get(ctx, optarr, i), 1);
1299
0
      else
1300
0
        opts[i] = pdf_array_get_text_string(ctx, optarr, i);
1301
0
    }
1302
0
  }
1303
0
  return n;
1304
0
}
1305
1306
int pdf_choice_field_option_count(fz_context *ctx, pdf_obj *field)
1307
0
{
1308
0
  pdf_obj *opt = pdf_dict_get_inheritable(ctx, field, PDF_NAME(Opt));
1309
0
  return pdf_array_len(ctx, opt);
1310
0
}
1311
1312
const char *pdf_choice_field_option(fz_context *ctx, pdf_obj *field, int export, int i)
1313
0
{
1314
0
  pdf_obj *opt = pdf_dict_get_inheritable(ctx, field, PDF_NAME(Opt));
1315
0
  pdf_obj *ent = pdf_array_get(ctx, opt, i);
1316
0
  if (pdf_array_len(ctx, ent) == 2)
1317
0
    return pdf_array_get_text_string(ctx, ent, export ? 0 : 1);
1318
0
  else
1319
0
    return pdf_to_text_string(ctx, ent);
1320
0
}
1321
1322
int pdf_choice_widget_is_multiselect(fz_context *ctx, pdf_annot *tw)
1323
0
{
1324
0
  pdf_annot *annot = (pdf_annot *)tw;
1325
1326
0
  if (!annot) return 0;
1327
1328
0
  switch (pdf_field_type(ctx, annot->obj))
1329
0
  {
1330
0
  case PDF_WIDGET_TYPE_LISTBOX:
1331
0
    return (pdf_field_flags(ctx, annot->obj) & PDF_CH_FIELD_IS_MULTI_SELECT) != 0;
1332
0
  default:
1333
0
    return 0;
1334
0
  }
1335
0
}
1336
1337
int pdf_choice_widget_value(fz_context *ctx, pdf_annot *tw, const char *opts[])
1338
0
{
1339
0
  pdf_annot *annot = (pdf_annot *)tw;
1340
0
  pdf_obj *optarr;
1341
0
  int i, n;
1342
1343
0
  if (!annot)
1344
0
    return 0;
1345
1346
0
  optarr = pdf_dict_get(ctx, annot->obj, PDF_NAME(V));
1347
1348
0
  if (pdf_is_string(ctx, optarr))
1349
0
  {
1350
0
    if (opts)
1351
0
      opts[0] = pdf_to_text_string(ctx, optarr);
1352
0
    return 1;
1353
0
  }
1354
0
  else
1355
0
  {
1356
0
    n = pdf_array_len(ctx, optarr);
1357
0
    if (opts)
1358
0
    {
1359
0
      for (i = 0; i < n; i++)
1360
0
      {
1361
0
        pdf_obj *elem = pdf_array_get(ctx, optarr, i);
1362
0
        if (pdf_is_array(ctx, elem))
1363
0
          elem = pdf_array_get(ctx, elem, 1);
1364
0
        opts[i] = pdf_to_text_string(ctx, elem);
1365
0
      }
1366
0
    }
1367
0
    return n;
1368
0
  }
1369
0
}
1370
1371
void pdf_choice_widget_set_value(fz_context *ctx, pdf_annot *tw, int n, const char *opts[])
1372
0
{
1373
0
  pdf_annot *annot = (pdf_annot *)tw;
1374
0
  pdf_obj *optarr = NULL;
1375
0
  int i;
1376
1377
0
  if (!annot)
1378
0
    return;
1379
1380
0
  begin_annot_op(ctx, annot, "Set choice");
1381
1382
0
  fz_var(optarr);
1383
0
  fz_try(ctx)
1384
0
  {
1385
0
    if (n != 1)
1386
0
    {
1387
0
      optarr = pdf_new_array(ctx, annot->page->doc, n);
1388
1389
0
      for (i = 0; i < n; i++)
1390
0
        pdf_array_push_text_string(ctx, optarr, opts[i]);
1391
1392
0
      pdf_dict_put_drop(ctx, annot->obj, PDF_NAME(V), optarr);
1393
0
    }
1394
0
    else
1395
0
      pdf_dict_put_text_string(ctx, annot->obj, PDF_NAME(V), opts[0]);
1396
1397
    /* FIXME: when n > 1, we should be regenerating the indexes */
1398
0
    pdf_dict_del(ctx, annot->obj, PDF_NAME(I));
1399
1400
0
    pdf_field_mark_dirty(ctx, annot->obj);
1401
0
    end_annot_op(ctx, annot);
1402
0
  }
1403
0
  fz_catch(ctx)
1404
0
  {
1405
0
    abandon_annot_op(ctx, annot);
1406
0
    pdf_drop_obj(ctx, optarr);
1407
0
    fz_rethrow(ctx);
1408
0
  }
1409
0
}
1410
1411
int pdf_signature_byte_range(fz_context *ctx, pdf_document *doc, pdf_obj *signature, fz_range *byte_range)
1412
0
{
1413
0
  pdf_obj *br = pdf_dict_getl(ctx, signature, PDF_NAME(V), PDF_NAME(ByteRange), NULL);
1414
0
  int i, n = pdf_array_len(ctx, br)/2;
1415
1416
0
  if (byte_range)
1417
0
  {
1418
0
    for (i = 0; i < n; i++)
1419
0
    {
1420
0
      int64_t offset = pdf_array_get_int(ctx, br, 2*i);
1421
0
      int length = pdf_array_get_int(ctx, br, 2*i+1);
1422
1423
0
      if (offset < 0 || offset > doc->file_size)
1424
0
        fz_throw(ctx, FZ_ERROR_FORMAT, "offset of signature byte range outside of file");
1425
0
      else if (length < 0)
1426
0
        fz_throw(ctx, FZ_ERROR_FORMAT, "length of signature byte range negative");
1427
0
      else if (offset + length > doc->file_size)
1428
0
        fz_throw(ctx, FZ_ERROR_FORMAT, "signature byte range extends past end of file");
1429
1430
0
      byte_range[i].offset = offset;
1431
0
      byte_range[i].length = length;
1432
0
    }
1433
0
  }
1434
1435
0
  return n;
1436
0
}
1437
1438
static int is_white(int c)
1439
0
{
1440
0
  return c == '\x00' || c == '\x09' || c == '\x0a' || c == '\x0c' || c == '\x0d' || c == '\x20';
1441
0
}
1442
1443
static int is_hex_or_white(int c)
1444
0
{
1445
0
  return (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9') || is_white(c);
1446
0
}
1447
1448
static void validate_certificate_data(fz_context *ctx, pdf_document *doc, fz_range *hole)
1449
0
{
1450
0
  fz_stream *stm;
1451
0
  int c;
1452
1453
0
  stm = fz_open_range_filter(ctx, doc->file, hole, 1);
1454
0
  fz_try(ctx)
1455
0
  {
1456
0
    while (is_white((c = fz_read_byte(ctx, stm))))
1457
0
      ;
1458
1459
0
    if (c == '<')
1460
0
      c = fz_read_byte(ctx, stm);
1461
1462
0
    while (is_hex_or_white(c))
1463
0
      c = fz_read_byte(ctx, stm);
1464
1465
0
    if (c == '>')
1466
0
      c = fz_read_byte(ctx, stm);
1467
1468
0
    while (is_white(c))
1469
0
      c = fz_read_byte(ctx, stm);
1470
1471
0
    if (c != EOF)
1472
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "signature certificate data contains invalid character");
1473
0
    if ((size_t)fz_tell(ctx, stm) != hole->length)
1474
0
      fz_throw(ctx, FZ_ERROR_FORMAT, "premature end of signature certificate data");
1475
0
  }
1476
0
  fz_always(ctx)
1477
0
    fz_drop_stream(ctx, stm);
1478
0
  fz_catch(ctx)
1479
0
    fz_rethrow(ctx);
1480
0
}
1481
1482
static int rangecmp(const void *a_, const void *b_)
1483
0
{
1484
0
  const fz_range *a = (const fz_range *) a_;
1485
0
  const fz_range *b = (const fz_range *) b_;
1486
0
  return (int) (a->offset - b->offset);
1487
0
}
1488
1489
static void validate_byte_ranges(fz_context *ctx, pdf_document *doc, fz_range *unsorted, int nranges)
1490
0
{
1491
0
  int64_t offset = 0;
1492
0
  fz_range *sorted;
1493
0
  int i;
1494
1495
0
  sorted = fz_calloc(ctx, nranges, sizeof(*sorted));
1496
0
  memcpy(sorted, unsorted, nranges * sizeof(*sorted));
1497
0
  qsort(sorted, nranges, sizeof(*sorted), rangecmp);
1498
1499
0
  fz_try(ctx)
1500
0
  {
1501
0
    offset = 0;
1502
1503
0
    for (i = 0; i < nranges; i++)
1504
0
    {
1505
0
      if (sorted[i].offset > offset)
1506
0
      {
1507
0
        fz_range hole;
1508
1509
0
        hole.offset = offset;
1510
0
        hole.length = sorted[i].offset - offset;
1511
1512
0
        validate_certificate_data(ctx, doc, &hole);
1513
0
      }
1514
1515
0
      offset = fz_maxi64(offset, sorted[i].offset + sorted[i].length);
1516
0
    }
1517
0
  }
1518
0
  fz_always(ctx)
1519
0
    fz_free(ctx, sorted);
1520
0
  fz_catch(ctx)
1521
0
    fz_rethrow(ctx);
1522
0
}
1523
1524
fz_stream *pdf_signature_hash_bytes(fz_context *ctx, pdf_document *doc, pdf_obj *signature)
1525
0
{
1526
0
  fz_range *byte_range = NULL;
1527
0
  int byte_range_len;
1528
0
  fz_stream *bytes = NULL;
1529
1530
0
  fz_var(byte_range);
1531
0
  fz_try(ctx)
1532
0
  {
1533
0
    byte_range_len = pdf_signature_byte_range(ctx, doc, signature, NULL);
1534
0
    if (byte_range_len)
1535
0
    {
1536
0
      byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
1537
0
      pdf_signature_byte_range(ctx, doc, signature, byte_range);
1538
0
    }
1539
1540
0
    validate_byte_ranges(ctx, doc, byte_range, byte_range_len);
1541
0
    bytes = fz_open_range_filter(ctx, doc->file, byte_range, byte_range_len);
1542
0
  }
1543
0
  fz_always(ctx)
1544
0
  {
1545
0
    fz_free(ctx, byte_range);
1546
0
  }
1547
0
  fz_catch(ctx)
1548
0
  {
1549
0
    fz_rethrow(ctx);
1550
0
  }
1551
1552
0
  return bytes;
1553
0
}
1554
1555
int pdf_incremental_change_since_signing_widget(fz_context *ctx, pdf_annot *widget)
1556
0
{
1557
0
  if (!widget->page)
1558
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
1559
0
  return pdf_signature_incremental_change_since_signing(ctx, widget->page->doc, widget->obj);
1560
0
}
1561
1562
int pdf_signature_incremental_change_since_signing(fz_context *ctx, pdf_document *doc, pdf_obj *signature)
1563
0
{
1564
0
  fz_range *byte_range = NULL;
1565
0
  int byte_range_len;
1566
0
  int changed = 0;
1567
1568
0
  if (pdf_dict_get_inheritable(ctx, signature, PDF_NAME(FT)) != PDF_NAME(Sig))
1569
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation is not a signature widget");
1570
0
  if (!pdf_signature_is_signed(ctx, doc, signature))
1571
0
    return 0;
1572
1573
0
  fz_var(byte_range);
1574
0
  fz_try(ctx)
1575
0
  {
1576
0
    byte_range_len = pdf_signature_byte_range(ctx, doc, signature, NULL);
1577
0
    if (byte_range_len)
1578
0
    {
1579
0
      fz_range *last_range;
1580
0
      int64_t end_of_range;
1581
1582
0
      byte_range = fz_calloc(ctx, byte_range_len, sizeof(*byte_range));
1583
0
      pdf_signature_byte_range(ctx, doc, signature, byte_range);
1584
1585
0
      last_range = &byte_range[byte_range_len -1];
1586
0
      end_of_range = last_range->offset + last_range->length;
1587
1588
      /* We can see how long the document was when signed by inspecting the byte
1589
       * ranges of the signature.  The document, when read in, may have already
1590
       * had changes tagged on to it, past its extent when signed, or we may have
1591
       * made changes since reading it, which will be held in a new incremental
1592
       * xref section. */
1593
0
      if (doc->file_size > end_of_range || doc->num_incremental_sections > 0)
1594
0
        changed = 1;
1595
0
    }
1596
0
  }
1597
0
  fz_always(ctx)
1598
0
  {
1599
0
    fz_free(ctx, byte_range);
1600
0
  }
1601
0
  fz_catch(ctx)
1602
0
  {
1603
0
    fz_rethrow(ctx);
1604
0
  }
1605
1606
0
  return changed;
1607
0
}
1608
1609
int pdf_signature_is_signed(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1610
0
{
1611
0
  pdf_obj *v;
1612
0
  pdf_obj* vtype;
1613
1614
0
  if (pdf_dict_get_inheritable(ctx, field, PDF_NAME(FT)) != PDF_NAME(Sig))
1615
0
    return 0;
1616
  /* Signatures can only be signed if the value is a dictionary,
1617
   * and if the value has a Type, it should be Sig. */
1618
0
  v = pdf_dict_get_inheritable(ctx, field, PDF_NAME(V));
1619
0
  vtype = pdf_dict_get(ctx, v, PDF_NAME(Type));
1620
0
  return pdf_is_dict(ctx, v) && (vtype ? pdf_name_eq(ctx, vtype, PDF_NAME(Sig)) : 1);
1621
0
}
1622
1623
int pdf_widget_is_signed(fz_context *ctx, pdf_annot *widget)
1624
0
{
1625
0
  if (widget == NULL)
1626
0
    return 0;
1627
1628
0
  if (!widget->page)
1629
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "annotation not bound to any page");
1630
1631
0
  return pdf_signature_is_signed(ctx, widget->page->doc, widget->obj);
1632
0
}
1633
1634
int pdf_widget_is_readonly(fz_context *ctx, pdf_annot *widget)
1635
0
{
1636
0
  int fflags;
1637
0
  if (widget == NULL)
1638
0
    return 0;
1639
0
  fflags = pdf_field_flags(ctx, ((pdf_annot *) widget)->obj);
1640
0
  return fflags & PDF_FIELD_IS_READ_ONLY;
1641
0
}
1642
1643
size_t pdf_signature_contents(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char **contents)
1644
0
{
1645
0
  pdf_obj *v_ref = pdf_dict_get_inheritable(ctx, signature, PDF_NAME(V));
1646
0
  pdf_obj *v_obj = pdf_load_unencrypted_object(ctx, doc, pdf_to_num(ctx, v_ref));
1647
0
  char *copy = NULL;
1648
0
  size_t len;
1649
1650
0
  fz_var(copy);
1651
0
  fz_try(ctx)
1652
0
  {
1653
0
    pdf_obj *c = pdf_dict_get(ctx, v_obj, PDF_NAME(Contents));
1654
0
    char *s;
1655
1656
0
    s = pdf_to_str_buf(ctx, c);
1657
0
    len = pdf_to_str_len(ctx, c);
1658
1659
0
    if (contents)
1660
0
    {
1661
0
      copy = Memento_label(fz_malloc(ctx, len), "sig_contents");
1662
0
      memcpy(copy, s, len);
1663
0
    }
1664
0
  }
1665
0
  fz_always(ctx)
1666
0
    pdf_drop_obj(ctx, v_obj);
1667
0
  fz_catch(ctx)
1668
0
  {
1669
0
    fz_free(ctx, copy);
1670
0
    fz_rethrow(ctx);
1671
0
  }
1672
1673
0
  if (contents)
1674
0
    *contents = copy;
1675
0
  return len;
1676
0
}
1677
1678
static fz_xml_doc *load_xfa(fz_context *ctx, pdf_document *doc)
1679
0
{
1680
0
  pdf_obj *xfa;
1681
0
  fz_buffer *buf = NULL;
1682
0
  fz_buffer *packet = NULL;
1683
0
  int i;
1684
1685
0
  if (doc->xfa)
1686
0
    return doc->xfa; /* Already loaded, and present. */
1687
1688
0
  xfa = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/XFA");
1689
0
  if (!pdf_is_array(ctx, xfa) && !pdf_is_stream(ctx, xfa))
1690
0
    return NULL; /* No XFA */
1691
1692
0
  fz_var(buf);
1693
0
  fz_var(packet);
1694
1695
0
  fz_try(ctx)
1696
0
  {
1697
0
    if (pdf_is_stream(ctx, xfa))
1698
0
    {
1699
      /* Load entire XFA resource */
1700
0
      buf = pdf_load_stream(ctx, xfa);
1701
0
    }
1702
0
    else
1703
0
    {
1704
      /* Concatenate packets to create entire XFA resource */
1705
0
      buf = fz_new_buffer(ctx, 1024);
1706
0
      for(i = 0; i < pdf_array_len(ctx, xfa); ++i)
1707
0
      {
1708
0
        pdf_obj *ref = pdf_array_get(ctx, xfa, i);
1709
0
        if (pdf_is_stream(ctx, ref))
1710
0
        {
1711
0
          packet = pdf_load_stream(ctx, ref);
1712
0
          fz_append_buffer(ctx, buf, packet);
1713
0
          fz_drop_buffer(ctx, packet);
1714
0
          packet = NULL;
1715
0
        }
1716
0
      }
1717
0
    }
1718
1719
    /* Parse and stow away XFA resource in document */
1720
0
    doc->xfa = fz_parse_xml(ctx, buf, 0);
1721
0
  }
1722
0
  fz_always(ctx)
1723
0
  {
1724
0
    fz_drop_buffer(ctx, packet);
1725
0
    fz_drop_buffer(ctx, buf);
1726
0
  }
1727
0
  fz_catch(ctx)
1728
0
  {
1729
0
    fz_rethrow(ctx);
1730
0
  }
1731
1732
0
  return doc->xfa;
1733
0
}
1734
1735
static fz_xml *
1736
get_xfa_resource(fz_context *ctx, pdf_document *doc, const char *str)
1737
0
{
1738
0
  fz_xml_doc *xfa;
1739
1740
0
  xfa = load_xfa(ctx, doc);
1741
0
  if (!xfa)
1742
0
    return NULL;
1743
1744
0
  return fz_xml_find_down(fz_xml_root(xfa), str);
1745
0
}
1746
1747
static int
1748
find_name_component(char **np, char **sp, char **ep)
1749
0
{
1750
0
  char *n = *np;
1751
0
  char *s, *e;
1752
0
  int idx = 0;
1753
1754
0
  if (*n == '.')
1755
0
    n++;
1756
1757
  /* Find the next name we are looking for. */
1758
0
  s = e = n;
1759
0
  while (*e && *e != '[' && *e != '.')
1760
0
    e++;
1761
1762
  /* So the next name is s..e */
1763
0
  n = e;
1764
0
  if (*n == '[')
1765
0
  {
1766
0
    n++;
1767
0
    while (*n >= '0' && *n <= '9')
1768
0
      idx = idx*10 + *n++ - '0';
1769
0
    while (*n && *n != ']')
1770
0
      n++;
1771
0
    if (*n == ']')
1772
0
      n++;
1773
0
  }
1774
0
  *np = n;
1775
0
  *sp = s;
1776
0
  *ep = e;
1777
1778
0
  return idx;
1779
0
}
1780
1781
static pdf_obj *
1782
annot_from_name(fz_context *ctx, pdf_document *doc, const char *str)
1783
0
{
1784
0
  pdf_obj *fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
1785
1786
0
  if (strncmp(str, "xfa[0].", 7) == 0)
1787
0
    str += 7;
1788
0
  if (strncmp(str, "template[0].", 12) == 0)
1789
0
    str += 12;
1790
1791
0
  return pdf_lookup_field(ctx, fields, str);
1792
0
}
1793
1794
static pdf_obj *
1795
get_locked_fields_from_xfa(fz_context *ctx, pdf_document *doc, pdf_obj *field)
1796
0
{
1797
0
  char *name = pdf_load_field_name(ctx, field);
1798
0
  char *n = name;
1799
0
  const char *use;
1800
0
  fz_xml *node;
1801
1802
0
  if (name == NULL)
1803
0
    return NULL;
1804
1805
0
  fz_try(ctx)
1806
0
  {
1807
0
    node = get_xfa_resource(ctx, doc, "template");
1808
1809
0
    do
1810
0
    {
1811
0
      char c, *s, *e;
1812
0
      int idx = 0;
1813
0
      char *key;
1814
1815
0
      idx = find_name_component(&n, &s, &e);
1816
      /* We want the idx'th occurrence of s..e */
1817
1818
      /* Hacky */
1819
0
      c = *e;
1820
0
      *e = 0;
1821
0
      key = *n ? "subform" : "field";
1822
0
      node = fz_xml_find_down_match(node, key, "name", s);
1823
0
      while (node && idx > 0)
1824
0
      {
1825
0
        node = fz_xml_find_next_match(node, key, "name", s);
1826
0
        idx--;
1827
0
      }
1828
0
      *e = c;
1829
0
    }
1830
0
    while (node && *n == '.');
1831
0
  }
1832
0
  fz_always(ctx)
1833
0
    fz_free(ctx, name);
1834
0
  fz_catch(ctx)
1835
0
    fz_rethrow(ctx);
1836
1837
0
  if (node == NULL)
1838
0
    return NULL;
1839
1840
0
  node = fz_xml_find_down(node, "ui");
1841
0
  node = fz_xml_find_down(node, "signature");
1842
0
  node = fz_xml_find_down(node, "manifest");
1843
1844
0
  use = fz_xml_att(node, "use");
1845
0
  if (use == NULL)
1846
0
    return NULL;
1847
0
  if (*use == '#')
1848
0
    use++;
1849
1850
  /* Now look for a variables entry in a subform that defines this. */
1851
0
  while (node)
1852
0
  {
1853
0
    fz_xml *variables, *manifest, *ref;
1854
0
    pdf_obj *arr;
1855
1856
    /* Find the enclosing subform */
1857
0
    do {
1858
0
      node = fz_xml_up(node);
1859
0
    } while (node && strcmp(fz_xml_tag(node), "subform"));
1860
1861
    /* Look for a variables within that. */
1862
0
    variables = fz_xml_find_down(node, "variables");
1863
0
    if (variables == NULL)
1864
0
      continue;
1865
1866
0
    manifest = fz_xml_find_down_match(variables, "manifest", "id", use);
1867
0
    if (manifest == NULL)
1868
0
      continue;
1869
1870
0
    arr = pdf_new_array(ctx, doc, 16);
1871
0
    fz_try(ctx)
1872
0
    {
1873
0
      ref = fz_xml_find_down(manifest, "ref");
1874
0
      while (ref)
1875
0
      {
1876
0
        const char *s = fz_xml_text(fz_xml_down(ref));
1877
0
        pdf_array_push(ctx, arr, annot_from_name(ctx, doc, s));
1878
0
        ref = fz_xml_find_next(ref, "ref");
1879
0
      }
1880
0
    }
1881
0
    fz_catch(ctx)
1882
0
    {
1883
0
      pdf_drop_obj(ctx, arr);
1884
0
      fz_rethrow(ctx);
1885
0
    }
1886
0
    return arr;
1887
0
  }
1888
1889
0
  return NULL;
1890
0
}
1891
1892
static void
1893
lock_field(fz_context *ctx, pdf_obj *f)
1894
0
{
1895
0
  int ff = pdf_dict_get_inheritable_int(ctx, f, PDF_NAME(Ff));
1896
1897
0
  if ((ff & PDF_FIELD_IS_READ_ONLY) ||
1898
0
    !pdf_name_eq(ctx, pdf_dict_get(ctx, f, PDF_NAME(Type)), PDF_NAME(Annot)) ||
1899
0
    !pdf_name_eq(ctx, pdf_dict_get(ctx, f, PDF_NAME(Subtype)), PDF_NAME(Widget)))
1900
0
    return;
1901
1902
0
  pdf_dict_put_int(ctx, f, PDF_NAME(Ff), ff | PDF_FIELD_IS_READ_ONLY);
1903
0
}
1904
1905
static void
1906
lock_xfa_locked_fields(fz_context *ctx, pdf_obj *a)
1907
0
{
1908
0
  int i;
1909
0
  int len = pdf_array_len(ctx, a);
1910
1911
0
  for (i = 0; i < len; i++)
1912
0
  {
1913
0
    lock_field(ctx, pdf_array_get(ctx, a, i));
1914
0
  }
1915
0
}
1916
1917
1918
void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_pkcs7_signer *signer, int64_t stime)
1919
0
{
1920
0
  pdf_obj *v = NULL;
1921
0
  pdf_obj *o = NULL;
1922
0
  pdf_obj *r = NULL;
1923
0
  pdf_obj *t = NULL;
1924
0
  pdf_obj *a = NULL;
1925
0
  pdf_obj *b = NULL;
1926
0
  pdf_obj *l = NULL;
1927
0
  pdf_obj *indv;
1928
0
  int vnum;
1929
0
  size_t max_digest_size;
1930
0
  char *buf = NULL;
1931
1932
0
  vnum = pdf_create_object(ctx, doc);
1933
0
  indv = pdf_new_indirect(ctx, doc, vnum, 0);
1934
0
  pdf_dict_put_drop(ctx, field, PDF_NAME(V), indv);
1935
1936
0
  max_digest_size = signer->max_digest_size(ctx, signer);
1937
1938
0
  fz_var(v);
1939
0
  fz_var(o);
1940
0
  fz_var(r);
1941
0
  fz_var(t);
1942
0
  fz_var(a);
1943
0
  fz_var(b);
1944
0
  fz_var(l);
1945
0
  fz_var(buf);
1946
0
  fz_try(ctx)
1947
0
  {
1948
0
    v = pdf_new_dict(ctx, doc, 4);
1949
0
    pdf_update_object(ctx, doc, vnum, v);
1950
1951
0
    buf = fz_calloc(ctx, max_digest_size, 1);
1952
1953
    /* Ensure that the /Filter entry is the first entry in the
1954
       dictionary after the digest contents since we look for
1955
       this tag when completing signatures in pdf-write.c in order
1956
       to generate the correct byte range. */
1957
0
    pdf_dict_put_array(ctx, v, PDF_NAME(ByteRange), 4);
1958
0
    pdf_dict_put_string(ctx, v, PDF_NAME(Contents), buf, max_digest_size);
1959
0
    pdf_dict_put(ctx, v, PDF_NAME(Filter), PDF_NAME(Adobe_PPKLite));
1960
0
    pdf_dict_put(ctx, v, PDF_NAME(SubFilter), PDF_NAME(adbe_pkcs7_detached));
1961
0
    pdf_dict_put(ctx, v, PDF_NAME(Type), PDF_NAME(Sig));
1962
0
    pdf_dict_put_date(ctx, v, PDF_NAME(M), stime);
1963
1964
0
    o = pdf_dict_put_array(ctx, v, PDF_NAME(Reference), 1);
1965
0
    r = pdf_array_put_dict(ctx, o, 0, 4);
1966
0
    pdf_dict_put(ctx, r, PDF_NAME(Data), pdf_dict_get(ctx, pdf_trailer(ctx, doc), PDF_NAME(Root)));
1967
0
    pdf_dict_put(ctx, r, PDF_NAME(TransformMethod), PDF_NAME(FieldMDP));
1968
0
    pdf_dict_put(ctx, r, PDF_NAME(Type), PDF_NAME(SigRef));
1969
0
    t = pdf_dict_put_dict(ctx, r, PDF_NAME(TransformParams), 5);
1970
1971
0
    l = pdf_dict_getp(ctx, field, "Lock/Action");
1972
0
    if (l)
1973
0
    {
1974
0
      a = pdf_dict_getp(ctx, field, "Lock/Fields");
1975
0
    }
1976
0
    else
1977
0
    {
1978
      /* Lock action wasn't specified so we need to encode an Include.
1979
       * Before we just use an empty array, check in the XFA for locking
1980
       * details. */
1981
0
      a = get_locked_fields_from_xfa(ctx, doc, field);
1982
0
      if (a)
1983
0
        lock_xfa_locked_fields(ctx, a);
1984
1985
      /* If we don't get a result from the XFA, just encode an empty array
1986
       * (leave a == NULL), even if Lock/Fields exists because we don't really
1987
       * know what to do with the information if the action isn't defined. */
1988
0
      l = PDF_NAME(Include);
1989
0
    }
1990
1991
0
    pdf_dict_put(ctx, t, PDF_NAME(Action), l);
1992
1993
0
    if (pdf_name_eq(ctx, l, PDF_NAME(Include)) || pdf_name_eq(ctx, l, PDF_NAME(Exclude)))
1994
0
    {
1995
      /* For action Include and Exclude, we need to encode a Fields array */
1996
0
      if (!a)
1997
0
      {
1998
        /* If one wasn't defined or we chose to ignore it because no action
1999
         * was defined then use an empty one. */
2000
0
        b = pdf_new_array(ctx, doc, 0);
2001
0
        a = b;
2002
0
      }
2003
2004
0
      pdf_dict_put_drop(ctx, t, PDF_NAME(Fields), pdf_copy_array(ctx, a));
2005
0
    }
2006
2007
0
    pdf_dict_put(ctx, t, PDF_NAME(Type), PDF_NAME(TransformParams));
2008
0
    pdf_dict_put(ctx, t, PDF_NAME(V), PDF_NAME(1_2));
2009
2010
    /* Record details within the document structure so that contents
2011
    * and byte_range can be updated with their correct values at
2012
    * saving time */
2013
0
    pdf_xref_store_unsaved_signature(ctx, doc, field, signer);
2014
0
  }
2015
0
  fz_always(ctx)
2016
0
  {
2017
0
    pdf_drop_obj(ctx, v);
2018
0
    pdf_drop_obj(ctx, b);
2019
0
    fz_free(ctx, buf);
2020
0
  }
2021
0
  fz_catch(ctx)
2022
0
  {
2023
0
    fz_rethrow(ctx);
2024
0
  }
2025
0
}
2026
2027
void pdf_set_widget_editing_state(fz_context *ctx, pdf_annot *widget, int editing)
2028
0
{
2029
0
  widget->ignore_trigger_events = editing;
2030
0
}
2031
2032
int pdf_get_widget_editing_state(fz_context *ctx, pdf_annot *widget)
2033
0
{
2034
0
  return widget->ignore_trigger_events;
2035
0
}
2036
2037
static void pdf_execute_js_action(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *js)
2038
0
{
2039
0
  if (js)
2040
0
  {
2041
0
    char *code = pdf_load_stream_or_string_as_utf8(ctx, js);
2042
0
    int in_op = 0;
2043
2044
0
    fz_var(in_op);
2045
0
    fz_try(ctx)
2046
0
    {
2047
0
      char buf[100];
2048
0
      fz_snprintf(buf, sizeof buf, "%d/%s", pdf_to_num(ctx, target), path);
2049
0
      pdf_begin_operation(ctx, doc, "Javascript Event");
2050
0
      in_op = 1;
2051
0
      pdf_js_execute(doc->js, buf, code, NULL);
2052
0
      pdf_end_operation(ctx, doc);
2053
0
    }
2054
0
    fz_always(ctx)
2055
0
    {
2056
0
      fz_free(ctx, code);
2057
0
    }
2058
0
    fz_catch(ctx)
2059
0
    {
2060
0
      if (in_op)
2061
0
        pdf_abandon_operation(ctx, doc);
2062
0
      fz_rethrow(ctx);
2063
0
    }
2064
0
  }
2065
0
}
2066
2067
static void pdf_execute_action_imp(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *action)
2068
0
{
2069
0
  pdf_obj *S = pdf_dict_get(ctx, action, PDF_NAME(S));
2070
0
  if (pdf_name_eq(ctx, S, PDF_NAME(JavaScript)))
2071
0
  {
2072
0
    if (doc->js)
2073
0
      pdf_execute_js_action(ctx, doc, target, path, pdf_dict_get(ctx, action, PDF_NAME(JS)));
2074
0
  }
2075
0
  if (pdf_name_eq(ctx, S, PDF_NAME(ResetForm)))
2076
0
  {
2077
0
    pdf_obj *fields = pdf_dict_get(ctx, action, PDF_NAME(Fields));
2078
0
    int flags = pdf_dict_get_int(ctx, action, PDF_NAME(Flags));
2079
0
    pdf_reset_form(ctx, doc, fields, flags & 1);
2080
0
  }
2081
0
}
2082
2083
static void pdf_execute_action_chain(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path, pdf_obj *action, pdf_cycle_list *cycle_up)
2084
0
{
2085
0
  pdf_cycle_list cycle;
2086
0
  pdf_obj *next;
2087
2088
0
  if (pdf_cycle(ctx, &cycle, cycle_up, action))
2089
0
    fz_throw(ctx, FZ_ERROR_FORMAT, "cycle in action chain");
2090
2091
0
  if (pdf_is_array(ctx, action))
2092
0
  {
2093
0
    int i, n = pdf_array_len(ctx, action);
2094
0
    for (i = 0; i < n; ++i)
2095
0
      pdf_execute_action_chain(ctx, doc, target, path, pdf_array_get(ctx, action, i), &cycle);
2096
0
  }
2097
0
  else
2098
0
  {
2099
0
    pdf_execute_action_imp(ctx, doc, target, path, action);
2100
0
    next = pdf_dict_get(ctx, action, PDF_NAME(Next));
2101
0
    if (next)
2102
0
      pdf_execute_action_chain(ctx, doc, target, path, next, &cycle);
2103
0
  }
2104
0
}
2105
2106
static void pdf_execute_action(fz_context *ctx, pdf_document *doc, pdf_obj *target, const char *path)
2107
0
{
2108
0
  pdf_obj *action = pdf_dict_getp_inheritable(ctx, target, path);
2109
0
  if (action)
2110
0
    pdf_execute_action_chain(ctx, doc, target, path, action, NULL);
2111
0
}
2112
2113
void pdf_document_event_will_close(fz_context *ctx, pdf_document *doc)
2114
0
{
2115
0
  pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WC");
2116
0
}
2117
2118
void pdf_document_event_will_save(fz_context *ctx, pdf_document *doc)
2119
0
{
2120
0
  pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WS");
2121
0
}
2122
2123
void pdf_document_event_did_save(fz_context *ctx, pdf_document *doc)
2124
0
{
2125
0
  pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/DS");
2126
0
}
2127
2128
void pdf_document_event_will_print(fz_context *ctx, pdf_document *doc)
2129
0
{
2130
0
  pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/WP");
2131
0
}
2132
2133
void pdf_document_event_did_print(fz_context *ctx, pdf_document *doc)
2134
0
{
2135
0
  pdf_execute_action(ctx, doc, pdf_trailer(ctx, doc), "Root/AA/DP");
2136
0
}
2137
2138
void pdf_page_event_open(fz_context *ctx, pdf_page *page)
2139
0
{
2140
0
  pdf_execute_action(ctx, page->doc, page->obj, "AA/O");
2141
0
}
2142
2143
void pdf_page_event_close(fz_context *ctx, pdf_page *page)
2144
0
{
2145
0
  pdf_execute_action(ctx, page->doc, page->obj, "AA/C");
2146
0
}
2147
2148
static void
2149
annot_execute_action(fz_context *ctx, pdf_annot *annot, const char *act)
2150
0
{
2151
0
  begin_annot_op(ctx, annot, "JavaScript action");
2152
2153
0
  fz_try(ctx)
2154
0
  {
2155
0
    pdf_execute_action(ctx, annot->page->doc, annot->obj, act);
2156
0
    end_annot_op(ctx, annot);
2157
0
  }
2158
0
  fz_catch(ctx)
2159
0
  {
2160
0
    abandon_annot_op(ctx, annot);
2161
0
    fz_rethrow(ctx);
2162
0
  }
2163
0
}
2164
2165
void pdf_annot_event_enter(fz_context *ctx, pdf_annot *annot)
2166
0
{
2167
0
  annot_execute_action(ctx, annot, "AA/E");
2168
0
}
2169
2170
void pdf_annot_event_exit(fz_context *ctx, pdf_annot *annot)
2171
0
{
2172
0
  annot_execute_action(ctx, annot, "AA/X");
2173
0
}
2174
2175
void pdf_annot_event_down(fz_context *ctx, pdf_annot *annot)
2176
0
{
2177
0
  annot_execute_action(ctx, annot, "AA/D");
2178
0
}
2179
2180
void pdf_annot_event_up(fz_context *ctx, pdf_annot *annot)
2181
0
{
2182
0
  pdf_obj *action;
2183
2184
0
  begin_annot_op(ctx, annot, "JavaScript action");
2185
2186
0
  fz_try(ctx)
2187
0
  {
2188
0
    action = pdf_dict_get(ctx, annot->obj, PDF_NAME(A));
2189
0
    if (action)
2190
0
      pdf_execute_action_chain(ctx, annot->page->doc, annot->obj, "A", action, NULL);
2191
0
    else
2192
0
      pdf_execute_action(ctx, annot->page->doc, annot->obj, "AA/U");
2193
0
    end_annot_op(ctx, annot);
2194
0
  }
2195
0
  fz_catch(ctx)
2196
0
  {
2197
0
    abandon_annot_op(ctx, annot);
2198
0
    fz_rethrow(ctx);
2199
0
  }
2200
0
}
2201
2202
void pdf_annot_event_focus(fz_context *ctx, pdf_annot *annot)
2203
0
{
2204
0
  annot_execute_action(ctx, annot, "AA/Fo");
2205
0
}
2206
2207
void pdf_annot_event_blur(fz_context *ctx, pdf_annot *annot)
2208
0
{
2209
0
  annot_execute_action(ctx, annot, "AA/Bl");
2210
0
}
2211
2212
void pdf_annot_event_page_open(fz_context *ctx, pdf_annot *annot)
2213
0
{
2214
0
  annot_execute_action(ctx, annot, "AA/PO");
2215
0
}
2216
2217
void pdf_annot_event_page_close(fz_context *ctx, pdf_annot *annot)
2218
0
{
2219
0
  annot_execute_action(ctx, annot, "AA/PC");
2220
0
}
2221
2222
void pdf_annot_event_page_visible(fz_context *ctx, pdf_annot *annot)
2223
0
{
2224
0
  annot_execute_action(ctx, annot, "AA/PV");
2225
0
}
2226
2227
void pdf_annot_event_page_invisible(fz_context *ctx, pdf_annot *annot)
2228
0
{
2229
0
  annot_execute_action(ctx, annot, "AA/PI");
2230
0
}
2231
2232
int pdf_field_event_keystroke(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_keystroke_event *evt)
2233
0
{
2234
0
  pdf_js *js = doc->js;
2235
0
  if (js)
2236
0
  {
2237
0
    pdf_obj *action = pdf_dict_getp_inheritable(ctx, field, "AA/K/JS");
2238
0
    if (action)
2239
0
    {
2240
0
      pdf_js_event_init_keystroke(js, field, evt);
2241
0
      pdf_execute_js_action(ctx, doc, field, "AA/K/JS", action);
2242
0
      return pdf_js_event_result_keystroke(js, evt);
2243
0
    }
2244
0
  }
2245
0
  evt->newChange = fz_strdup(ctx, evt->change);
2246
0
  evt->newValue = fz_strdup(ctx, evt->value);
2247
0
  return 1;
2248
0
}
2249
2250
int pdf_annot_field_event_keystroke(fz_context *ctx, pdf_document *doc, pdf_annot *annot, pdf_keystroke_event *evt)
2251
0
{
2252
0
  int ret;
2253
2254
0
  pdf_annot_push_local_xref(ctx, annot);
2255
2256
0
  fz_try(ctx)
2257
0
    ret = pdf_field_event_keystroke(ctx, doc, annot->obj, evt);
2258
0
  fz_always(ctx)
2259
0
    pdf_annot_pop_local_xref(ctx, annot);
2260
0
  fz_catch(ctx)
2261
0
    fz_rethrow(ctx);
2262
2263
0
  return ret;
2264
0
}
2265
2266
char *pdf_field_event_format(fz_context *ctx, pdf_document *doc, pdf_obj *field)
2267
152
{
2268
152
  pdf_js *js = doc->js;
2269
152
  if (js)
2270
0
  {
2271
0
    pdf_obj *action = pdf_dict_getp_inheritable(ctx, field, "AA/F/JS");
2272
0
    if (action)
2273
0
    {
2274
0
      const char *value = pdf_field_value(ctx, field);
2275
0
      pdf_js_event_init(js, field, value, 1);
2276
0
      pdf_execute_js_action(ctx, doc, field, "AA/F/JS", action);
2277
0
      return pdf_js_event_value(js);
2278
0
    }
2279
0
  }
2280
152
  return NULL;
2281
152
}
2282
2283
int pdf_field_event_validate(fz_context *ctx, pdf_document *doc, pdf_obj *field, const char *value, char **newvalue)
2284
0
{
2285
0
  pdf_js *js = doc->js;
2286
2287
0
  *newvalue = NULL;
2288
0
  if (js)
2289
0
  {
2290
0
    pdf_obj *action = pdf_dict_getp_inheritable(ctx, field, "AA/V/JS");
2291
0
    if (action)
2292
0
    {
2293
0
      pdf_js_event_init(js, field, value, 1);
2294
0
      pdf_execute_js_action(ctx, doc, field, "AA/V/JS", action);
2295
0
      return pdf_js_event_result_validate(js, newvalue);
2296
0
    }
2297
0
  }
2298
0
  return 1;
2299
0
}
2300
2301
void pdf_field_event_calculate(fz_context *ctx, pdf_document *doc, pdf_obj *field)
2302
0
{
2303
0
  pdf_js *js = doc->js;
2304
0
  if (js)
2305
0
  {
2306
0
    pdf_obj *action = pdf_dict_getp_inheritable(ctx, field, "AA/C/JS");
2307
0
    if (action)
2308
0
    {
2309
0
      char *old_value = fz_strdup(ctx, pdf_field_value(ctx, field));
2310
0
      char *new_value = NULL;
2311
0
      fz_var(new_value);
2312
0
      fz_try(ctx)
2313
0
      {
2314
0
        pdf_js_event_init(js, field, old_value, 1);
2315
0
        pdf_execute_js_action(ctx, doc, field, "AA/C/JS", action);
2316
0
        if (pdf_js_event_result(js))
2317
0
        {
2318
0
          new_value = pdf_js_event_value(js);
2319
0
          if (strcmp(old_value, new_value))
2320
0
            pdf_set_field_value(ctx, doc, field, new_value, 0);
2321
0
        }
2322
0
      }
2323
0
      fz_always(ctx)
2324
0
      {
2325
0
        fz_free(ctx, old_value);
2326
0
        fz_free(ctx, new_value);
2327
0
      }
2328
0
      fz_catch(ctx)
2329
0
        fz_rethrow(ctx);
2330
0
    }
2331
0
  }
2332
0
}
2333
2334
static void
2335
count_sigs(fz_context *ctx, pdf_obj *field, void *arg, pdf_obj **ft)
2336
0
{
2337
0
  int *n = (int *)arg;
2338
2339
0
  if (!pdf_name_eq(ctx, pdf_dict_get(ctx, field, PDF_NAME(Type)), PDF_NAME(Annot)) ||
2340
0
    !pdf_name_eq(ctx, pdf_dict_get(ctx, field, PDF_NAME(Subtype)), PDF_NAME(Widget)) ||
2341
0
    !pdf_name_eq(ctx, *ft, PDF_NAME(Sig)))
2342
0
    return;
2343
2344
0
  (*n)++;
2345
0
}
2346
2347
static pdf_obj *ft_name[2] = { PDF_NAME(FT), NULL };
2348
2349
int pdf_count_signatures(fz_context *ctx, pdf_document *doc)
2350
0
{
2351
0
  int n = 0;
2352
0
  pdf_obj *ft = NULL;
2353
0
  pdf_obj *form_fields = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), "Root/AcroForm/Fields");
2354
0
  pdf_walk_tree(ctx, form_fields, PDF_NAME(Kids), count_sigs, NULL, &n, ft_name, &ft);
2355
0
  return n;
2356
0
}
2357
2358
/*
2359
 * Bake interactive form fields into static content.
2360
 */
2361
2362
static pdf_obj *get_annot_ap(fz_context *ctx, pdf_obj *annot)
2363
0
{
2364
0
  pdf_obj *ap = pdf_dict_get(ctx, annot, PDF_NAME(AP));
2365
0
  pdf_obj *as = pdf_dict_get(ctx, annot, PDF_NAME(AS));
2366
0
  if (ap)
2367
0
  {
2368
0
    as = pdf_resolve_indirect_chain(ctx, as);
2369
0
    ap = pdf_dict_get(ctx, ap, PDF_NAME(N));
2370
0
    if (pdf_is_stream(ctx, ap))
2371
0
      return ap;
2372
0
    ap = pdf_dict_get(ctx, ap, as);
2373
0
    if (pdf_is_stream(ctx, ap))
2374
0
      return ap;
2375
0
  }
2376
0
  return NULL;
2377
0
}
2378
2379
static fz_matrix get_annot_transform(fz_context *ctx, pdf_obj *annot, pdf_obj *ap)
2380
0
{
2381
0
  float w, h, x, y;
2382
0
  fz_matrix transform;
2383
0
  fz_rect bbox;
2384
0
  fz_rect rect;
2385
2386
0
  rect = pdf_dict_get_rect(ctx, annot, PDF_NAME(Rect));
2387
0
  bbox = pdf_dict_get_rect(ctx, ap, PDF_NAME(BBox));
2388
0
  transform = pdf_dict_get_matrix(ctx, ap, PDF_NAME(Matrix));
2389
2390
0
  bbox = fz_transform_rect(bbox, transform);
2391
0
  w = (rect.x1 - rect.x0) / (bbox.x1 - bbox.x0);
2392
0
  h = (rect.y1 - rect.y0) / (bbox.y1 - bbox.y0);
2393
0
  x = rect.x0 - bbox.x0 * w;
2394
0
  y = rect.y0 - bbox.y0 * h;
2395
2396
0
  return fz_make_matrix(w, 0, 0, h, x, y);
2397
0
}
2398
2399
static void pdf_bake_annot(fz_context *ctx, fz_buffer *buf, pdf_document *doc, pdf_obj *page, pdf_obj *res_xobj, pdf_obj *annot)
2400
0
{
2401
0
  fz_matrix m;
2402
0
  pdf_obj *ap;
2403
0
  char name[20];
2404
2405
0
  int flags = pdf_dict_get_int(ctx, annot, PDF_NAME(F));
2406
0
  if (flags & (PDF_ANNOT_IS_INVISIBLE | PDF_ANNOT_IS_HIDDEN))
2407
0
    return;
2408
2409
0
  ap = get_annot_ap(ctx, annot);
2410
0
  if (ap)
2411
0
  {
2412
0
    fz_snprintf(name, sizeof name, "Annot%d", pdf_to_num(ctx, annot));
2413
0
    pdf_dict_puts(ctx, res_xobj, name, ap);
2414
0
    pdf_dict_put(ctx, ap, PDF_NAME(Type), PDF_NAME(XObject));
2415
0
    pdf_dict_put(ctx, ap, PDF_NAME(Subtype), PDF_NAME(Form));
2416
0
    m = get_annot_transform(ctx, annot, ap);
2417
0
    fz_append_printf(ctx, buf,
2418
0
      "q\n%g %g %g %g %g %g cm\n/%s Do\nQ\n",
2419
0
      m.a, m.b, m.c, m.d, m.e, m.f,
2420
0
      name
2421
0
    );
2422
0
  }
2423
0
}
2424
2425
static void pdf_bake_page(fz_context *ctx, pdf_document *doc, pdf_obj *page, int bake_annots, int bake_widgets)
2426
0
{
2427
0
  pdf_obj *res;
2428
0
  pdf_obj *res_xobj;
2429
0
  pdf_obj *contents;
2430
0
  pdf_obj *new_contents = NULL;
2431
0
  pdf_obj *annots;
2432
0
  pdf_obj *annot;
2433
0
  pdf_obj *subtype;
2434
0
  pdf_obj *prologue = NULL;
2435
0
  fz_buffer *buf = NULL;
2436
0
  int prepend, append;
2437
0
  int i;
2438
2439
0
  fz_var(buf);
2440
0
  fz_var(prologue);
2441
0
  fz_var(new_contents);
2442
2443
0
  annots = pdf_dict_get(ctx, page, PDF_NAME(Annots));
2444
0
  if (pdf_array_len(ctx, annots) == 0)
2445
0
    return;
2446
2447
0
  res = pdf_dict_get(ctx, page, PDF_NAME(Resources));
2448
0
  if (!res)
2449
0
  {
2450
0
    res = pdf_dict_get_inheritable(ctx, page, PDF_NAME(Resources));
2451
0
    if (res)
2452
0
      pdf_dict_put(ctx, page, PDF_NAME(Resources), res);
2453
0
    else
2454
0
      res = pdf_dict_put_dict(ctx, page, PDF_NAME(Resources), 4);
2455
0
  }
2456
2457
0
  res_xobj = pdf_dict_get(ctx, res, PDF_NAME(XObject));
2458
0
  if (!res_xobj)
2459
0
    res_xobj = pdf_dict_put_dict(ctx, res, PDF_NAME(XObject), 8);
2460
2461
0
  fz_try(ctx)
2462
0
  {
2463
    // Ensure that the graphics state is balanced.
2464
0
    contents = pdf_dict_get(ctx, page, PDF_NAME(Contents));
2465
0
    pdf_count_q_balance(ctx, doc, res, contents, &prepend, &append);
2466
2467
0
    if (prepend)
2468
0
    {
2469
      // Prepend enough 'q' to ensure we can get back to initial state.
2470
0
      buf = fz_new_buffer(ctx, 1024);
2471
0
      while (prepend-- > 0)
2472
0
        fz_append_string(ctx, buf, "q\n");
2473
2474
0
      prologue = pdf_add_stream(ctx, doc, buf, NULL, 0);
2475
0
      fz_drop_buffer(ctx, buf);
2476
0
      buf = NULL;
2477
0
    }
2478
2479
    // Append enough 'Q' to get back to initial state.
2480
0
    buf = fz_new_buffer(ctx, 1024);
2481
0
    while (append-- > 0)
2482
0
      fz_append_string(ctx, buf, "Q\n");
2483
2484
0
    for (i = 0; i < pdf_array_len(ctx, annots); )
2485
0
    {
2486
0
      annot = pdf_array_get(ctx, annots, i);
2487
0
      subtype = pdf_dict_get(ctx, annot, PDF_NAME(Subtype));
2488
0
      if (subtype == PDF_NAME(Link))
2489
0
      {
2490
0
        ++i;
2491
0
      }
2492
0
      else if (subtype == PDF_NAME(Widget))
2493
0
      {
2494
0
        if (bake_widgets)
2495
0
        {
2496
0
          pdf_bake_annot(ctx, buf, doc, page, res_xobj, annot);
2497
0
          pdf_array_delete(ctx, annots, i);
2498
0
        }
2499
0
        else
2500
0
        {
2501
0
          ++i;
2502
0
        }
2503
0
      }
2504
0
      else
2505
0
      {
2506
0
        if (bake_annots)
2507
0
        {
2508
0
          pdf_bake_annot(ctx, buf, doc, page, res_xobj, annot);
2509
0
          pdf_array_delete(ctx, annots, i);
2510
0
        }
2511
0
        else
2512
0
        {
2513
0
          ++i;
2514
0
        }
2515
0
      }
2516
0
    }
2517
2518
0
    if (!pdf_is_array(ctx, contents))
2519
0
    {
2520
0
      new_contents = pdf_new_array(ctx, doc, 10);
2521
0
      if (prologue)
2522
0
        pdf_array_push(ctx, new_contents, prologue);
2523
0
      if (contents)
2524
0
        pdf_array_push(ctx, new_contents, contents);
2525
0
      pdf_dict_put(ctx, page, PDF_NAME(Contents), new_contents);
2526
0
      pdf_drop_obj(ctx, new_contents);
2527
0
      contents = new_contents;
2528
0
      new_contents = NULL;
2529
0
    }
2530
0
    else if (prologue)
2531
0
    {
2532
0
      pdf_array_insert(ctx, contents, prologue, 0);
2533
0
    }
2534
2535
0
    pdf_array_push_drop(ctx, contents, pdf_add_stream(ctx, doc, buf, NULL, 0));
2536
0
  }
2537
0
  fz_always(ctx)
2538
0
  {
2539
0
    fz_drop_buffer(ctx, buf);
2540
0
    pdf_drop_obj(ctx, prologue);
2541
0
    pdf_drop_obj(ctx, new_contents);
2542
0
  }
2543
0
  fz_catch(ctx)
2544
0
  {
2545
0
    fz_rethrow(ctx);
2546
0
  }
2547
0
}
2548
2549
void pdf_bake_document(fz_context *ctx, pdf_document *doc, int bake_annots, int bake_widgets)
2550
0
{
2551
0
  pdf_page *page = NULL;
2552
0
  pdf_annot *annot;
2553
0
  int i, n;
2554
2555
0
  fz_var(page);
2556
2557
0
  pdf_begin_operation(ctx, doc, "Bake interactive content");
2558
0
  fz_try(ctx)
2559
0
  {
2560
0
    n = pdf_count_pages(ctx, doc);
2561
0
    for (i = 0; i < n; ++i)
2562
0
    {
2563
0
      page = pdf_load_page(ctx, doc, i);
2564
2565
0
      if (bake_annots)
2566
0
        for (annot = pdf_first_annot(ctx, page); annot; annot = pdf_next_annot(ctx, annot))
2567
0
          pdf_annot_request_synthesis(ctx, annot);
2568
0
      if (bake_widgets)
2569
0
        for (annot = pdf_first_widget(ctx, page); annot; annot = pdf_next_widget(ctx, annot))
2570
0
          pdf_annot_request_synthesis(ctx, annot);
2571
0
      pdf_update_page(ctx, page);
2572
2573
0
      pdf_bake_page(ctx, doc, page->obj, bake_annots, bake_widgets);
2574
2575
0
      fz_drop_page(ctx, (fz_page*)page);
2576
0
      page = NULL;
2577
0
    }
2578
2579
0
    if (bake_widgets)
2580
0
    {
2581
0
      pdf_obj *trailer = pdf_trailer(ctx, doc);
2582
0
      pdf_obj *root = pdf_dict_get(ctx, trailer, PDF_NAME(Root));
2583
0
      pdf_dict_del(ctx, root, PDF_NAME(AcroForm));
2584
0
    }
2585
0
    pdf_end_operation(ctx, doc);
2586
0
  }
2587
0
  fz_always(ctx)
2588
0
  {
2589
0
    fz_drop_page(ctx, (fz_page*)page);
2590
0
  }
2591
0
  fz_catch(ctx)
2592
0
  {
2593
0
    pdf_abandon_operation(ctx, doc);
2594
0
  }
2595
0
}