From f2228b1f88dfed31b5b16026984db69f605f84dc Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 16 Aug 2024 15:58:55 +0100 Subject: [PATCH] Fix handling of hybrid reference files in QPDF::read_xrefTable QPDF::read_xrefTable ignores type 0 entries for objects in a section if an associates XRefStm has an entry for the same object. The spec states: When the conforming reader searches for an object, if an entry is not found in any given standard cross-reference section, the search shall proceed to a cross-reference stream specified by the XRefStm entry before looking in the previous cross-reference section, If a deleted entry is found in a section, the XRefStm is not searched according to the standard. --- libqpdf/QPDF.cc | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index c5f8ee74..5144c4b3 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -952,8 +952,6 @@ QPDF::read_xrefEntry(qpdf_offset_t& f1, int& f2, char& type) qpdf_offset_t QPDF::read_xrefTable(qpdf_offset_t xref_offset) { - std::vector deleted_items; - m->file->seek(xref_offset, SEEK_SET); std::string line; while (true) { @@ -982,8 +980,7 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) "xref table", "invalid xref entry (obj=" + std::to_string(i) + ")"); } if (type == 'f') { - // Save deleted items until after we've checked the XRefStm, if any. - deleted_items.emplace_back(toI(i), f2); + insertFreeXrefEntry(QPDFObjGen(toI(i), f2)); } else { insertXrefEntry(toI(i), 1, f1, f2); } @@ -1030,23 +1027,16 @@ QPDF::read_xrefTable(qpdf_offset_t xref_offset) } } - // Handle any deleted items now that we've read the /XRefStm. - for (auto const& og: deleted_items) { - insertFreeXrefEntry(og); - } - if (cur_trailer.hasKey("/Prev")) { if (!cur_trailer.getKey("/Prev").isInteger()) { QTC::TC("qpdf", "QPDF trailer prev not integer"); throw damagedPDF("trailer", "/Prev key in trailer dictionary is not an integer"); } QTC::TC("qpdf", "QPDF prev key in trailer dictionary"); - xref_offset = cur_trailer.getKey("/Prev").getIntValue(); - } else { - xref_offset = 0; + return cur_trailer.getKey("/Prev").getIntValue(); } - return xref_offset; + return 0; } // Read a single cross-reference stream.