diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index ef904eae..dc208ee6 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -829,6 +829,34 @@ QPDF::Xref_table::subsection(std::string const& line) file->getLastOffset() + toI(p - start)}; } +std::vector +QPDF::Xref_table::subsections(std::string& line) +{ + std::vector result; + qpdf_offset_t f1 = 0; + int f2 = 0; + char type = '\0'; + + while (true) { + line.assign(50, '\0'); + file->read(line.data(), line.size()); + auto [obj, num, offset] = result.emplace_back(subsection(line)); + file->seek(offset, SEEK_SET); + for (qpdf_offset_t i = obj; i - num < obj; ++i) { + if (!read_entry(f1, f2, type)) { + QTC::TC("qpdf", "QPDF invalid xref entry"); + throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")"); + } + } + qpdf_offset_t pos = file->tell(); + if (read_token().isWord("trailer")) { + return result; + } else { + file->seek(pos, SEEK_SET); + } + } +} + bool QPDF::Xref_table::read_bad_entry(qpdf_offset_t& f1, int& f2, char& type) { @@ -970,10 +998,8 @@ QPDF::Xref_table::read_table(qpdf_offset_t xref_offset) { file->seek(xref_offset, SEEK_SET); std::string line; - while (true) { - line.assign(50, '\0'); - file->read(line.data(), line.size()); - auto [obj, num, offset] = subsection(line); + auto subs = subsections(line); + for (auto [obj, num, offset]: subs) { file->seek(offset, SEEK_SET); for (qpdf_offset_t i = obj; i - num < obj; ++i) { if (i == 0) { @@ -985,7 +1011,6 @@ QPDF::Xref_table::read_table(qpdf_offset_t xref_offset) int f2 = 0; char type = '\0'; if (!read_entry(f1, f2, type)) { - QTC::TC("qpdf", "QPDF invalid xref entry"); throw damaged_table("invalid xref entry (obj=" + std::to_string(i) + ")"); } if (type == 'f') { diff --git a/libqpdf/qpdf/QPDF_private.hh b/libqpdf/qpdf/QPDF_private.hh index 186d32b5..4009cdd2 100644 --- a/libqpdf/qpdf/QPDF_private.hh +++ b/libqpdf/qpdf/QPDF_private.hh @@ -125,6 +125,7 @@ class QPDF::Xref_table // Methods to parse tables qpdf_offset_t read_table(qpdf_offset_t offset); + std::vector subsections(std::string& line); Subsection subsection(std::string const& line); bool read_entry(qpdf_offset_t& f1, int& f2, char& type); bool read_bad_entry(qpdf_offset_t& f1, int& f2, char& type); diff --git a/qpdf/qtest/qpdf/xref-errors.out b/qpdf/qtest/qpdf/xref-errors.out index 66420c35..ff3ae822 100644 --- a/qpdf/qtest/qpdf/xref-errors.out +++ b/qpdf/qtest/qpdf/xref-errors.out @@ -3,6 +3,11 @@ WARNING: xref-errors.pdf (xref table, offset 606): accepting invalid xref table WARNING: xref-errors.pdf (xref table, offset 627): accepting invalid xref table entry WARNING: xref-errors.pdf (xref table, offset 648): accepting invalid xref table entry WARNING: xref-errors.pdf (xref table, offset 667): accepting invalid xref table entry +WARNING: xref-errors.pdf (xref table, offset 585): accepting invalid xref table entry +WARNING: xref-errors.pdf (xref table, offset 606): accepting invalid xref table entry +WARNING: xref-errors.pdf (xref table, offset 627): accepting invalid xref table entry +WARNING: xref-errors.pdf (xref table, offset 648): accepting invalid xref table entry +WARNING: xref-errors.pdf (xref table, offset 667): accepting invalid xref table entry checking xref-errors.pdf PDF Version: 1.3 File is not encrypted