diff options
-rw-r--r-- | include/mupdf/pdf/document.h | 6 | ||||
-rw-r--r-- | include/mupdf/pdf/xref.h | 5 | ||||
-rw-r--r-- | source/pdf/pdf-form.c | 11 | ||||
-rw-r--r-- | source/pdf/pdf-pkcs7.c | 14 | ||||
-rw-r--r-- | source/pdf/pdf-write.c | 274 | ||||
-rw-r--r-- | source/pdf/pdf-xref.c | 109 |
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); |