summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/pdf/document.h6
-rw-r--r--include/mupdf/pdf/xref.h5
-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
6 files changed, 257 insertions, 162 deletions
diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h
index 668a9d13..e65a7590 100644
--- a/include/mupdf/pdf/document.h
+++ b/include/mupdf/pdf/document.h
@@ -178,9 +178,11 @@ struct pdf_document_s
int max_xref_len;
int num_xref_sections;
+ int num_incremental_sections;
+ int xref_base;
+ int disallow_new_increments;
pdf_xref *xref_sections;
int *xref_index;
- int xref_altered;
int freeze_updates;
int has_xref_streams;
@@ -244,8 +246,6 @@ struct pdf_document_s
void (*drop_js)(pdf_js *js);
int recalculating;
int dirty;
- pdf_unsaved_sig *unsaved_sigs;
- pdf_unsaved_sig **unsaved_sigs_end;
void (*update_appearance)(fz_context *ctx, pdf_document *doc, pdf_annot *annot);
diff --git a/include/mupdf/pdf/xref.h b/include/mupdf/pdf/xref.h
index 845c936e..30b59222 100644
--- a/include/mupdf/pdf/xref.h
+++ b/include/mupdf/pdf/xref.h
@@ -63,6 +63,9 @@ struct pdf_xref_s
pdf_xref_subsec *subsec;
pdf_obj *trailer;
pdf_obj *pre_repair_trailer;
+ pdf_unsaved_sig *unsaved_sigs;
+ pdf_unsaved_sig **unsaved_sigs_end;
+ fz_off_t end_ofs; /* file offset to end of xref */
};
pdf_xref_entry *pdf_cache_object(fz_context *ctx, pdf_document *doc, int num, int gen);
@@ -94,6 +97,8 @@ pdf_xref_entry *pdf_get_xref_entry(fz_context *ctx, pdf_document *doc, int i);
void pdf_replace_xref(fz_context *ctx, pdf_document *doc, pdf_xref_entry *entries, int n);
void pdf_xref_ensure_incremental_object(fz_context *ctx, pdf_document *doc, int num);
int pdf_xref_is_incremental(fz_context *ctx, pdf_document *doc, int num);
+void pdf_xref_store_unsaved_signature(fz_context *ctx, pdf_document *doc, pdf_obj *field, pdf_signer *signer);
+int pdf_xref_obj_is_unsaved_signature(pdf_document *doc, pdf_obj *obj);
void pdf_repair_xref(fz_context *ctx, pdf_document *doc);
void pdf_repair_obj_stms(fz_context *ctx, pdf_document *doc);
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);