aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf/QPDF.cc
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2024-01-06 22:51:03 +0100
committerJay Berkenbilt <ejb@ql.org>2024-01-06 22:51:03 +0100
commit2994f9cf4cc45e33406de34d4bce45ca491df98e (patch)
treee108755c1deb2a7cc711e44d7dbe9b693c8b4cef /libqpdf/QPDF.cc
parent8a24287c392969d1aa25bc9aaabc3502c0bbaf08 (diff)
downloadqpdf-2994f9cf4cc45e33406de34d4bce45ca491df98e.tar.zst
Attempt to find xref streams during recovery (fixes #1103)
Diffstat (limited to 'libqpdf/QPDF.cc')
-rw-r--r--libqpdf/QPDF.cc32
1 files changed, 32 insertions, 0 deletions
diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc
index af3db080..67f5e2e0 100644
--- a/libqpdf/QPDF.cc
+++ b/libqpdf/QPDF.cc
@@ -580,6 +580,38 @@ QPDF::reconstruct_xref(QPDFExc& e)
m->deleted_objects.clear();
if (!m->trailer.isInitialized()) {
+ qpdf_offset_t max_offset{0};
+ // If there are any xref streams, take the last one to appear.
+ for (auto const& iter: m->xref_table) {
+ auto entry = iter.second;
+ if (entry.getType() != 1) {
+ continue;
+ }
+ auto oh = getObjectByObjGen(iter.first);
+ try {
+ if (!oh.isStreamOfType("/XRef")) {
+ continue;
+ }
+ } catch (std::exception&) {
+ continue;
+ }
+ auto offset = entry.getOffset();
+ if (offset > max_offset) {
+ max_offset = offset;
+ setTrailer(oh.getDict());
+ }
+ }
+ if (max_offset > 0) {
+ try {
+ read_xref(max_offset);
+ } catch (std::exception&) {
+ throw damagedPDF("", 0, "error decoding candidate xref stream while recovering damaged file");
+ }
+ QTC::TC("qpdf", "QPDF recover xref stream");
+ }
+ }
+
+ if (!m->trailer.isInitialized()) {
// We could check the last encountered object to see if it was an xref stream. If so, we
// could try to get the trailer from there. This may make it possible to recover files with
// bad startxref pointers even when they have object streams.