aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2019-01-04 18:32:02 +0100
committerJay Berkenbilt <ejb@ql.org>2019-01-04 18:37:22 +0100
commit16fd6e64f947e17144e05325e51d792df33eaa61 (patch)
treeca397d4fcdbc15fc6b9414c6a8db0c0343aba3e2
parent837dcf8fc2546a80f205a0c4c53e5a1545c53a84 (diff)
downloadqpdf-16fd6e64f947e17144e05325e51d792df33eaa61.tar.zst
Add QPDFWriter::getFinalVersion (fixes #266)
-rw-r--r--ChangeLog5
-rw-r--r--include/qpdf/QPDFWriter.hh14
-rw-r--r--libqpdf/QPDFWriter.cc44
-rw-r--r--qpdf/qtest/qpdf.test10
-rw-r--r--qpdf/test_driver.cc12
5 files changed, 73 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog
index 7814dadb..3d889d78 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2019-01-04 Jay Berkenbilt <ejb@ql.org>
+ * Add new method QPDFWriter::getFinalVersion, which returns the
+ PDF version that will ultimately be written to the final file. See
+ comments in QPDFWriter.hh for some restrictions on its use. Fixes
+ #266.
+
* When unexpected errors are found while checking linearization
data, print an error message instead of calling assert, which
cause the program to crash. Fixes #209, #231.
diff --git a/include/qpdf/QPDFWriter.hh b/include/qpdf/QPDFWriter.hh
index 4385a409..8f18dad1 100644
--- a/include/qpdf/QPDFWriter.hh
+++ b/include/qpdf/QPDFWriter.hh
@@ -404,6 +404,18 @@ class QPDFWriter
QPDF_DLL
void registerProgressReporter(PointerHolder<ProgressReporter>);
+ // Return the PDF version that will be written into the header.
+ // Calling this method does all the preparation for writing, so it
+ // is an error to call any methods that may cause a change to the
+ // version. Adding new objects to the original file after calling
+ // this may also cause problems. It is safe to update existing
+ // objects or stream contents after calling this method, e.g., to
+ // include the final version number in metadata.
+ QPDF_DLL
+ std::string getFinalVersion();
+
+ // Write the final file. There is no expectation of being able to
+ // call write() more than once.
QPDF_DLL
void write();
@@ -473,6 +485,7 @@ class QPDFWriter
void writeLinearized();
void enqueuePart(std::vector<QPDFObjectHandle>& part);
void writeEncryptionDictionary();
+ void doWriteSetup();
void writeHeader();
void writeHintStream(int hint_id);
qpdf_offset_t writeXRefTable(
@@ -598,6 +611,7 @@ class QPDFWriter
bool deterministic_id;
Pl_MD5* md5_pipeline;
std::string deterministic_id_data;
+ bool did_write_setup;
// For linearization only
std::string lin_pass1_filename;
diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc
index 22b990ff..598d4654 100644
--- a/libqpdf/QPDFWriter.cc
+++ b/libqpdf/QPDFWriter.cc
@@ -63,6 +63,7 @@ QPDFWriter::Members::Members(QPDF& pdf) :
max_ostream_index(0),
deterministic_id(false),
md5_pipeline(0),
+ did_write_setup(false),
events_expected(0),
events_seen(0),
next_progress_report(0)
@@ -2358,8 +2359,14 @@ QPDFWriter::prepareFileForWrite()
}
void
-QPDFWriter::write()
+QPDFWriter::doWriteSetup()
{
+ if (this->m->did_write_setup)
+ {
+ return;
+ }
+ this->m->did_write_setup = true;
+
// Do preliminary setup
if (this->m->linearized)
@@ -2507,6 +2514,23 @@ QPDFWriter::write()
setMinimumPDFVersion("1.5");
}
+ setMinimumPDFVersion(this->m->pdf.getPDFVersion(),
+ this->m->pdf.getExtensionLevel());
+ this->m->final_pdf_version = this->m->min_pdf_version;
+ this->m->final_extension_level = this->m->min_extension_level;
+ if (! this->m->forced_pdf_version.empty())
+ {
+ QTC::TC("qpdf", "QPDFWriter using forced PDF version");
+ this->m->final_pdf_version = this->m->forced_pdf_version;
+ this->m->final_extension_level = this->m->forced_extension_level;
+ }
+}
+
+void
+QPDFWriter::write()
+{
+ doWriteSetup();
+
// Set up progress reporting. We spent about equal amounts of time
// preparing and writing one pass. To get a rough estimate of
// progress, we track handling of indirect objects. For linearized
@@ -2569,20 +2593,16 @@ QPDFWriter::writeEncryptionDictionary()
closeObject(this->m->encryption_dict_objid);
}
+std::string
+QPDFWriter::getFinalVersion()
+{
+ doWriteSetup();
+ return this->m->final_pdf_version;
+}
+
void
QPDFWriter::writeHeader()
{
- setMinimumPDFVersion(this->m->pdf.getPDFVersion(),
- this->m->pdf.getExtensionLevel());
- this->m->final_pdf_version = this->m->min_pdf_version;
- this->m->final_extension_level = this->m->min_extension_level;
- if (! this->m->forced_pdf_version.empty())
- {
- QTC::TC("qpdf", "QPDFWriter using forced PDF version");
- this->m->final_pdf_version = this->m->forced_pdf_version;
- this->m->final_extension_level = this->m->forced_extension_level;
- }
-
writeString("%PDF-");
writeString(this->m->final_pdf_version);
if (this->m->pclm)
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 0ef397c2..cad3633c 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -175,6 +175,16 @@ $td->runtest("\@file exists and file doesn't",
show_ntests();
# ----------
+$td->notify("--- Final Version ---");
+$n_tests += 1;
+
+$td->runtest("check final version",
+ {$td->COMMAND => "test_driver 54 minimal.pdf"},
+ {$td->STRING => "test 54 done\n", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+
+show_ntests();
+# ----------
$td->notify("--- Dangling Refs ---");
my @dangling = (qw(minimal dangling-refs));
$n_tests += 2 * scalar(@dangling);
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 1f4b865c..8031d0cc 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -1865,6 +1865,18 @@ void runtest(int n, char const* filename1, char const* arg2)
w.setStaticID(true);
w.write();
}
+ else if (n == 54)
+ {
+ // Test getFinalVersion. This must be invoked with a file
+ // whose final version is not 1.5.
+ QPDFWriter w(pdf, "a.pdf");
+ assert(pdf.getPDFVersion() != "1.5");
+ w.setObjectStreamMode(qpdf_o_generate);
+ if (w.getFinalVersion() != "1.5")
+ {
+ std::cout << "oops: " << w.getFinalVersion() << std::endl;
+ }
+ }
else
{
throw std::runtime_error(std::string("invalid test ") +