Keep all trailers in CPDF_Parser in m_Trailers
This CL removes m_pTrailer in favor of having them all in a vector, and
having an index that points to the position of the previous m_pTrailer
in the vector.
Bug: pdfium:787
Change-Id: Ieebbf4849f7ea78f8f74d188e3adb3446a53482e
Reviewed-on: https://pdfium-review.googlesource.com/7040
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: Nicolás Peña <npm@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_parser.cpp b/core/fpdfapi/parser/cpdf_parser.cpp
index b2bde8d..841bf27 100644
--- a/core/fpdfapi/parser/cpdf_parser.cpp
+++ b/core/fpdfapi/parser/cpdf_parser.cpp
@@ -52,14 +52,14 @@
} // namespace
CPDF_Parser::CPDF_Parser()
- : m_bHasParsed(false),
+ : m_pSyntax(pdfium::MakeUnique<CPDF_SyntaxParser>()),
+ m_bHasParsed(false),
m_bXRefStream(false),
m_bVersionUpdated(false),
m_FileVersion(0),
m_pEncryptDict(nullptr),
- m_dwXrefStartObjNum(0) {
- m_pSyntax = pdfium::MakeUnique<CPDF_SyntaxParser>();
-}
+ m_TrailerPos(CPDF_Parser::kInvalidPos),
+ m_dwXrefStartObjNum(0) {}
CPDF_Parser::~CPDF_Parser() {
ReleaseEncryptHandler();
@@ -219,12 +219,13 @@
}
return SUCCESS;
}
+
CPDF_Parser::Error CPDF_Parser::SetEncryptHandler() {
ReleaseEncryptHandler();
- if (!m_pTrailer)
+ if (!GetTrailer())
return FORMAT_ERROR;
- CPDF_Object* pEncryptObj = m_pTrailer->GetObjectFor("Encrypt");
+ CPDF_Object* pEncryptObj = GetTrailer()->GetObjectFor("Encrypt");
if (pEncryptObj) {
if (CPDF_Dictionary* pEncryptDict = pEncryptObj->AsDictionary()) {
SetEncryptDictionary(pEncryptDict);
@@ -304,11 +305,13 @@
if (!LoadCrossRefV4(xrefpos, 0, true))
return false;
- m_pTrailer = LoadTrailerV4();
- if (!m_pTrailer)
+ std::unique_ptr<CPDF_Dictionary> trailer = LoadTrailerV4();
+ if (!trailer)
return false;
- int32_t xrefsize = GetDirectInteger(m_pTrailer.get(), "Size");
+ m_Trailers.push_back(std::move(trailer));
+ m_TrailerPos = m_Trailers.size() - 1;
+ int32_t xrefsize = GetDirectInteger(GetTrailer(), "Size");
if (xrefsize > 0 && xrefsize <= kMaxXRefSize)
ShrinkObjectMap(xrefsize);
@@ -317,12 +320,12 @@
std::set<FX_FILESIZE> seen_xrefpos;
CrossRefList.push_back(xrefpos);
- XRefStreamList.push_back(GetDirectInteger(m_pTrailer.get(), "XRefStm"));
+ XRefStreamList.push_back(GetDirectInteger(GetTrailer(), "XRefStm"));
seen_xrefpos.insert(xrefpos);
- // When |m_pTrailer| doesn't have Prev entry or Prev entry value is not
+ // When the trailer doesn't have Prev entry or Prev entry value is not
// numerical, GetDirectInteger() returns 0. Loading will end.
- xrefpos = GetDirectInteger(m_pTrailer.get(), "Prev");
+ xrefpos = GetDirectInteger(GetTrailer(), "Prev");
while (xrefpos) {
// Check for circular references.
if (pdfium::ContainsKey(seen_xrefpos, xrefpos))
@@ -360,14 +363,13 @@
if (!LoadLinearizedCrossRefV4(xrefpos, dwObjCount))
return false;
- if (m_pTrailer)
- m_Trailers.push_back(std::move(m_pTrailer));
-
- m_pTrailer = LoadTrailerV4();
- if (!m_pTrailer)
+ std::unique_ptr<CPDF_Dictionary> trailer = LoadTrailerV4();
+ if (!trailer)
return false;
- int32_t xrefsize = GetDirectInteger(m_pTrailer.get(), "Size");
+ m_Trailers.push_back(std::move(trailer));
+ m_TrailerPos = m_Trailers.size() - 1;
+ int32_t xrefsize = GetDirectInteger(GetTrailer(), "Size");
if (xrefsize == 0)
return false;
@@ -376,10 +378,10 @@
std::set<FX_FILESIZE> seen_xrefpos;
CrossRefList.push_back(xrefpos);
- XRefStreamList.push_back(GetDirectInteger(m_pTrailer.get(), "XRefStm"));
+ XRefStreamList.push_back(GetDirectInteger(GetTrailer(), "XRefStm"));
seen_xrefpos.insert(xrefpos);
- xrefpos = GetDirectInteger(m_pTrailer.get(), "Prev");
+ xrefpos = GetDirectInteger(GetTrailer(), "Prev");
while (xrefpos) {
// Check for circular references.
if (pdfium::ContainsKey(seen_xrefpos, xrefpos))
@@ -568,7 +570,8 @@
bool CPDF_Parser::RebuildCrossRef() {
m_ObjectInfo.clear();
m_SortedOffset.clear();
- m_pTrailer.reset();
+ m_Trailers.clear();
+ m_TrailerPos = CPDF_Parser::kInvalidPos;
ParserState state = ParserState::kDefault;
int32_t inside_index = 0;
@@ -729,7 +732,8 @@
CPDF_Object* pRoot = pDict->GetObjectFor("Root");
if (pRoot && pRoot->GetDict() &&
pRoot->GetDict()->GetObjectFor("Pages")) {
- m_pTrailer = ToDictionary(pDict->Clone());
+ m_Trailers.push_back(ToDictionary(pDict->Clone()));
+ m_TrailerPos = m_Trailers.size() - 1;
}
}
}
@@ -785,7 +789,7 @@
CPDF_Stream* pStream = pObj->AsStream();
if (CPDF_Dictionary* pTrailer =
pStream ? pStream->GetDict() : pObj->AsDictionary()) {
- if (m_pTrailer) {
+ if (GetTrailer()) {
CPDF_Object* pRoot = pTrailer->GetObjectFor("Root");
CPDF_Reference* pRef = ToReference(pRoot);
if (!pRoot ||
@@ -799,19 +803,19 @@
uint32_t dwObjNum =
pElement ? pElement->GetObjNum() : 0;
if (dwObjNum) {
- m_pTrailer->SetNewFor<CPDF_Reference>(
+ GetTrailer()->SetNewFor<CPDF_Reference>(
key, m_pDocument.Get(), dwObjNum);
} else {
- m_pTrailer->SetFor(key, pElement->Clone());
+ GetTrailer()->SetFor(key, pElement->Clone());
}
}
}
} else {
- if (pObj->IsStream()) {
- m_pTrailer = ToDictionary(pTrailer->Clone());
- } else {
- m_pTrailer = ToDictionary(std::move(pObj));
- }
+ if (pObj->IsStream())
+ m_Trailers.push_back(ToDictionary(pTrailer->Clone()));
+ else
+ m_Trailers.push_back(ToDictionary(std::move(pObj)));
+ m_TrailerPos = m_Trailers.size() - 1;
FX_FILESIZE dwSavePos = m_pSyntax->GetPos();
CFX_ByteString strWord = m_pSyntax->GetKeyword();
@@ -915,7 +919,7 @@
last_trailer = m_pSyntax->m_FileLen;
m_SortedOffset.insert(last_trailer - m_pSyntax->m_HeaderOffset);
- return m_pTrailer && !m_ObjectInfo.empty();
+ return GetTrailer() && !m_ObjectInfo.empty();
}
bool CPDF_Parser::LoadCrossRefV5(FX_FILESIZE* pos, bool bMainXRef) {
@@ -951,7 +955,8 @@
std::unique_ptr<CPDF_Dictionary> pNewTrailer = ToDictionary(pDict->Clone());
if (bMainXRef) {
- m_pTrailer = std::move(pNewTrailer);
+ m_Trailers.push_back(std::move(pNewTrailer));
+ m_TrailerPos = m_Trailers.size() - 1;
ShrinkObjectMap(size);
for (auto& it : m_ObjectInfo)
it.second.type = 0;
@@ -1060,10 +1065,10 @@
}
CPDF_Array* CPDF_Parser::GetIDArray() {
- if (!m_pTrailer)
+ if (!GetTrailer())
return nullptr;
- CPDF_Object* pID = m_pTrailer->GetObjectFor("ID");
+ CPDF_Object* pID = GetTrailer()->GetObjectFor("ID");
if (!pID)
return nullptr;
@@ -1074,19 +1079,19 @@
std::unique_ptr<CPDF_Object> pNewObj =
ParseIndirectObject(nullptr, pRef->GetRefObjNum());
pID = pNewObj.get();
- m_pTrailer->SetFor("ID", std::move(pNewObj));
+ GetTrailer()->SetFor("ID", std::move(pNewObj));
return ToArray(pID);
}
uint32_t CPDF_Parser::GetRootObjNum() {
CPDF_Reference* pRef =
- ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Root") : nullptr);
+ ToReference(GetTrailer() ? GetTrailer()->GetObjectFor("Root") : nullptr);
return pRef ? pRef->GetRefObjNum() : 0;
}
uint32_t CPDF_Parser::GetInfoObjNum() {
CPDF_Reference* pRef =
- ToReference(m_pTrailer ? m_pTrailer->GetObjectFor("Info") : nullptr);
+ ToReference(GetTrailer() ? GetTrailer()->GetObjectFor("Info") : nullptr);
if (pRef)
return pRef->GetRefObjNum();
@@ -1488,11 +1493,13 @@
}
if (bLoadV4) {
- m_pTrailer = LoadTrailerV4();
- if (!m_pTrailer)
+ std::unique_ptr<CPDF_Dictionary> trailer = LoadTrailerV4();
+ if (!trailer)
return SUCCESS;
- int32_t xrefsize = GetDirectInteger(m_pTrailer.get(), "Size");
+ m_Trailers.push_back(std::move(trailer));
+ m_TrailerPos = m_Trailers.size() - 1;
+ int32_t xrefsize = GetDirectInteger(GetTrailer(), "Size");
if (xrefsize > 0)
ShrinkObjectMap(xrefsize);
}
@@ -1559,8 +1566,6 @@
CPDF_Parser::Error CPDF_Parser::LoadLinearizedMainXRefTable() {
uint32_t dwSaveMetadataObjnum = m_pSyntax->m_MetadataObjnum;
m_pSyntax->m_MetadataObjnum = 0;
- if (m_pTrailer)
- m_Trailers.push_back(std::move(m_pTrailer));
m_pSyntax->SetPos(m_LastXRefOffset - m_pSyntax->m_HeaderOffset);
uint8_t ch = 0;
diff --git a/core/fpdfapi/parser/cpdf_parser.h b/core/fpdfapi/parser/cpdf_parser.h
index 8f55ddb..efe1055 100644
--- a/core/fpdfapi/parser/cpdf_parser.h
+++ b/core/fpdfapi/parser/cpdf_parser.h
@@ -7,6 +7,7 @@
#ifndef CORE_FPDFAPI_PARSER_CPDF_PARSER_H_
#define CORE_FPDFAPI_PARSER_CPDF_PARSER_H_
+#include <limits>
#include <map>
#include <memory>
#include <set>
@@ -41,6 +42,8 @@
// are higher, but this may be large enough in practice.
static const uint32_t kMaxObjectNumber = 1048576;
+ static const size_t kInvalidPos = std::numeric_limits<size_t>::max();
+
CPDF_Parser();
~CPDF_Parser();
@@ -51,7 +54,10 @@
void SetPassword(const char* password) { m_Password = password; }
CFX_ByteString GetPassword() { return m_Password; }
- CPDF_Dictionary* GetTrailer() const { return m_pTrailer.get(); }
+ CPDF_Dictionary* GetTrailer() const {
+ return m_TrailerPos == kInvalidPos ? nullptr
+ : m_Trailers[m_TrailerPos].get();
+ }
FX_FILESIZE GetLastXRefOffset() const { return m_LastXRefOffset; }
uint32_t GetPermissions() const;
@@ -161,8 +167,8 @@
std::unique_ptr<CPDF_SecurityHandler> m_pSecurityHandler;
CFX_ByteString m_Password;
std::set<FX_FILESIZE> m_SortedOffset;
- std::unique_ptr<CPDF_Dictionary> m_pTrailer;
std::vector<std::unique_ptr<CPDF_Dictionary>> m_Trailers;
+ size_t m_TrailerPos;
std::unique_ptr<CPDF_LinearizedHeader> m_pLinearized;
uint32_t m_dwXrefStartObjNum;