From cfcb279e49d1f2049a64652be7bf75d1ae557f1d Mon Sep 17 00:00:00 2001 From: m-holger Date: Thu, 24 Nov 2022 16:50:46 +0000 Subject: Alternative fix logic for fixDanglingReferences --- include/qpdf/QPDF.hh | 5 ++-- libqpdf/QPDF.cc | 64 +++++++++++++++++++++------------------------------ libqpdf/QPDFWriter.cc | 2 +- 3 files changed, 30 insertions(+), 41 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 7cec14d2..5b2db6a8 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1173,6 +1173,7 @@ class QPDF void inParse(bool); void setTrailer(QPDFObjectHandle obj); void read_xref(qpdf_offset_t offset); + bool resolveXRefTable(); void reconstruct_xref(QPDFExc& e); bool parse_xrefFirst(std::string const& line, int& obj, int& num, int& bytes); @@ -1202,10 +1203,10 @@ class QPDF bool attempt_recovery, qpdf_offset_t offset, std::string const& description, - QPDFObjGen const& exp_og, + QPDFObjGen exp_og, QPDFObjGen& og, bool skip_cache_if_in_xref); - void resolve(QPDFObjGen const& og); + void resolve(QPDFObjGen og); void resolveObjectsInStream(int obj_stream_number); void stopOnError(std::string const& message); QPDFObjectHandle reserveObjectIfNotExists(QPDFObjGen const& og); diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 89487ee1..86846675 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1292,48 +1292,36 @@ QPDF::showXRefTable() } } +// Resolve all objects in the xref table. If this triggers a xref table +// reconstruction abort and return false. Otherwise return true. +bool +QPDF::resolveXRefTable() +{ + bool may_change = !this->m->reconstructed_xref; + for (auto& iter: this->m->xref_table) { + if (isUnresolved(iter.first)) { + resolve(iter.first); + if (may_change && this->m->reconstructed_xref) { + return false; + } + } + } + return true; +} + +// Ensure all objects in the pdf file, including those in indirect +// references, appear in the object cache. void QPDF::fixDanglingReferences(bool force) { - // Ensure all objects in the pdf file, including those in indirect - // references, appear in the object cache. - if (this->m->fixed_dangling_refs && !force) { + if (this->m->fixed_dangling_refs) { return; } - - // Make sure everything in the xref table appears in the object - // cache. - for (auto const& iter: this->m->xref_table) { - auto og = iter.first; - if (!isCached(og)) { - m->obj_cache[og] = - ObjCache(QPDF_Unresolved::create(this, og), -1, -1); - } - } - - // Resolve all known objects. The parser inserts any indirect - // reference into the object cache, including dangling references. - bool orig_reconstructed_xref = this->m->reconstructed_xref; - bool triggered_xref_reconstruction = false; - for (auto const& iter: this->m->obj_cache) { - resolve(iter.first); - if (!orig_reconstructed_xref && this->m->reconstructed_xref) { - triggered_xref_reconstruction = true; - // We triggered xref reconstruction. We'll have to start - // over. - break; - } - } - if (triggered_xref_reconstruction) { - // Resolving objects triggered xref reconstruction. This may - // cause new objects to appear in the xref. Start over again. - // This recursive call can never go more than two deep since - // we never clear this->m->reconstructed_xref. + if (!resolveXRefTable()) { QTC::TC("qpdf", "QPDF fix dangling triggered xref reconstruction"); - fixDanglingReferences(force); - } else { - this->m->fixed_dangling_refs = true; + resolveXRefTable(); } + this->m->fixed_dangling_refs = true; } size_t @@ -1356,7 +1344,7 @@ QPDF::getAllObjects() { // After fixDanglingReferences is called, all objects are in the // object cache. - fixDanglingReferences(true); + fixDanglingReferences(); std::vector result; for (auto const& iter: this->m->obj_cache) { result.push_back(newIndirect(iter.first, iter.second.object)); @@ -1616,7 +1604,7 @@ QPDF::readObjectAtOffset( bool try_recovery, qpdf_offset_t offset, std::string const& description, - QPDFObjGen const& exp_og, + QPDFObjGen exp_og, QPDFObjGen& og, bool skip_cache_if_in_xref) { @@ -1799,7 +1787,7 @@ QPDF::readObjectAtOffset( } void -QPDF::resolve(QPDFObjGen const& og) +QPDF::resolve(QPDFObjGen og) { if (!isUnresolved(og)) { return; diff --git a/libqpdf/QPDFWriter.cc b/libqpdf/QPDFWriter.cc index b29f75b9..b07aef53 100644 --- a/libqpdf/QPDFWriter.cc +++ b/libqpdf/QPDFWriter.cc @@ -2266,7 +2266,7 @@ QPDFWriter::prepareFileForWrite() // Make document extension level information direct as required by // the spec. - this->m->pdf.fixDanglingReferences(true); + this->m->pdf.fixDanglingReferences(); QPDFObjectHandle root = this->m->pdf.getRoot(); for (auto const& key: root.getKeys()) { QPDFObjectHandle oh = root.getKey(key); -- cgit v1.2.3-54-g00ecf