summaryrefslogtreecommitdiff
path: root/source/pdf/pdf-write.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/pdf/pdf-write.c')
-rw-r--r--source/pdf/pdf-write.c119
1 files changed, 118 insertions, 1 deletions
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index a161c763..fd126aac 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2270,6 +2270,117 @@ static void dump_object_details(pdf_document *doc, pdf_write_options *opts)
}
#endif
+static void presize_unsaved_signature_byteranges(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;
+
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ n++;
+
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ /* 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_getp(usig->field, "V/ByteRange");
+
+ for (i = 0; i < n+1; i++)
+ {
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, INT_MAX));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, INT_MAX));
+ }
+ }
+ }
+}
+
+static void complete_signatures(pdf_document *doc, pdf_write_options *opts, char *filename)
+{
+ fz_context *ctx = doc->ctx;
+ pdf_unsaved_sig *usig;
+ FILE *f;
+ char buf[5120];
+ int i;
+ int flen;
+ int last_end;
+
+ if (doc->unsaved_sigs)
+ {
+ pdf_obj *byte_range;
+
+ f = fopen(filename, "rb+");
+ if (!f)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Failed to open %s to complete signatures", filename);
+
+ fseek(f, 0, SEEK_END);
+ flen = ftell(f);
+
+ /* Locate the byte ranges and contents in the saved file */
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ char *bstr, *cstr, *fstr;
+ int pnum = pdf_obj_parent_num(pdf_dict_getp(usig->field, "V/ByteRange"));
+ 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(doc, 4);
+ pdf_dict_putp_drop(doc->unsaved_sigs->field, "V/ByteRange", byte_range);
+
+ last_end = 0;
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ {
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, last_end));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, usig->contents_start - last_end));
+ last_end = usig->contents_end;
+ }
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, last_end));
+ pdf_array_push_drop(byte_range, pdf_new_int(doc, flen - last_end));
+
+ /* Copy the new ByteRange to the other unsaved signatures */
+ for (usig = doc->unsaved_sigs->next; usig; usig = usig->next)
+ pdf_dict_putp_drop(usig->field, "V/ByteRange", pdf_copy_array(byte_range));
+
+ /* Write the byte range into buf, padding with spaces*/
+ i = pdf_sprint_obj(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)
+ {
+ fseek(f, usig->byte_range_start, SEEK_SET);
+ fwrite(buf, 1, usig->byte_range_end - usig->byte_range_start, f);
+ }
+
+ fclose(f);
+
+ /* Write the digests into the file */
+ for (usig = doc->unsaved_sigs; usig; usig = usig->next)
+ pdf_write_digest(doc, filename, byte_range, usig->contents_start, usig->contents_end - usig->contents_start, usig->signer);
+ }
+}
+
void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_opts)
{
int lastfree;
@@ -2285,6 +2396,7 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
ctx = doc->ctx;
pdf_finish_edit(doc);
+ presize_unsaved_signature_byteranges(doc);
xref_len = pdf_xref_len(doc);
@@ -2415,6 +2527,10 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
writexref(doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
}
+ fclose(opts.out);
+ opts.out = NULL;
+ complete_signatures(doc, &opts, filename);
+
doc->dirty = 0;
}
fz_always(ctx)
@@ -2439,7 +2555,8 @@ void pdf_write_document(pdf_document *doc, char *filename, fz_write_options *fz_
pdf_drop_obj(opts.hints_s);
pdf_drop_obj(opts.hints_length);
page_objects_list_destroy(ctx, opts.page_object_lists);
- fclose(opts.out);
+ if (opts.out)
+ fclose(opts.out);
doc->freeze_updates = 0;
}
fz_catch(ctx)