[gs-commits] mupdf 1.16.1.78 Separate flag for freezing updates to PDF

[email protected] (Sebastian Rasmussen) Fri, 4 Oct 2019 10:28:15 +0000 (UTC)
Newsgroups gmane.comp.printing.ghostscript.cvs
Message-ID <[email protected]>
commit 6d7d90f61a0f2110dbe45ff9f360873b28bb7f76
Author: Pete McLaughlin <[email protected]>
Date:   Sat Sep 14 11:53:41 2019 +0100

    Separate flag for freezing updates to PDF document into two.
    
    The flag freeze_updates conflated two states:
    
    * A flag indicating that repaired files can't be saved incrementally.
    
    * A flag indicating that changes to PDF objects while the document is
      being saved (e.g. when the signature dictionary has /Contents and
      /ByteRange updated) should not cause an incremental xref section
      from being created.
    
    To see why consider that pdf_save_document() calls prepare_for_save()
    which used to set the flag freeze_updates, later cleared at end of
    do_pdf_save_document(). If the document was saved incrementally but
    had no incremental xref sections, then an early return prevented
    freeze_updates from being cleared. An easy fix would have been to
    clear freeze_updates at the early return too.
    
    The same freeze_updates flag was also set by pdf_repair_xref(),
    because saving a repaired file incrementally will create a broken
    file. With the easy fix, a repaired document without incremental xref
    sections being saved incrementally could then have its freeze_updates
    flag incorrectly cleared.
    
    This commit splits freeze_updates into the existing repair_attempted
    flag and save_in_progress. This allows for clearing the latter flag
    both at the end of do_pdf_save_document() and at the early return in
    without affecting the flag set by pdf_repair_xref(). (+1 squashed commit)
    Squashed commits:
    [ff966f966] Ensure that PDFDocument freeze_updates is always reset on save
    
    We set the freeze_updates field to 1 in prepare_for_save() when saving a document,
    and we reset it to zero when we complete the save. However, we can fail to reset
    the field in do_pdf_save_document() in the case where we have incremental save
    enabled, but have no incremental sections in the document. We do a simple
    return in this instance.
    
    Add code to reset the freeze_updates field in this case.

diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h
index 55bd877..6c57da8 100644
--- a/include/mupdf/pdf/document.h
+++ b/include/mupdf/pdf/document.h
@@ -219,7 +219,7 @@ struct pdf_document_s
 	pdf_xref *xref_sections;
 	pdf_xref *saved_xref_sections;
 	int *xref_index;
-	int freeze_updates;
+	int save_in_progress;
 	int has_xref_streams;
 	int has_old_style_xrefs;
 
diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c
index 7a541a8..9a49388 100644
--- a/source/pdf/pdf-object.c
+++ b/source/pdf/pdf-object.c
@@ -681,10 +681,10 @@ static void prepare_object_for_alteration(fz_context *ctx, pdf_obj *obj, pdf_obj
 	}
 
 	/*
-		parent_num = 0 while an object is being parsed from the file.
+		parent_num == 0 while an object is being parsed from the file.
 		No further action is necessary.
 	*/
-	if (parent == 0 || doc->freeze_updates)
+	if (parent == 0 || doc->save_in_progress || doc->repair_attempted)
 		return;
 
 	/*
diff --git a/source/pdf/pdf-repair.c b/source/pdf/pdf-repair.c
index 2433a0c..fc49d88 100644
--- a/source/pdf/pdf-repair.c
+++ b/source/pdf/pdf-repair.c
@@ -331,7 +331,6 @@ pdf_repair_xref(fz_context *ctx, pdf_document *doc)
 	doc->repair_attempted = 1;
 
 	doc->dirty = 1;
-	doc->freeze_updates = 1; /* Can't support incremental update after repair */
 
 	pdf_forget_xref(ctx, doc);
 
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index 2345a37..94d8467 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -3106,12 +3106,19 @@ int pdf_can_be_saved_incrementally(fz_context *ctx, pdf_document *doc)
 static void
 prepare_for_save(fz_context *ctx, pdf_document *doc, pdf_write_options *in_opts)
 {
-	doc->freeze_updates = 1;
-
 	/* Rewrite (and possibly sanitize) the operator streams */
 	if (in_opts->do_clean || in_opts->do_sanitize)
 		clean_content_streams(ctx, doc, in_opts->do_sanitize, in_opts->do_ascii);
 
+	/* When saving a PDF with signatures the file will
+	first be written once, then the file will have its
+	digests and byte ranges calculated and and then the
+	signature dictionary containing them will be updated
+	both in memory and in the saved file. By setting this
+	flag we avoid a new xref section from being created when
+	the signature dictionary is updated. */
+	doc->save_in_progress = 1;
+
 	presize_unsaved_signature_byteranges(ctx, doc);
 }
 
@@ -3217,7 +3224,11 @@ do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts,
 	{
 		/* If no changes, nothing to write */
 		if (doc->num_incremental_sections == 0)
+		{
+			doc->save_in_progress = 0;
 			return;
+		}
+
 		if (opts->out)
 		{
 			fz_seek_output(ctx, opts->out, 0, SEEK_END);
@@ -3411,7 +3422,7 @@ do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts,
 		finalise_write_state(ctx, opts);
 		if (opts->crypt != doc->crypt)
 			pdf_drop_crypt(ctx, opts->crypt);
-		doc->freeze_updates = 0;
+		doc->save_in_progress = 0;
 	}
 	fz_catch(ctx)
 	{
@@ -3524,7 +3535,10 @@ void pdf_save_document(fz_context *ctx, pdf_document *doc, const char *filename,
 	{
 		/* If no changes, nothing to write */
 		if (doc->num_incremental_sections == 0)
+		{
+			doc->save_in_progress = 0;
 			return;
+		}
 		opts.out = fz_new_output_with_path(ctx, filename, 1);
 	}
 	else

http://git.ghostscript.com/?p=mupdf.git;a=commit;h=6d7d90f61a0f2110dbe45ff9f360873b28bb7f76

--
MuPDF library
Artifex Software, Inc.