Ignore /Prev for hybrid-reference files
Per spec, files whose trailers have /XRefStm and /Prev should ignore the
/Prev value. Do this to properly fix the rendering for bug_1484283.pdf,
without causing any known regressions. Re-enable that pixel test.
Bug: chromium:1484283
Change-Id: I371adaba8b22577b24fd8e000a30992840e651d9
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116093
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index 43984d0..d502c42 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -389,33 +389,39 @@
std::vector<FX_FILESIZE> xref_list{xref_offset};
std::set<FX_FILESIZE> seen_xref_offset{xref_offset};
- // When the trailer doesn't have Prev entry or Prev entry value is not
- // numerical, GetDirectInteger() returns 0. Loading will end.
- xref_offset = GetTrailer()->GetDirectIntegerFor("Prev");
- while (xref_offset > 0) {
- // Check for circular references.
- if (pdfium::Contains(seen_xref_offset, xref_offset))
- return false;
+ // Ignore /Prev for hybrid-reference files.
+ // See ISO 32000-1:2008 spec, table 17.
+ if (!xref_stm) {
+ // When the trailer doesn't have Prev entry or Prev entry value is not
+ // numerical, GetDirectInteger() returns 0. Loading will end.
+ xref_offset = GetTrailer()->GetDirectIntegerFor("Prev");
+ while (xref_offset > 0) {
+ // Check for circular references.
+ if (pdfium::Contains(seen_xref_offset, xref_offset)) {
+ return false;
+ }
- seen_xref_offset.insert(xref_offset);
- xref_list.insert(xref_list.begin(), xref_offset);
+ seen_xref_offset.insert(xref_offset);
+ xref_list.insert(xref_list.begin(), xref_offset);
- // SLOW ...
- LoadCrossRefV4(xref_offset, true);
+ // SLOW ...
+ LoadCrossRefV4(xref_offset, true);
- RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
- if (!pDict)
- return false;
+ RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
+ if (!pDict) {
+ return false;
+ }
- xref_offset = pDict->GetDirectIntegerFor("Prev");
- xref_stm = pDict->GetIntegerFor("XRefStm");
- xref_stream_list.insert(xref_stream_list.begin(), xref_stm);
+ xref_offset = pDict->GetDirectIntegerFor("Prev");
+ xref_stm = pDict->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),
- kNoV4TrailerObjectNumber),
- std::move(m_CrossRefTable));
+ // SLOW ...
+ m_CrossRefTable = CPDF_CrossRefTable::MergeUp(
+ std::make_unique<CPDF_CrossRefTable>(std::move(pDict),
+ kNoV4TrailerObjectNumber),
+ std::move(m_CrossRefTable));
+ }
}
for (size_t i = 0; i < xref_list.size(); ++i) {
@@ -459,33 +465,39 @@
kNoV4TrailerObjectNumber),
std::move(m_CrossRefTable));
- // Now GetTrailer() returns the merged trailer, where /Prev is from the
- // main-trailer.
- FX_FILESIZE xref_offset = GetTrailer()->GetDirectIntegerFor("Prev");
- while (xref_offset > 0) {
- // Check for circular references.
- if (pdfium::Contains(seen_xref_offset, xref_offset))
- return false;
+ // Ignore /Prev for hybrid-reference files.
+ // See ISO 32000-1:2008 spec, table 17.
+ if (!xref_stm) {
+ // Now GetTrailer() returns the merged trailer, where /Prev is from the
+ // main-trailer.
+ FX_FILESIZE xref_offset = GetTrailer()->GetDirectIntegerFor("Prev");
+ while (xref_offset > 0) {
+ // Check for circular references.
+ if (pdfium::Contains(seen_xref_offset, xref_offset)) {
+ return false;
+ }
- seen_xref_offset.insert(xref_offset);
- xref_list.insert(xref_list.begin(), xref_offset);
+ seen_xref_offset.insert(xref_offset);
+ xref_list.insert(xref_list.begin(), xref_offset);
- // SLOW ...
- LoadCrossRefV4(xref_offset, true);
+ // SLOW ...
+ LoadCrossRefV4(xref_offset, true);
- RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
- if (!pDict)
- return false;
+ RetainPtr<CPDF_Dictionary> pDict(LoadTrailerV4());
+ if (!pDict) {
+ return false;
+ }
- xref_offset = pDict->GetDirectIntegerFor("Prev");
- xref_stm = pDict->GetIntegerFor("XRefStm");
- xref_stream_list.insert(xref_stream_list.begin(), xref_stm);
+ xref_offset = pDict->GetDirectIntegerFor("Prev");
+ xref_stm = pDict->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),
- kNoV4TrailerObjectNumber),
- std::move(m_CrossRefTable));
+ // SLOW ...
+ m_CrossRefTable = CPDF_CrossRefTable::MergeUp(
+ std::make_unique<CPDF_CrossRefTable>(std::move(pDict),
+ kNoV4TrailerObjectNumber),
+ std::move(m_CrossRefTable));
+ }
}
if (xref_stream_list[0] > 0 &&
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index 28c98ff..96c84d12 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -639,9 +639,6 @@
# TODO(pdfium:1457): Remove after associated bug is fixed
bug_1457.in * * * *
-# TODO(chromium:1484283): Remove after associated bug is fixed
-bug_1484283.pdf * * * *
-
# TODO(pdfium:1519): Remove after associated bug is fixed
bug_1519.in * * * *