Fix PDF loading when an initial xref stream references a xref table
In CPDF_Parser, LoadAllCrossRefV4() will try to call LoadCrossRefV5() if
LoadCrossRefV4() fails for secondary xref data. However,
LoadAllCrossRefV5() only calls LoadCrossRefV5(). As a result, if
LoadAllCrossRefV5() only knows how to handle cross reference streams,
and fails if it ever encounters a cross reference table. Update
LoadAllCrossRefV5() to call LoadCrossRefV4() if LoadCrossRefV5() fails.
Then unsuppress the pixel test that renders correctly as a result of
this fix.
Along the way, fix some nits for how CPDF_Dictionary variables in
CPDF_Parser are named and assigned to.
Bug: pdfium:2123
Change-Id: Id77056b459dcd58864e34821940e73a29caed927
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116274
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index b28deeb..89a846e 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -407,18 +407,18 @@
// SLOW ...
LoadCrossRefV4(xref_offset, true);
- RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
- if (!pDict) {
+ RetainPtr<CPDF_Dictionary> trailer_dict = LoadTrailerV4();
+ if (!trailer_dict) {
return false;
}
- xref_offset = pDict->GetDirectIntegerFor("Prev");
- xref_stm = pDict->GetIntegerFor("XRefStm");
+ xref_offset = trailer_dict->GetDirectIntegerFor("Prev");
+ xref_stm = trailer_dict->GetIntegerFor("XRefStm");
xref_stream_list.insert(xref_stream_list.begin(), xref_stm);
// SLOW ...
m_CrossRefTable = CPDF_CrossRefTable::MergeUp(
- std::make_unique<CPDF_CrossRefTable>(std::move(pDict),
+ std::make_unique<CPDF_CrossRefTable>(std::move(trailer_dict),
kNoV4TrailerObjectNumber),
std::move(m_CrossRefTable));
}
@@ -483,18 +483,18 @@
// SLOW ...
LoadCrossRefV4(xref_offset, true);
- RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
- if (!pDict) {
+ RetainPtr<CPDF_Dictionary> trailer_dict = LoadTrailerV4();
+ if (!trailer_dict) {
return false;
}
- xref_offset = pDict->GetDirectIntegerFor("Prev");
- xref_stm = pDict->GetIntegerFor("XRefStm");
+ xref_offset = trailer_dict->GetDirectIntegerFor("Prev");
+ xref_stm = trailer_dict->GetIntegerFor("XRefStm");
xref_stream_list.insert(xref_stream_list.begin(), xref_stm);
// SLOW ...
m_CrossRefTable = CPDF_CrossRefTable::MergeUp(
- std::make_unique<CPDF_CrossRefTable>(std::move(pDict),
+ std::make_unique<CPDF_CrossRefTable>(std::move(trailer_dict),
kNoV4TrailerObjectNumber),
std::move(m_CrossRefTable));
}
@@ -680,13 +680,27 @@
std::set<FX_FILESIZE> seen_xref_offset;
while (xref_offset > 0) {
seen_xref_offset.insert(xref_offset);
+ FX_FILESIZE save_xref_offset = xref_offset;
if (!LoadCrossRefV5(&xref_offset, /*is_main_xref=*/false)) {
- return false;
+ // If a cross-reference stream failed to load at `xref_offset`, try
+ // loading a cross-reference table at the same location. Use
+ // `save_xref_offset` instead of `xref_offset`, as `xref_offset` may have
+ // changed.
+ if (!LoadCrossRefV4(save_xref_offset, /*bSkip=*/false)) {
+ return false;
+ }
+
+ RetainPtr<CPDF_Dictionary> trailer_dict = LoadTrailerV4();
+ if (!trailer_dict) {
+ return false;
+ }
+ xref_offset = trailer_dict->GetDirectIntegerFor("Prev");
}
// Check for circular references.
- if (pdfium::Contains(seen_xref_offset, xref_offset))
+ if (pdfium::Contains(seen_xref_offset, xref_offset)) {
return false;
+ }
}
m_ObjectStreamMap.clear();
m_bXRefStream = true;
@@ -893,9 +907,10 @@
const ObjectType existing_type = GetObjectType(obj_num);
if (existing_type == ObjectType::kNull) {
const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths);
- if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset))
+ if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) {
m_CrossRefTable->AddNormal(obj_num, 0, /*is_object_stream=*/false,
offset);
+ }
return;
}
@@ -910,9 +925,10 @@
if (type == ObjectType::kNormal) {
const uint32_t offset = GetSecondXRefStreamEntry(entry_span, field_widths);
- if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset))
+ if (pdfium::base::IsValueInRangeForNumericType<FX_FILESIZE>(offset)) {
m_CrossRefTable->AddNormal(obj_num, 0, /*is_object_stream=*/false,
offset);
+ }
return;
}
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index 77d15a8..96c84d12 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -659,9 +659,6 @@
# TODO(pdfium:2001): Remove after associated bug is fixed
bug_2001.pdf * * * *
-# TODO(pdfium:2123): Remove after associated bug is fixed
-bug_2123.pdf * * * *
-
# TODO(chromium:237527): Remove after associated bug is fixed
bug_237527_1.in * * * *