Add QPDFWriter::getFinalVersion (fixes #266)

This commit is contained in:
Jay Berkenbilt 2019-01-04 12:32:02 -05:00
parent 837dcf8fc2
commit 16fd6e64f9
5 changed files with 73 additions and 12 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -173,6 +173,16 @@ $td->runtest("\@file exists and file doesn't",
{$td->FILE => "check-at-file.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
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 ---");

View File

@ -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 ") +