summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-06-10 16:06:27 +0100
committerRobin Watts <robin.watts@artifex.com>2016-06-13 13:09:09 +0100
commit3aacd38b1f559b4dc9b8f420f39915575fb8ad2d (patch)
tree699268e2d0e0e0cf5d9509a24d1f324e25c32bab
parentd93f4d8433c0cc1f40533663a0d2ec509f973dbc (diff)
downloadmupdf-3aacd38b1f559b4dc9b8f420f39915575fb8ad2d.tar.xz
Add pdf_write_document.
Allow us to write a document to an fz_output as opposed to just a filename. We cannot write digital signatures in this method though. Will ponder that in a later commit.
-rw-r--r--include/mupdf/pdf/document.h13
-rw-r--r--source/pdf/pdf-write.c245
2 files changed, 170 insertions, 88 deletions
diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h
index 857f2d58..6248145e 100644
--- a/include/mupdf/pdf/document.h
+++ b/include/mupdf/pdf/document.h
@@ -409,6 +409,19 @@ struct pdf_write_options_s
void pdf_parse_write_options(fz_context *ctx, pdf_write_options *opts, const char *args);
/*
+ pdf_has_unsaved_sigs: Returns true if there are digital signatures waiting to
+ to updated on save.
+*/
+int pdf_has_unsaved_sigs(fz_context *ctx, pdf_document *doc);
+
+/*
+ pdf_write_document: Write out the document to an output stream with all changes finalised.
+
+ This method will throw an error if pdf_has_unsaved_sigs.
+*/
+void pdf_write_document(fz_context *ctx, pdf_document *doc, fz_output *out, pdf_write_options *opts);
+
+/*
pdf_save_document: Write out the document to a file with all changes finalised.
*/
void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename, pdf_write_options *opts);
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index 87c31926..34e831d1 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -2813,28 +2813,9 @@ int pdf_can_be_saved_incrementally(fz_context *ctx, pdf_document *doc)
return 1;
}
-void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename, pdf_write_options *in_opts)
+static void
+prepare_for_save(fz_context *ctx, pdf_document *doc, pdf_write_options *in_opts)
{
- pdf_write_options opts_defaults = { 0 };
- pdf_write_state opts = { 0 };
-
- int lastfree;
- int num;
- int xref_len;
-
- if (!doc)
- return;
-
- if (!in_opts)
- in_opts = &opts_defaults;
-
- if (in_opts->do_incremental && doc->repair_attempted)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes on a repaired file");
- if (in_opts->do_incremental && in_opts->do_garbage)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with garbage collection");
- if (in_opts->do_incremental && in_opts->do_linear)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with linearisation");
-
doc->freeze_updates = 1;
/* Sanitize the operator streams */
@@ -2843,68 +2824,68 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
pdf_finish_edit(ctx, doc);
presize_unsaved_signature_byteranges(ctx, doc);
+}
- xref_len = pdf_xref_len(ctx, doc);
+static void
+do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pdf_write_options *in_opts)
+{
+ int lastfree;
+ int num;
+ int xref_len;
if (in_opts->do_incremental)
{
/* If no changes, nothing to write */
if (doc->num_incremental_sections == 0)
return;
- opts.out = fz_new_output_with_path(ctx, filename, 1);
- if (opts.out)
+ if (opts->out)
{
- fz_seek_output(ctx, opts.out, 0, SEEK_END);
- fz_puts(ctx, opts.out, "\n");
+ fz_seek_output(ctx, opts->out, 0, SEEK_END);
+ fz_puts(ctx, opts->out, "\n");
}
}
- else
- {
- opts.out = fz_new_output_with_path(ctx, filename, 0);
- }
- if (!opts.out)
- fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open output file '%s'", filename);
+ xref_len = pdf_xref_len(ctx, doc);
fz_try(ctx)
{
- initialise_write_state(ctx, doc, in_opts, &opts);
+ initialise_write_state(ctx, doc, in_opts, opts);
/* Make sure any objects hidden in compressed streams have been loaded */
- if (!opts.do_incremental)
+ if (!opts->do_incremental)
{
pdf_ensure_solid_xref(ctx, doc, xref_len);
preloadobjstms(ctx, doc);
}
/* Sweep & mark objects from the trailer */
- if (opts.do_garbage >= 1 || opts.do_linear)
- (void)markobj(ctx, doc, &opts, pdf_trailer(ctx, doc));
+ if (opts->do_garbage >= 1 || opts->do_linear)
+ (void)markobj(ctx, doc, opts, pdf_trailer(ctx, doc));
else
for (num = 0; num < xref_len; num++)
- opts.use_list[num] = 1;
+ opts->use_list[num] = 1;
/* Coalesce and renumber duplicate objects */
- if (opts.do_garbage >= 3)
- removeduplicateobjs(ctx, doc, &opts);
+ if (opts->do_garbage >= 3)
+ removeduplicateobjs(ctx, doc, opts);
/* Compact xref by renumbering and removing unused objects */
- if (opts.do_garbage >= 2 || opts.do_linear)
- compactxref(ctx, doc, &opts);
+ if (opts->do_garbage >= 2 || opts->do_linear)
+ compactxref(ctx, doc, opts);
/* Make renumbering affect all indirect references and update xref */
- if (opts.do_garbage >= 2 || opts.do_linear)
- renumberobjs(ctx, doc, &opts);
+ if (opts->do_garbage >= 2 || opts->do_linear)
+ renumberobjs(ctx, doc, opts);
/* Truncate the xref after compacting and renumbering */
- if ((opts.do_garbage >= 2 || opts.do_linear) && !opts.do_incremental)
- while (xref_len > 0 && !opts.use_list[xref_len-1])
+ if ((opts->do_garbage >= 2 || opts->do_linear) && !opts->do_incremental)
+ while (xref_len > 0 && !opts->use_list[xref_len-1])
xref_len--;
- if (opts.do_linear)
- linearize(ctx, doc, &opts);
+ if (opts->do_linear)
+ linearize(ctx, doc, opts);
- if (opts.do_incremental)
+ if (opts->do_incremental)
{
int i;
@@ -2914,29 +2895,29 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
{
doc->xref_base = doc->num_incremental_sections - i - 1;
- writeobjects(ctx, doc, &opts, 0);
+ writeobjects(ctx, doc, opts, 0);
#ifdef DEBUG_WRITING
- dump_object_details(ctx, doc, &opts);
+ dump_object_details(ctx, doc, opts);
#endif
for (num = 0; num < xref_len; num++)
{
- if (!opts.use_list[num] && pdf_xref_is_incremental(ctx, doc, num))
+ 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->gen_list[num] = 65535;
+ opts->ofs_list[num] = 0;
}
}
- opts.first_xref_offset = fz_tell_output(ctx, opts.out);
+ opts->first_xref_offset = fz_tell_output(ctx, opts->out);
if (doc->has_xref_streams)
- writexrefstream(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
+ 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);
+ writexref(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
- doc->xref_sections[doc->xref_base].end_ofs = fz_tell_output(ctx, opts.out);
+ doc->xref_sections[doc->xref_base].end_ofs = fz_tell_output(ctx, opts->out);
}
doc->xref_base = 0;
@@ -2944,67 +2925,63 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
}
else
{
- writeobjects(ctx, doc, &opts, 0);
+ writeobjects(ctx, doc, opts, 0);
#ifdef DEBUG_WRITING
- dump_object_details(ctx, doc, &opts);
+ dump_object_details(ctx, doc, opts);
#endif
/* Construct linked list of free object slots */
lastfree = 0;
for (num = 0; num < xref_len; num++)
{
- if (!opts.use_list[num])
+ if (!opts->use_list[num])
{
- opts.gen_list[num]++;
- opts.ofs_list[lastfree] = num;
+ opts->gen_list[num]++;
+ opts->ofs_list[lastfree] = num;
lastfree = num;
}
}
- if (opts.do_linear)
+ if (opts->do_linear)
{
- opts.main_xref_offset = fz_tell_output(ctx, opts.out);
- writexref(ctx, doc, &opts, 0, opts.start, 0, 0, opts.first_xref_offset);
- opts.file_len = fz_tell_output(ctx, opts.out);
+ opts->main_xref_offset = fz_tell_output(ctx, opts->out);
+ writexref(ctx, doc, opts, 0, opts->start, 0, 0, opts->first_xref_offset);
+ opts->file_len = fz_tell_output(ctx, opts->out);
- make_hint_stream(ctx, doc, &opts);
- if (opts.do_ascii)
+ make_hint_stream(ctx, doc, opts);
+ if (opts->do_ascii)
{
- opts.hintstream_len *= 2;
- opts.hintstream_len += 1 + ((opts.hintstream_len+63)>>6);
+ 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_seek_output(ctx, opts.out, 0, 0);
- writeobjects(ctx, doc, &opts, 1);
-
- padto(ctx, 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_seek_output(ctx, opts->out, 0, 0);
+ writeobjects(ctx, doc, opts, 1);
+
+ padto(ctx, 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_tell_output(ctx, opts.out);
- writexref(ctx, doc, &opts, 0, xref_len, 1, 0, opts.first_xref_offset);
+ opts->first_xref_offset = fz_tell_output(ctx, opts->out);
+ writexref(ctx, doc, opts, 0, xref_len, 1, 0, opts->first_xref_offset);
}
- doc->xref_sections[0].end_ofs = fz_tell_output(ctx, opts.out);
+ doc->xref_sections[0].end_ofs = fz_tell_output(ctx, opts->out);
}
- fz_drop_output(ctx, opts.out);
- opts.out = NULL;
- complete_signatures(ctx, doc, &opts, filename);
-
doc->dirty = 0;
}
fz_always(ctx)
{
#ifdef DEBUG_LINEARIZATION
- page_objects_dump(&opts);
- objects_dump(ctx, doc, &opts);
+ page_objects_dump(opts);
+ objects_dump(ctx, doc, opts);
#endif
- finalise_write_state(ctx, &opts);
+ finalise_write_state(ctx, opts);
doc->freeze_updates = 0;
}
@@ -3014,6 +2991,98 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
}
}
+int pdf_has_unsaved_sigs(fz_context *ctx, pdf_document *doc)
+{
+ int s;
+ for (s = 0; s < doc->num_incremental_sections; s++)
+ {
+ pdf_xref *xref = &doc->xref_sections[doc->num_incremental_sections - s - 1];
+
+ if (xref->unsaved_sigs)
+ return 1;
+ }
+ return 0;
+}
+
+void pdf_write_document(fz_context *ctx, pdf_document *doc, fz_output *out, pdf_write_options *in_opts)
+{
+ pdf_write_options opts_defaults = { 0 };
+ pdf_write_state opts = { 0 };
+
+ if (!doc)
+ return;
+
+ if (!in_opts)
+ in_opts = &opts_defaults;
+
+ if (in_opts->do_incremental && doc->repair_attempted)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes on a repaired file");
+ if (in_opts->do_incremental && in_opts->do_garbage)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with garbage collection");
+ if (in_opts->do_incremental && in_opts->do_linear)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with linearisation");
+ if (pdf_has_unsaved_sigs(ctx, doc))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't write pdf that has unsaved sigs to an fz_output!");
+
+ prepare_for_save(ctx, doc, in_opts);
+
+ opts.out = out;
+
+ do_pdf_save_document(ctx, doc, &opts, in_opts);
+}
+
+void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename, pdf_write_options *in_opts)
+{
+ pdf_write_options opts_defaults = { 0 };
+ pdf_write_state opts = { 0 };
+
+ if (!doc)
+ return;
+
+ if (!in_opts)
+ in_opts = &opts_defaults;
+
+ if (in_opts->do_incremental && doc->repair_attempted)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes on a repaired file");
+ if (in_opts->do_incremental && in_opts->do_garbage)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with garbage collection");
+ if (in_opts->do_incremental && in_opts->do_linear)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Can't do incremental writes with linearisation");
+
+ prepare_for_save(ctx, doc, in_opts);
+
+ if (in_opts->do_incremental)
+ {
+ /* If no changes, nothing to write */
+ if (doc->num_incremental_sections == 0)
+ return;
+ opts.out = fz_new_output_with_path(ctx, filename, 1);
+ }
+ else
+ {
+ opts.out = fz_new_output_with_path(ctx, filename, 0);
+ }
+
+ if (!opts.out)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot open output file '%s'", filename);
+
+ fz_try(ctx)
+ {
+ do_pdf_save_document(ctx, doc, &opts, in_opts);
+
+ complete_signatures(ctx, doc, &opts, filename);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_output(ctx, opts.out);
+ opts.out = NULL;
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+}
+
#define KIDS_PER_LEVEL 32
#if 0