summaryrefslogtreecommitdiff
path: root/source/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paul.gardiner@artifex.com>2015-08-27 16:55:45 +0100
committerPaul Gardiner <paul.gardiner@artifex.com>2015-08-27 16:55:45 +0100
commit0d74c055c16c391a76c79cec4eb7636e72a407f9 (patch)
tree2529bcb973074e9d49fa32f712564c5fb802b86c /source/pdf
parent71459622bc78f03c379c59f1e60a9008147b32fc (diff)
downloadmupdf-0d74c055c16c391a76c79cec4eb7636e72a407f9.tar.xz
Support several levels of incremental xref
This fixes bug #696123 by allowing multiple signatures each to be written to the document in a separate incemental update. Add count num_incremental_sections to keep track of the number of incremental sections. Add xref_base, which can be set between 0 and num_incremental_sections inclusive to access different versions of the document. Add disallow_new_increments flag that stops new incremental sections being provoked by the creation of an xref stream. Move the unsaved_sigs list from the document structure to the xref structure. With this commit in place, the lists will never grow beyond length one, but we've maintained the list structure in case other cases need supporting in the future. Add an end offset field to the xref structure, so that during completion of signatures the document length of the various incremental versions of the document are available. Factor out functions for storing unsaved signatures and for checking if an object is an unsaved signature. Do deep copy of objects that require the holding of several versions.
Diffstat (limited to 'source/pdf')
-rw-r--r--source/pdf/pdf-form.c11
-rw-r--r--source/pdf/pdf-pkcs7.c14
-rw-r--r--source/pdf/pdf-write.c274
-rw-r--r--source/pdf/pdf-xref.c109
4 files changed, 249 insertions, 159 deletions
diff --git a/source/pdf/pdf-form.c b/source/pdf/pdf-form.c
index 5a23786f..dcb08bc7 100644
--- a/source/pdf/pdf-form.c
+++ b/source/pdf/pdf-form.c
@@ -1439,7 +1439,6 @@ void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field,
pdf_obj *byte_range;
pdf_obj *contents;
char buf[2048];
- pdf_unsaved_sig *unsaved_sig;
memset(buf, 0, sizeof(buf));
@@ -1474,13 +1473,5 @@ void pdf_signature_set_value(fz_context *ctx, pdf_document *doc, pdf_obj *field,
/* Record details within the document structure so that contents
* and byte_range can be updated with their correct values at
* saving time */
- unsaved_sig = fz_malloc_struct(ctx, pdf_unsaved_sig);
- unsaved_sig->field = pdf_keep_obj(ctx, field);
- unsaved_sig->signer = pdf_keep_signer(ctx, signer);
- unsaved_sig->next = NULL;
- if (doc->unsaved_sigs_end == NULL)
- doc->unsaved_sigs_end = &doc->unsaved_sigs;
-
- *doc->unsaved_sigs_end = unsaved_sig;
- doc->unsaved_sigs_end = &unsaved_sig->next;
+ pdf_xref_store_unsaved_signature(ctx, doc, field, signer);
}
diff --git a/source/pdf/pdf-pkcs7.c b/source/pdf/pdf-pkcs7.c
index 15609153..6303a3c9 100644
--- a/source/pdf/pdf-pkcs7.c
+++ b/source/pdf/pdf-pkcs7.c
@@ -670,17 +670,13 @@ int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_widget *widget,
char *contents = NULL;
int contents_len;
int res = 0;
- pdf_unsaved_sig *usig;
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ if (pdf_xref_obj_is_unsaved_signature(doc, ((pdf_annot *)widget)->obj))
{
- if (usig->field == ((pdf_annot *)widget)->obj)
- {
- fz_strlcpy(ebuf, "Signed but document yet to be saved", ebufsize);
- if (ebufsize > 0)
- ebuf[ebufsize-1] = 0;
- return 0;
- }
+ fz_strlcpy(ebuf, "Signed but document yet to be saved", ebufsize);
+ if (ebufsize > 0)
+ ebuf[ebufsize-1] = 0;
+ return 0;
}
fz_var(byte_range);
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index ea2c65a2..93560e81 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2474,29 +2474,36 @@ static void dump_object_details(fz_context *ctx, pdf_document *doc, pdf_write_op
static void presize_unsaved_signature_byteranges(fz_context *ctx, pdf_document *doc)
{
- if (doc->unsaved_sigs)
- {
- /* The ByteRange objects of signatures are initially written out with
- * dummy values, and then overwritten later. We need to make sure their
- * initial form at least takes enough sufficient file space */
- pdf_unsaved_sig *usig;
- int n = 0;
+ int s;
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
- n++;
+ for (s = 0; s < doc->num_incremental_sections; s++)
+ {
+ pdf_xref *xref = &doc->xref_sections[s];
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ if (xref->unsaved_sigs)
{
- /* There will be segments of bytes at the beginning, at
- * the end and between each consecutive pair of signatures,
- * hence n + 1 */
- int i;
- pdf_obj *byte_range = pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+ /* The ByteRange objects of signatures are initially written out with
+ * dummy values, and then overwritten later. We need to make sure their
+ * initial form at least takes enough sufficient file space */
+ pdf_unsaved_sig *usig;
+ int n = 0;
+
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ n++;
- for (i = 0; i < n+1; i++)
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
{
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, INT_MAX));
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, INT_MAX));
+ /* There will be segments of bytes at the beginning, at
+ * the end and between each consecutive pair of signatures,
+ * hence n + 1 */
+ int i;
+ pdf_obj *byte_range = pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+
+ for (i = 0; i < n+1; i++)
+ {
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, INT_MAX));
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, INT_MAX));
+ }
}
}
}
@@ -2507,86 +2514,88 @@ static void complete_signatures(fz_context *ctx, pdf_document *doc, pdf_write_op
pdf_unsaved_sig *usig;
FILE *f;
char buf[5120];
+ int s;
int i;
- int flen;
int last_end;
- if (doc->unsaved_sigs)
+ for (s = 0; s < doc->num_incremental_sections; s++)
{
- pdf_obj *byte_range;
-
- f = fz_fopen(filename, "rb+");
- if (!f)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to open %s to complete signatures", filename);
+ pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
- fz_fseek(f, 0, SEEK_END);
- flen = fz_ftell(f);
-
- /* Locate the byte ranges and contents in the saved file */
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ if (xref->unsaved_sigs)
{
- char *bstr, *cstr, *fstr;
- int pnum = pdf_obj_parent_num(ctx, pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL));
- fz_fseek(f, opts->ofs_list[pnum], SEEK_SET);
- (void)fread(buf, 1, sizeof(buf), f);
- buf[sizeof(buf)-1] = 0;
+ pdf_obj *byte_range;
- bstr = strstr(buf, "/ByteRange");
- cstr = strstr(buf, "/Contents");
- fstr = strstr(buf, "/Filter");
+ f = fz_fopen(filename, "rb+");
+ if (!f)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to open %s to complete signatures", filename);
- if (bstr && cstr && fstr && bstr < cstr && cstr < fstr)
+ /* Locate the byte ranges and contents in the saved file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
{
- usig->byte_range_start = bstr - buf + 10 + opts->ofs_list[pnum];
- usig->byte_range_end = cstr - buf + opts->ofs_list[pnum];
- usig->contents_start = cstr - buf + 9 + opts->ofs_list[pnum];
- usig->contents_end = fstr - buf + opts->ofs_list[pnum];
+ char *bstr, *cstr, *fstr;
+ int pnum = pdf_obj_parent_num(ctx, pdf_dict_getl(ctx, usig->field, PDF_NAME_V, PDF_NAME_ByteRange, NULL));
+ fz_fseek(f, opts->ofs_list[pnum], SEEK_SET);
+ (void)fread(buf, 1, sizeof(buf), f);
+ buf[sizeof(buf)-1] = 0;
+
+ bstr = strstr(buf, "/ByteRange");
+ cstr = strstr(buf, "/Contents");
+ fstr = strstr(buf, "/Filter");
+
+ if (bstr && cstr && fstr && bstr < cstr && cstr < fstr)
+ {
+ usig->byte_range_start = bstr - buf + 10 + opts->ofs_list[pnum];
+ usig->byte_range_end = cstr - buf + opts->ofs_list[pnum];
+ usig->contents_start = cstr - buf + 9 + opts->ofs_list[pnum];
+ usig->contents_end = fstr - buf + opts->ofs_list[pnum];
+ }
}
- }
- /* Recreate ByteRange with correct values. Initially store the
- * recreated object in the first of the unsaved signatures */
- byte_range = pdf_new_array(ctx, doc, 4);
- pdf_dict_putl_drop(ctx, doc->unsaved_sigs->field, byte_range, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+ /* Recreate ByteRange with correct values. Initially store the
+ * recreated object in the first of the unsaved signatures */
+ byte_range = pdf_new_array(ctx, doc, 4);
+ pdf_dict_putl_drop(ctx, xref->unsaved_sigs->field, byte_range, PDF_NAME_V, PDF_NAME_ByteRange, NULL);
- last_end = 0;
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
- {
+ last_end = 0;
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ {
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, usig->contents_start - last_end));
+ last_end = usig->contents_end;
+ }
pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, usig->contents_start - last_end));
- last_end = usig->contents_end;
- }
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, last_end));
- pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, flen - last_end));
+ pdf_array_push_drop(ctx, byte_range, pdf_new_int(ctx, doc, xref->end_ofs - last_end));
- /* Copy the new ByteRange to the other unsaved signatures */
- for (usig = doc->unsaved_sigs->next; usig; usig = usig->next)
- pdf_dict_putl_drop(ctx, usig->field, pdf_copy_array(ctx, byte_range), PDF_NAME_V, PDF_NAME_ByteRange, NULL);
+ /* Copy the new ByteRange to the other unsaved signatures */
+ for (usig = xref->unsaved_sigs->next; usig; usig = usig->next)
+ pdf_dict_putl_drop(ctx, usig->field, pdf_copy_array(ctx, byte_range), PDF_NAME_V, PDF_NAME_ByteRange, NULL);
- /* Write the byte range into buf, padding with spaces*/
- i = pdf_sprint_obj(ctx, buf, sizeof(buf), byte_range, 1);
- memset(buf+i, ' ', sizeof(buf)-i);
+ /* Write the byte range into buf, padding with spaces*/
+ i = pdf_sprint_obj(ctx, buf, sizeof(buf), byte_range, 1);
+ memset(buf+i, ' ', sizeof(buf)-i);
- /* Write the byte range to the file */
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
- {
- fz_fseek(f, usig->byte_range_start, SEEK_SET);
- fwrite(buf, 1, usig->byte_range_end - usig->byte_range_start, f);
- }
+ /* Write the byte range to the file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ {
+ fz_fseek(f, usig->byte_range_start, SEEK_SET);
+ fwrite(buf, 1, usig->byte_range_end - usig->byte_range_start, f);
+ }
- fclose(f);
+ fclose(f);
- /* Write the digests into the file */
- for (usig = doc->unsaved_sigs; usig; usig = usig->next)
- pdf_write_digest(ctx, doc, filename, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
+ /* Write the digests into the file */
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ pdf_write_digest(ctx, doc, filename, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
- /* delete the unsaved_sigs records */
- while ((usig = doc->unsaved_sigs) != NULL)
- {
- doc->unsaved_sigs = usig->next;
- pdf_drop_obj(ctx, usig->field);
- pdf_drop_signer(ctx, usig->signer);
- fz_free(ctx, usig);
+ /* delete the unsaved_sigs records */
+ while ((usig = xref->unsaved_sigs) != NULL)
+ {
+ xref->unsaved_sigs = usig->next;
+ pdf_drop_obj(ctx, usig->field);
+ pdf_drop_signer(ctx, usig->signer);
+ fz_free(ctx, usig);
+ }
}
}
}
@@ -2681,6 +2690,11 @@ void pdf_write_document(fz_context *ctx, pdf_document *doc, char *filename, fz_w
if (!fz_opts)
fz_opts = &opts_defaults;
+ if (fz_opts->do_incremental && fz_opts->do_garbage)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with garbage collection");
+ if (fz_opts->do_incremental && fz_opts->do_linear)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with linearisation");
+
doc->freeze_updates = 1;
/* Sanitize the operator streams */
@@ -2695,7 +2709,7 @@ void pdf_write_document(fz_context *ctx, pdf_document *doc, char *filename, fz_w
if (fz_opts->do_incremental)
{
/* If no changes, nothing to write */
- if (!doc->xref_altered)
+ if (doc->num_incremental_sections == 0)
return;
opts.out = fz_fopen(filename, "ab");
if (opts.out)
@@ -2716,11 +2730,6 @@ void pdf_write_document(fz_context *ctx, pdf_document *doc, char *filename, fz_w
{
initialise_write_options(ctx, doc, fz_opts, &opts);
- if (opts.do_incremental && opts.do_garbage)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with garbage collection");
- if (opts.do_incremental && opts.do_linear)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with linearisation");
-
/* Make sure any objects hidden in compressed streams have been loaded */
if (!opts.do_incremental)
{
@@ -2755,26 +2764,52 @@ void pdf_write_document(fz_context *ctx, pdf_document *doc, char *filename, fz_w
if (opts.do_linear)
linearize(ctx, doc, &opts);
- writeobjects(ctx, doc, &opts, 0);
+ if (opts.do_incremental)
+ {
+ int i;
+
+ doc->disallow_new_increments = 1;
+
+ for (i = 0; i < doc->num_incremental_sections; i++)
+ {
+ doc->xref_base = doc->num_incremental_sections - i - 1;
+
+ writeobjects(ctx, doc, &opts, 0);
#ifdef DEBUG_WRITING
- dump_object_details(ctx, doc, &opts);
+ dump_object_details(ctx, doc, &opts);
#endif
- if (opts.do_incremental)
- {
- for (num = 0; num < xref_len; num++)
- {
- if (!opts.use_list[num] && pdf_xref_is_incremental(ctx, doc, num))
+ for (num = 0; num < xref_len; num++)
{
- /* Make unreusable. FIXME: would be better to link to existing free list */
- opts.gen_list[num] = 65535;
- opts.ofs_list[num] = 0;
+ if (!opts.use_list[num] && pdf_xref_is_incremental(ctx, doc, num))
+ {
+ /* Make unreusable. FIXME: would be better to link to existing free list */
+ opts.gen_list[num] = 65535;
+ opts.ofs_list[num] = 0;
+ }
}
+
+ opts.first_xref_offset = fz_ftell(opts.out);
+ if (doc->has_xref_streams)
+ writexrefstream(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
+ else
+ writexref(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
+
+ doc->xref_sections[doc->xref_base].end_ofs = fz_ftell(opts.out);
}
+
+ doc->xref_base = 0;
+ doc->disallow_new_increments = 0;
}
else
{
+ writeobjects(ctx, doc, &opts, 0);
+
+#ifdef DEBUG_WRITING
+ dump_object_details(ctx, doc, &opts);
+#endif
+
/* Construct linked list of free object slots */
lastfree = 0;
for (num = 0; num < xref_len; num++)
@@ -2786,36 +2821,35 @@ void pdf_write_document(fz_context *ctx, pdf_document *doc, char *filename, fz_w
lastfree = num;
}
}
- }
- if (opts.do_linear)
- {
- opts.main_xref_offset = fz_ftell(opts.out);
- writexref(ctx, doc, &opts, 0, opts.start, 0, 0, opts.first_xref_offset);
- opts.file_len = fz_ftell(opts.out);
-
- make_hint_stream(ctx, doc, &opts);
- if (opts.do_ascii)
+ if (opts.do_linear)
{
- opts.hintstream_len *= 2;
- opts.hintstream_len += 1 + ((opts.hintstream_len+63)>>6);
+ opts.main_xref_offset = fz_ftell(opts.out);
+ writexref(ctx, doc, &opts, 0, opts.start, 0, 0, opts.first_xref_offset);
+ opts.file_len = fz_ftell(opts.out);
+
+ make_hint_stream(ctx, doc, &opts);
+ if (opts.do_ascii)
+ {
+ opts.hintstream_len *= 2;
+ opts.hintstream_len += 1 + ((opts.hintstream_len+63)>>6);
+ }
+ opts.file_len += opts.hintstream_len;
+ opts.main_xref_offset += opts.hintstream_len;
+ update_linearization_params(ctx, doc, &opts);
+ fz_fseek(opts.out, 0, 0);
+ writeobjects(ctx, doc, &opts, 1);
+
+ padto(opts.out, opts.main_xref_offset);
+ writexref(ctx, doc, &opts, 0, opts.start, 0, 0, opts.first_xref_offset);
}
- opts.file_len += opts.hintstream_len;
- opts.main_xref_offset += opts.hintstream_len;
- update_linearization_params(ctx, doc, &opts);
- fz_fseek(opts.out, 0, 0);
- writeobjects(ctx, doc, &opts, 1);
-
- padto(opts.out, opts.main_xref_offset);
- writexref(ctx, doc, &opts, 0, opts.start, 0, 0, opts.first_xref_offset);
- }
- else
- {
- opts.first_xref_offset = fz_ftell(opts.out);
- if (opts.do_incremental && doc->has_xref_streams)
- writexrefstream(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
else
+ {
+ opts.first_xref_offset = fz_ftell(opts.out);
writexref(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
+ }
+
+ doc->xref_sections[0].end_ofs = fz_ftell(opts.out);
}
fclose(opts.out);
diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c
index a5cc29ef..3a9f70df 100644
--- a/source/pdf/pdf-xref.c
+++ b/source/pdf/pdf-xref.c
@@ -22,6 +22,7 @@ static inline int iswhite(int ch)
static void pdf_drop_xref_sections(fz_context *ctx, pdf_document *doc)
{
+ pdf_unsaved_sig *usig;
int x, e;
for (x = 0; x < doc->num_xref_sections; x++)
@@ -49,11 +50,20 @@ static void pdf_drop_xref_sections(fz_context *ctx, pdf_document *doc)
pdf_drop_obj(ctx, xref->pre_repair_trailer);
pdf_drop_obj(ctx, xref->trailer);
+
+ while ((usig = xref->unsaved_sigs) != NULL)
+ {
+ xref->unsaved_sigs = usig->next;
+ pdf_drop_obj(ctx, usig->field);
+ pdf_drop_signer(ctx, usig->signer);
+ fz_free(ctx, usig);
+ }
}
fz_free(ctx, doc->xref_sections);
doc->xref_sections = NULL;
doc->num_xref_sections = 0;
+ doc->num_incremental_sections = 0;
}
static void
@@ -75,7 +85,7 @@ extend_xref_index(fz_context *ctx, pdf_document *doc, int newlen)
static void pdf_resize_xref(fz_context *ctx, pdf_document *doc, int newlen)
{
int i;
- pdf_xref *xref = &doc->xref_sections[0];
+ pdf_xref *xref = &doc->xref_sections[doc->xref_base];
pdf_xref_subsec *sub;
assert(xref != NULL);
@@ -110,6 +120,8 @@ static void pdf_populate_next_xref_level(fz_context *ctx, pdf_document *doc)
xref->num_objects = 0;
xref->trailer = NULL;
xref->pre_repair_trailer = NULL;
+ xref->unsaved_sigs = NULL;
+ xref->unsaved_sigs_end = NULL;
}
pdf_obj *pdf_trailer(fz_context *ctx, pdf_document *doc)
@@ -240,6 +252,11 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i)
else
j = 0;
+ /* We may be accessing an earlier version of the document using xref_base
+ * and j may be an index into a later xref section */
+ if (doc->xref_base > j)
+ j = doc->xref_base;
+
/* Find the first xref section where the entry is defined. */
for (; j < doc->num_xref_sections; j++)
{
@@ -257,7 +274,10 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i)
entry = &sub->table[i - sub->start];
if (entry->type)
{
- doc->xref_index[i] = j;
+ /* Don't update xref_index if xref_base may have
+ * influenced the value of j */
+ if (doc->xref_base == 0)
+ doc->xref_index[i] = j;
return entry;
}
}
@@ -269,7 +289,7 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i)
doc->xref_index[i] = 0;
if (xref == NULL || i < xref->num_objects)
{
- xref = &doc->xref_sections[0];
+ xref = &doc->xref_sections[doc->xref_base];
for (sub = xref->subsec; sub != NULL; sub = sub->next)
{
if (i >= sub->start && i < sub->start + sub->len)
@@ -294,8 +314,11 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i)
*/
static void ensure_incremental_xref(fz_context *ctx, pdf_document *doc)
{
-
- if (!doc->xref_altered)
+ /* If there are as yet no incremental sections, or if the most recent
+ * one has been used to sign a signature field, then we need a new one.
+ * After a signing, any further document changes require a new increment */
+ if ((doc->num_incremental_sections == 0 || doc->xref_sections[0].unsaved_sigs != NULL)
+ && !doc->disallow_new_increments)
{
pdf_xref *xref = &doc->xref_sections[0];
pdf_xref *pxref;
@@ -317,12 +340,14 @@ static void ensure_incremental_xref(fz_context *ctx, pdf_document *doc)
xref->subsec = sub;
xref->trailer = trailer;
xref->pre_repair_trailer = NULL;
+ xref->unsaved_sigs = NULL;
+ xref->unsaved_sigs_end = NULL;
sub->next = NULL;
sub->len = xref->num_objects;
sub->start = 0;
sub->table = new_table;
doc->num_xref_sections++;
- doc->xref_altered = 1;
+ doc->num_incremental_sections++;
}
fz_catch(ctx)
{
@@ -348,7 +373,7 @@ static pdf_xref_entry *pdf_get_incremental_xref_entry(fz_context *ctx, pdf_docum
/* Make a new final xref section if we haven't already */
ensure_incremental_xref(ctx, doc);
- xref = &doc->xref_sections[0];
+ xref = &doc->xref_sections[doc->xref_base];
if (i >= xref->num_objects)
pdf_resize_xref(ctx, doc, i + 1);
@@ -361,12 +386,49 @@ static pdf_xref_entry *pdf_get_incremental_xref_entry(fz_context *ctx, pdf_docum
int pdf_xref_is_incremental(fz_context *ctx, pdf_document *doc, int num)
{
- pdf_xref *xref = &doc->xref_sections[0];
+ pdf_xref *xref = &doc->xref_sections[doc->xref_base];
pdf_xref_subsec *sub = xref->subsec;
assert(sub != NULL && sub->next == NULL && sub->len == xref->num_objects && sub->start == 0);
- return doc->xref_altered && num < xref->num_objects && sub->table[num].type;
+ return num < xref->num_objects && sub->table[num].type;
+}
+
+void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer)
+{
+ pdf_xref *xref = &doc->xref_sections[0];
+ pdf_unsaved_sig *unsaved_sig;
+
+ /* Record details within the document structure so that contents
+ * and byte_range can be updated with their correct values at
+ * saving time */
+ unsaved_sig = fz_malloc_struct(ctx, pdf_unsaved_sig);
+ unsaved_sig->field = pdf_keep_obj(ctx, field);
+ unsaved_sig->signer = pdf_keep_signer(ctx, signer);
+ unsaved_sig->next = NULL;
+ if (xref->unsaved_sigs_end == NULL)
+ xref->unsaved_sigs_end = &xref->unsaved_sigs;
+
+ *xref->unsaved_sigs_end = unsaved_sig;
+ xref->unsaved_sigs_end = &unsaved_sig->next;
+}
+
+int pdf_xref_obj_is_unsaved_signature(pdf_document *doc, pdf_obj *obj)
+{
+ int i;
+ for (i = 0; i < doc->num_incremental_sections; i++)
+ {
+ pdf_xref *xref = &doc->xref_sections[i];
+ pdf_unsaved_sig *usig;
+
+ for (usig = xref->unsaved_sigs; usig; usig = usig->next)
+ {
+ if (usig->field == obj)
+ return 1;
+ }
+ }
+
+ return 0;
}
/* Ensure that the current populating xref has a single subsection
@@ -415,7 +477,18 @@ void pdf_xref_ensure_incremental_object(fz_context *ctx, pdf_document *doc, int
old_entry = &sub->table[num - sub->start];
new_entry = pdf_get_incremental_xref_entry(ctx, doc, num);
*new_entry = *old_entry;
- old_entry->obj = NULL;
+ if (i < doc->num_incremental_sections)
+ {
+ /* old entry is incremental and may have changes.
+ * Better keep a copy. We must override the old entry with
+ * the copy because the caller may be holding a reference to
+ * the original and expect it to end up in the new entry */
+ old_entry->obj = pdf_deep_copy_obj(ctx, old_entry->obj);
+ }
+ else
+ {
+ old_entry->obj = NULL;
+ }
old_entry->stm_buf = NULL;
}
@@ -447,6 +520,9 @@ void pdf_replace_xref(fz_context *ctx, pdf_document *doc, pdf_xref_entry *entrie
doc->xref_sections = xref;
doc->num_xref_sections = 1;
+ doc->num_incremental_sections = 0;
+ doc->xref_base = 0;
+ doc->disallow_new_increments = 0;
doc->max_xref_len = n;
memset(doc->xref_index, 0, sizeof(int)*doc->max_xref_len);
@@ -1469,7 +1545,6 @@ pdf_init_document(fz_context *ctx, pdf_document *doc)
void
pdf_close_document(fz_context *ctx, pdf_document *doc)
{
- pdf_unsaved_sig *usig;
int i;
if (!doc)
@@ -1507,14 +1582,6 @@ pdf_close_document(fz_context *ctx, pdf_document *doc)
fz_free(ctx, doc->hint_shared);
fz_free(ctx, doc->hint_obj_offsets);
- while ((usig = doc->unsaved_sigs) != NULL)
- {
- doc->unsaved_sigs = usig->next;
- pdf_drop_obj(ctx, usig->field);
- pdf_drop_signer(ctx, usig->signer);
- fz_free(ctx, usig);
- }
-
for (i=0; i < doc->num_type3_fonts; i++)
{
fz_decouple_type3_font(ctx, doc->type3_fonts[i], (void *)doc);
@@ -2644,8 +2711,10 @@ pdf_document *pdf_create_document(fz_context *ctx)
doc->file_size = 0;
doc->startxref = 0;
doc->num_xref_sections = 0;
+ doc->num_incremental_sections = 0;
+ doc->xref_base = 0;
+ doc->disallow_new_increments = 0;
pdf_get_populating_xref_entry(ctx, doc, 0);
- doc->xref_altered = 1;
trailer = pdf_new_dict(ctx, doc, 2);
pdf_dict_put_drop(ctx, trailer, PDF_NAME_Size, pdf_new_int(ctx, doc, 3));
o = root = pdf_new_dict(ctx, doc, 2);