From b8bdef0ad12883d72ced5eb443e6e34a93bbbb91 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 25 Oct 2015 11:09:25 -0400 Subject: Implement deterministic ID For non-encrypted files, determinstic ID generation uses file contents instead of timestamp and file name. At a small runtime cost, this enables generation of the same /ID if the same inputs are converted in the same way multiple times. --- include/qpdf/QPDFWriter.hh | 44 +++++++++++++++++++++++++++++++++++++++++++- include/qpdf/qpdf-c.h | 5 ++++- 2 files changed, 47 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh index 8997e144..747386bf 100644 --- a/include/qpdf/QPDFWriter.hh +++ b/include/qpdf/QPDFWriter.hh @@ -35,6 +35,7 @@ class QPDF; class QPDFObjectHandle; class Pl_Count; +class Pl_MD5; class QPDFWriter { @@ -189,8 +190,22 @@ class QPDFWriter QPDF_DLL void setExtraHeaderText(std::string const&); + // Causes a deterministic /ID value to be generated. When this is + // set, the current time and output file name are not used as part + // of /ID generation. Instead, a digest of all significant parts + // of the output file's contents is included in the /ID + // calculation. Use of a deterministic /ID can be handy when it is + // desirable for a repeat of the same qpdf operation on the same + // inputs being written to the same outputs with the same + // parameters to generate exactly the same results. This feature + // is incompatible with encrypted files because, for encrypted + // files, the /ID is generated before any part of the file is + // written since it is an input to the encryption process. + QPDF_DLL + void setDeterministicID(bool); + // Cause a static /ID value to be generated. Use only in test - // suites. + // suites. See also setDeterministicID. QPDF_DLL void setStaticID(bool); @@ -298,6 +313,9 @@ class QPDFWriter void writeObject(QPDFObjectHandle object, int object_stream_index = -1); void writeTrailer(trailer_e which, int size, bool xref_stream, qpdf_offset_t prev = 0); + void writeTrailer(trailer_e which, int size, + bool xref_stream, qpdf_offset_t prev, + int linearization_pass); void unparseObject(QPDFObjectHandle object, int level, unsigned int flags); void unparseObject(QPDFObjectHandle object, int level, @@ -348,6 +366,15 @@ class QPDFWriter int hint_id, qpdf_offset_t hint_offset, qpdf_offset_t hint_length); + qpdf_offset_t writeXRefTable( + trailer_e which, int first, int last, int size, + // for linearization + qpdf_offset_t prev, + bool suppress_offsets, + int hint_id, + qpdf_offset_t hint_offset, + qpdf_offset_t hint_length, + int linearization_pass); qpdf_offset_t writeXRefStream( int objid, int max_id, qpdf_offset_t max_offset, trailer_e which, int first, int last, int size); @@ -360,6 +387,16 @@ class QPDFWriter qpdf_offset_t hint_offset, qpdf_offset_t hint_length, bool skip_compression); + qpdf_offset_t writeXRefStream( + int objid, int max_id, qpdf_offset_t max_offset, + trailer_e which, int first, int last, int size, + // for linearization + qpdf_offset_t prev, + int hint_id, + qpdf_offset_t hint_offset, + qpdf_offset_t hint_length, + bool skip_compression, + int linearization_pass); int calculateXrefStreamPadding(int xref_bytes); // When filtering subsections, push additional pipelines to the @@ -380,6 +417,8 @@ class QPDFWriter void adjustAESStreamLength(size_t& length); void pushEncryptionFilter(); void pushDiscardFilter(); + void pushMD5Pipeline(); + void computeDeterministicIDData(); void discardGeneration(std::map const& in, std::map& out); @@ -437,6 +476,9 @@ class QPDFWriter std::map object_to_object_stream; std::map > object_stream_to_objects; std::list pipeline_stack; + bool deterministic_id; + Pl_MD5* md5_pipeline; + std::string deterministic_id_data; // For linearization only std::map obj_renumber_no_gen; diff --git a/include/qpdf/qpdf-c.h b/include/qpdf/qpdf-c.h index 96ea8aa9..95ae5f61 100644 --- a/include/qpdf/qpdf-c.h +++ b/include/qpdf/qpdf-c.h @@ -324,8 +324,11 @@ extern "C" { QPDF_DLL void qpdf_set_qdf_mode(qpdf_data qpdf, QPDF_BOOL value); + QPDF_DLL + void qpdf_set_deterministic_ID(qpdf_data qpdf, QPDF_BOOL value); + /* Never use qpdf_set_static_ID except in test suites to suppress - * generation of a random /ID. + * generation of a random /ID. See also qpdf_set_deterministic_ID. */ QPDF_DLL void qpdf_set_static_ID(qpdf_data qpdf, QPDF_BOOL value); -- cgit v1.2.3-54-g00ecf