aboutsummaryrefslogtreecommitdiff
path: root/core/fpdfapi/parser/cpdf_document.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fpdfapi/parser/cpdf_document.cpp')
-rw-r--r--core/fpdfapi/parser/cpdf_document.cpp385
1 files changed, 239 insertions, 146 deletions
diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
index d26d5c4aa..ee9dfcdc9 100644
--- a/core/fpdfapi/parser/cpdf_document.cpp
+++ b/core/fpdfapi/parser/cpdf_document.cpp
@@ -1,4 +1,4 @@
-// Copyright 2014 PDFium Authors. All rights reserved.
+// Copyright 2014 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,8 @@
#include "core/fpdfapi/parser/cpdf_document.h"
-#include <set>
#include <utility>
-#include <vector>
-#include "build/build_config.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_linearized_header.h"
@@ -21,43 +18,109 @@
#include "core/fpdfapi/parser/cpdf_reference.h"
#include "core/fpdfapi/parser/cpdf_stream.h"
#include "core/fpdfapi/parser/cpdf_stream_acc.h"
-#include "core/fpdfapi/parser/cpdf_string.h"
+#include "core/fpdfapi/parser/fpdf_parser_utility.h"
#include "core/fxcodec/jbig2/JBig2_DocumentContext.h"
#include "core/fxcrt/fx_codepage.h"
-#include "third_party/base/ptr_util.h"
-#include "third_party/base/stl_util.h"
+#include "core/fxcrt/scoped_set_insertion.h"
+#include "core/fxcrt/stl_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/base/check.h"
+#include "third_party/base/containers/contains.h"
namespace {
const int kMaxPageLevel = 1024;
-int CountPages(CPDF_Dictionary* pPages,
- std::set<CPDF_Dictionary*>* visited_pages) {
+// Returns a value in the range [0, `CPDF_Document::kPageMaxNum`), or nullopt on
+// error.
+absl::optional<int> CountPages(
+ RetainPtr<CPDF_Dictionary> pPages,
+ std::set<RetainPtr<CPDF_Dictionary>>* visited_pages) {
int count = pPages->GetIntegerFor("Count");
if (count > 0 && count < CPDF_Document::kPageMaxNum)
return count;
- CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
+ RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids");
if (!pKidList)
return 0;
count = 0;
for (size_t i = 0; i < pKidList->size(); i++) {
- CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
- if (!pKid || pdfium::ContainsKey(*visited_pages, pKid))
+ RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i);
+ if (!pKid || pdfium::Contains(*visited_pages, pKid))
continue;
if (pKid->KeyExist("Kids")) {
// Use |visited_pages| to help detect circular references of pages.
- pdfium::ScopedSetInsertion<CPDF_Dictionary*> local_add(visited_pages,
- pKid);
- count += CountPages(pKid, visited_pages);
+ ScopedSetInsertion<RetainPtr<CPDF_Dictionary>> local_add(visited_pages,
+ pKid);
+ absl::optional<int> local_count =
+ CountPages(std::move(pKid), visited_pages);
+ if (!local_count.has_value()) {
+ return absl::nullopt; // Propagate error.
+ }
+ count += local_count.value();
} else {
// This page is a leaf node.
count++;
}
+ if (count >= CPDF_Document::kPageMaxNum) {
+ return absl::nullopt; // Error: too many pages.
+ }
}
pPages->SetNewFor<CPDF_Number>("Count", count);
return count;
}
+int FindPageIndex(const CPDF_Dictionary* pNode,
+ uint32_t* skip_count,
+ uint32_t objnum,
+ int* index,
+ int level) {
+ if (!pNode->KeyExist("Kids")) {
+ if (objnum == pNode->GetObjNum())
+ return *index;
+
+ if (*skip_count != 0)
+ (*skip_count)--;
+
+ (*index)++;
+ return -1;
+ }
+
+ RetainPtr<const CPDF_Array> pKidList = pNode->GetArrayFor("Kids");
+ if (!pKidList)
+ return -1;
+
+ if (level >= kMaxPageLevel)
+ return -1;
+
+ size_t count = pNode->GetIntegerFor("Count");
+ if (count <= *skip_count) {
+ (*skip_count) -= count;
+ (*index) += count;
+ return -1;
+ }
+
+ if (count && count == pKidList->size()) {
+ for (size_t i = 0; i < count; i++) {
+ RetainPtr<const CPDF_Reference> pKid =
+ ToReference(pKidList->GetObjectAt(i));
+ if (pKid && pKid->GetRefObjNum() == objnum)
+ return static_cast<int>(*index + i);
+ }
+ }
+
+ for (size_t i = 0; i < pKidList->size(); i++) {
+ RetainPtr<const CPDF_Dictionary> pKid = pKidList->GetDictAt(i);
+ if (!pKid || pKid == pNode)
+ continue;
+
+ int found_index =
+ FindPageIndex(pKid.Get(), skip_count, objnum, index, level + 1);
+ if (found_index >= 0)
+ return found_index;
+ }
+ return -1;
+}
+
} // namespace
CPDF_Document::CPDF_Document(std::unique_ptr<RenderDataIface> pRenderData,
@@ -69,7 +132,19 @@ CPDF_Document::CPDF_Document(std::unique_ptr<RenderDataIface> pRenderData,
m_pDocPage->SetDocument(this);
}
-CPDF_Document::~CPDF_Document() = default;
+CPDF_Document::~CPDF_Document() {
+ // Be absolutely certain that |m_pExtension| is null before destroying
+ // the extension, to avoid re-entering it while being destroyed. clang
+ // seems to already do this for us, but the C++ standards seem to
+ // indicate the opposite.
+ m_pExtension.reset();
+}
+
+// static
+bool CPDF_Document::IsValidPageObject(const CPDF_Object* obj) {
+ // See ISO 32000-1:2008 spec, table 30.
+ return ValidateDictType(ToDictionary(obj), "Page");
+}
RetainPtr<CPDF_Object> CPDF_Document::ParseIndirectObject(uint32_t objnum) {
return m_pParser ? m_pParser->ParseIndirectObject(objnum) : nullptr;
@@ -78,30 +153,33 @@ RetainPtr<CPDF_Object> CPDF_Document::ParseIndirectObject(uint32_t objnum) {
bool CPDF_Document::TryInit() {
SetLastObjNum(m_pParser->GetLastObjNum());
- CPDF_Object* pRootObj = GetOrParseIndirectObject(m_pParser->GetRootObjNum());
+ RetainPtr<CPDF_Object> pRootObj =
+ GetOrParseIndirectObject(m_pParser->GetRootObjNum());
if (pRootObj)
- m_pRootDict.Reset(pRootObj->GetDict());
+ m_pRootDict = pRootObj->GetMutableDict();
LoadPages();
return GetRoot() && GetPageCount() > 0;
}
CPDF_Parser::Error CPDF_Document::LoadDoc(
- const RetainPtr<IFX_SeekableReadStream>& pFileAccess,
- const char* password) {
+ RetainPtr<IFX_SeekableReadStream> pFileAccess,
+ const ByteString& password) {
if (!m_pParser)
- SetParser(pdfium::MakeUnique<CPDF_Parser>(this));
+ SetParser(std::make_unique<CPDF_Parser>(this));
- return HandleLoadResult(m_pParser->StartParse(pFileAccess, password));
+ return HandleLoadResult(
+ m_pParser->StartParse(std::move(pFileAccess), password));
}
CPDF_Parser::Error CPDF_Document::LoadLinearizedDoc(
- const RetainPtr<CPDF_ReadValidator>& validator,
- const char* password) {
+ RetainPtr<CPDF_ReadValidator> validator,
+ const ByteString& password) {
if (!m_pParser)
- SetParser(pdfium::MakeUnique<CPDF_Parser>(this));
+ SetParser(std::make_unique<CPDF_Parser>(this));
- return HandleLoadResult(m_pParser->StartLinearizedParse(validator, password));
+ return HandleLoadResult(
+ m_pParser->StartLinearizedParse(std::move(validator), password));
}
void CPDF_Document::LoadPages() {
@@ -112,20 +190,27 @@ void CPDF_Document::LoadPages() {
return;
}
- m_PageList.resize(linearized_header->GetPageCount());
- ASSERT(linearized_header->GetFirstPageNo() < m_PageList.size());
- m_PageList[linearized_header->GetFirstPageNo()] =
- linearized_header->GetFirstPageObjNum();
+ uint32_t objnum = linearized_header->GetFirstPageObjNum();
+ if (!IsValidPageObject(GetOrParseIndirectObject(objnum).Get())) {
+ m_PageList.resize(RetrievePageCount());
+ return;
+ }
+
+ uint32_t first_page_num = linearized_header->GetFirstPageNo();
+ uint32_t page_count = linearized_header->GetPageCount();
+ DCHECK(first_page_num < page_count);
+ m_PageList.resize(page_count);
+ m_PageList[first_page_num] = objnum;
}
-CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage,
- int* nPagesToGo,
- size_t level) {
+RetainPtr<CPDF_Dictionary> CPDF_Document::TraversePDFPages(int iPage,
+ int* nPagesToGo,
+ size_t level) {
if (*nPagesToGo < 0 || m_bReachedMaxPageLevel)
return nullptr;
- CPDF_Dictionary* pPages = m_pTreeTraversal[level].first;
- CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
+ RetainPtr<CPDF_Dictionary> pPages = m_pTreeTraversal[level].first;
+ RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids");
if (!pKidList) {
m_pTreeTraversal.pop_back();
if (*nPagesToGo != 1)
@@ -138,12 +223,12 @@ CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage,
m_bReachedMaxPageLevel = true;
return nullptr;
}
- CPDF_Dictionary* page = nullptr;
+ RetainPtr<CPDF_Dictionary> page;
for (size_t i = m_pTreeTraversal[level].second; i < pKidList->size(); i++) {
if (*nPagesToGo == 0)
break;
pKidList->ConvertToIndirectObjectAt(i, this);
- CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
+ RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i);
if (!pKid) {
(*nPagesToGo)--;
m_pTreeTraversal[level].second++;
@@ -158,22 +243,23 @@ CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage,
(*nPagesToGo)--;
m_pTreeTraversal[level].second++;
if (*nPagesToGo == 0) {
- page = pKid;
+ page = std::move(pKid);
break;
}
} else {
// If the vector has size level+1, the child is not in yet
if (m_pTreeTraversal.size() == level + 1)
- m_pTreeTraversal.push_back(std::make_pair(pKid, 0));
+ m_pTreeTraversal.emplace_back(std::move(pKid), 0);
// Now m_pTreeTraversal[level+1] should exist and be equal to pKid.
- CPDF_Dictionary* pageKid = TraversePDFPages(iPage, nPagesToGo, level + 1);
+ RetainPtr<CPDF_Dictionary> pPageKid =
+ TraversePDFPages(iPage, nPagesToGo, level + 1);
// Check if child was completely processed, i.e. it popped itself out
if (m_pTreeTraversal.size() == level + 1)
m_pTreeTraversal[level].second++;
// If child did not finish, no pages to go, or max level reached, end
if (m_pTreeTraversal.size() != level + 1 || *nPagesToGo == 0 ||
m_bReachedMaxPageLevel) {
- page = pageKid;
+ page = std::move(pPageKid);
break;
}
}
@@ -190,7 +276,7 @@ void CPDF_Document::ResetTraversal() {
}
void CPDF_Document::SetParser(std::unique_ptr<CPDF_Parser> pParser) {
- ASSERT(!m_pParser);
+ DCHECK(!m_pParser);
m_pParser = std::move(pParser);
}
@@ -200,104 +286,75 @@ CPDF_Parser::Error CPDF_Document::HandleLoadResult(CPDF_Parser::Error error) {
return error;
}
-const CPDF_Dictionary* CPDF_Document::GetPagesDict() const {
+RetainPtr<const CPDF_Dictionary> CPDF_Document::GetPagesDict() const {
const CPDF_Dictionary* pRoot = GetRoot();
return pRoot ? pRoot->GetDictFor("Pages") : nullptr;
}
-CPDF_Dictionary* CPDF_Document::GetPagesDict() {
- return const_cast<CPDF_Dictionary*>(
- static_cast<const CPDF_Document*>(this)->GetPagesDict());
+RetainPtr<CPDF_Dictionary> CPDF_Document::GetMutablePagesDict() {
+ return pdfium::WrapRetain(
+ const_cast<CPDF_Dictionary*>(this->GetPagesDict().Get()));
}
bool CPDF_Document::IsPageLoaded(int iPage) const {
return !!m_PageList[iPage];
}
-CPDF_Dictionary* CPDF_Document::GetPageDictionary(int iPage) {
- if (!pdfium::IndexInBounds(m_PageList, iPage))
+RetainPtr<const CPDF_Dictionary> CPDF_Document::GetPageDictionary(int iPage) {
+ if (!fxcrt::IndexInBounds(m_PageList, iPage))
return nullptr;
const uint32_t objnum = m_PageList[iPage];
if (objnum) {
- CPDF_Dictionary* result = ToDictionary(GetOrParseIndirectObject(objnum));
+ RetainPtr<CPDF_Dictionary> result =
+ ToDictionary(GetOrParseIndirectObject(objnum));
if (result)
return result;
}
- CPDF_Dictionary* pPages = GetPagesDict();
+ RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict();
if (!pPages)
return nullptr;
if (m_pTreeTraversal.empty()) {
ResetTraversal();
- m_pTreeTraversal.push_back(std::make_pair(pPages, 0));
+ m_pTreeTraversal.emplace_back(std::move(pPages), 0);
}
int nPagesToGo = iPage - m_iNextPageToTraverse + 1;
- CPDF_Dictionary* pPage = TraversePDFPages(iPage, &nPagesToGo, 0);
+ RetainPtr<CPDF_Dictionary> pPage = TraversePDFPages(iPage, &nPagesToGo, 0);
m_iNextPageToTraverse = iPage + 1;
return pPage;
}
+RetainPtr<CPDF_Dictionary> CPDF_Document::GetMutablePageDictionary(int iPage) {
+ return pdfium::WrapRetain(
+ const_cast<CPDF_Dictionary*>(GetPageDictionary(iPage).Get()));
+}
+
void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) {
m_PageList[iPage] = objNum;
}
-int CPDF_Document::FindPageIndex(const CPDF_Dictionary* pNode,
- uint32_t* skip_count,
- uint32_t objnum,
- int* index,
- int level) const {
- if (!pNode->KeyExist("Kids")) {
- if (objnum == pNode->GetObjNum())
- return *index;
-
- if (*skip_count)
- (*skip_count)--;
-
- (*index)++;
- return -1;
- }
-
- const CPDF_Array* pKidList = pNode->GetArrayFor("Kids");
- if (!pKidList)
- return -1;
-
- if (level >= kMaxPageLevel)
- return -1;
-
- size_t count = pNode->GetIntegerFor("Count");
- if (count <= *skip_count) {
- (*skip_count) -= count;
- (*index) += count;
- return -1;
- }
-
- if (count && count == pKidList->size()) {
- for (size_t i = 0; i < count; i++) {
- const CPDF_Reference* pKid = ToReference(pKidList->GetObjectAt(i));
- if (pKid && pKid->GetRefObjNum() == objnum)
- return static_cast<int>(*index + i);
- }
- }
+JBig2_DocumentContext* CPDF_Document::GetOrCreateCodecContext() {
+ if (!m_pCodecContext)
+ m_pCodecContext = std::make_unique<JBig2_DocumentContext>();
+ return m_pCodecContext.get();
+}
- for (size_t i = 0; i < pKidList->size(); i++) {
- const CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
- if (!pKid || pKid == pNode)
- continue;
+RetainPtr<CPDF_Stream> CPDF_Document::CreateModifiedAPStream() {
+ auto stream = NewIndirect<CPDF_Stream>();
+ m_ModifiedAPStreamIDs.insert(stream->GetObjNum());
+ return stream;
+}
- int found_index = FindPageIndex(pKid, skip_count, objnum, index, level + 1);
- if (found_index >= 0)
- return found_index;
- }
- return -1;
+bool CPDF_Document::IsModifiedAPStream(const CPDF_Stream* stream) const {
+ return stream && pdfium::Contains(m_ModifiedAPStreamIDs, stream->GetObjNum());
}
int CPDF_Document::GetPageIndex(uint32_t objnum) {
- uint32_t nPages = m_PageList.size();
uint32_t skip_count = 0;
bool bSkipped = false;
- for (uint32_t i = 0; i < nPages; i++) {
+ for (uint32_t i = 0; i < m_PageList.size(); ++i) {
if (m_PageList[i] == objnum)
return i;
@@ -306,7 +363,7 @@ int CPDF_Document::GetPageIndex(uint32_t objnum) {
bSkipped = true;
}
}
- const CPDF_Dictionary* pPages = GetPagesDict();
+ RetainPtr<const CPDF_Dictionary> pPages = GetPagesDict();
if (!pPages)
return -1;
@@ -314,28 +371,29 @@ int CPDF_Document::GetPageIndex(uint32_t objnum) {
int found_index = FindPageIndex(pPages, &skip_count, objnum, &start_index, 0);
// Corrupt page tree may yield out-of-range results.
- if (!pdfium::IndexInBounds(m_PageList, found_index))
+ if (!fxcrt::IndexInBounds(m_PageList, found_index))
return -1;
- m_PageList[found_index] = objnum;
+ // Only update |m_PageList| when |objnum| points to a /Page object.
+ if (IsValidPageObject(GetOrParseIndirectObject(objnum).Get()))
+ m_PageList[found_index] = objnum;
return found_index;
}
int CPDF_Document::GetPageCount() const {
- return pdfium::CollectionSize<int>(m_PageList);
+ return fxcrt::CollectionSize<int>(m_PageList);
}
int CPDF_Document::RetrievePageCount() {
- CPDF_Dictionary* pPages = GetPagesDict();
+ RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict();
if (!pPages)
return 0;
if (!pPages->KeyExist("Kids"))
return 1;
- std::set<CPDF_Dictionary*> visited_pages;
- visited_pages.insert(pPages);
- return CountPages(pPages, &visited_pages);
+ std::set<RetainPtr<CPDF_Dictionary>> visited_pages = {pPages};
+ return CountPages(std::move(pPages), &visited_pages).value_or(0);
}
uint32_t CPDF_Document::GetUserPermissions() const {
@@ -345,22 +403,38 @@ uint32_t CPDF_Document::GetUserPermissions() const {
return m_pExtension ? m_pExtension->GetUserPermissions() : 0;
}
+RetainPtr<CPDF_StreamAcc> CPDF_Document::GetFontFileStreamAcc(
+ RetainPtr<const CPDF_Stream> pFontStream) {
+ return m_pDocPage->GetFontFileStreamAcc(std::move(pFontStream));
+}
+
+void CPDF_Document::MaybePurgeFontFileStreamAcc(
+ RetainPtr<CPDF_StreamAcc>&& pStreamAcc) {
+ if (m_pDocPage)
+ m_pDocPage->MaybePurgeFontFileStreamAcc(std::move(pStreamAcc));
+}
+
+void CPDF_Document::MaybePurgeImage(uint32_t objnum) {
+ if (m_pDocPage)
+ m_pDocPage->MaybePurgeImage(objnum);
+}
+
void CPDF_Document::CreateNewDoc() {
- ASSERT(!m_pRootDict);
- ASSERT(!m_pInfoDict);
- m_pRootDict.Reset(NewIndirect<CPDF_Dictionary>());
+ DCHECK(!m_pRootDict);
+ DCHECK(!m_pInfoDict);
+ m_pRootDict = NewIndirect<CPDF_Dictionary>();
m_pRootDict->SetNewFor<CPDF_Name>("Type", "Catalog");
- CPDF_Dictionary* pPages = NewIndirect<CPDF_Dictionary>();
+ auto pPages = NewIndirect<CPDF_Dictionary>();
pPages->SetNewFor<CPDF_Name>("Type", "Pages");
pPages->SetNewFor<CPDF_Number>("Count", 0);
pPages->SetNewFor<CPDF_Array>("Kids");
m_pRootDict->SetNewFor<CPDF_Reference>("Pages", this, pPages->GetObjNum());
- m_pInfoDict.Reset(NewIndirect<CPDF_Dictionary>());
+ m_pInfoDict = NewIndirect<CPDF_Dictionary>();
}
-CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) {
- CPDF_Dictionary* pDict = NewIndirect<CPDF_Dictionary>();
+RetainPtr<CPDF_Dictionary> CPDF_Document::CreateNewPage(int iPage) {
+ auto pDict = NewIndirect<CPDF_Dictionary>();
pDict->SetNewFor<CPDF_Name>("Type", "Page");
uint32_t dwObjNum = pDict->GetObjNum();
if (!InsertNewPage(iPage, pDict)) {
@@ -370,18 +444,19 @@ CPDF_Dictionary* CPDF_Document::CreateNewPage(int iPage) {
return pDict;
}
-bool CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages,
- int nPagesToGo,
- CPDF_Dictionary* pPageDict,
- bool bInsert,
- std::set<CPDF_Dictionary*>* pVisited) {
- CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
+bool CPDF_Document::InsertDeletePDFPage(
+ RetainPtr<CPDF_Dictionary> pPages,
+ int nPagesToGo,
+ RetainPtr<CPDF_Dictionary> pPageDict,
+ bool bInsert,
+ std::set<RetainPtr<CPDF_Dictionary>>* pVisited) {
+ RetainPtr<CPDF_Array> pKidList = pPages->GetMutableArrayFor("Kids");
if (!pKidList)
return false;
for (size_t i = 0; i < pKidList->size(); i++) {
- CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
- if (pKid->GetStringFor("Type") == "Page") {
+ RetainPtr<CPDF_Dictionary> pKid = pKidList->GetMutableDictAt(i);
+ if (pKid->GetNameFor("Type") == "Page") {
if (nPagesToGo != 0) {
nPagesToGo--;
continue;
@@ -403,13 +478,14 @@ bool CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages,
nPagesToGo -= nPages;
continue;
}
- if (pdfium::ContainsKey(*pVisited, pKid))
+ if (pdfium::Contains(*pVisited, pKid))
return false;
- pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid);
- if (!InsertDeletePDFPage(pKid, nPagesToGo, pPageDict, bInsert, pVisited))
+ ScopedSetInsertion<RetainPtr<CPDF_Dictionary>> insertion(pVisited, pKid);
+ if (!InsertDeletePDFPage(std::move(pKid), nPagesToGo, pPageDict, bInsert,
+ pVisited)) {
return false;
-
+ }
pPages->SetNewFor<CPDF_Number>(
"Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
break;
@@ -417,9 +493,13 @@ bool CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages,
return true;
}
-bool CPDF_Document::InsertNewPage(int iPage, CPDF_Dictionary* pPageDict) {
- CPDF_Dictionary* pRoot = GetRoot();
- CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr;
+bool CPDF_Document::InsertNewPage(int iPage,
+ RetainPtr<CPDF_Dictionary> pPageDict) {
+ RetainPtr<CPDF_Dictionary> pRoot = GetMutableRoot();
+ if (!pRoot)
+ return false;
+
+ RetainPtr<CPDF_Dictionary> pPages = pRoot->GetMutableDictFor("Pages");
if (!pPages)
return false;
@@ -428,37 +508,42 @@ bool CPDF_Document::InsertNewPage(int iPage, CPDF_Dictionary* pPageDict) {
return false;
if (iPage == nPages) {
- CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
- if (!pPagesList)
- pPagesList = pPages->SetNewFor<CPDF_Array>("Kids");
- pPagesList->AddNew<CPDF_Reference>(this, pPageDict->GetObjNum());
+ RetainPtr<CPDF_Array> pPagesList = pPages->GetOrCreateArrayFor("Kids");
+ pPagesList->AppendNew<CPDF_Reference>(this, pPageDict->GetObjNum());
pPages->SetNewFor<CPDF_Number>("Count", nPages + 1);
pPageDict->SetNewFor<CPDF_Reference>("Parent", this, pPages->GetObjNum());
ResetTraversal();
} else {
- std::set<CPDF_Dictionary*> stack = {pPages};
- if (!InsertDeletePDFPage(pPages, iPage, pPageDict, true, &stack))
+ std::set<RetainPtr<CPDF_Dictionary>> stack = {pPages};
+ if (!InsertDeletePDFPage(std::move(pPages), iPage, pPageDict, true, &stack))
return false;
}
m_PageList.insert(m_PageList.begin() + iPage, pPageDict->GetObjNum());
return true;
}
-CPDF_Dictionary* CPDF_Document::GetInfo() {
+RetainPtr<CPDF_Dictionary> CPDF_Document::GetInfo() {
if (m_pInfoDict)
- return m_pInfoDict.Get();
+ return m_pInfoDict;
+
+ if (!m_pParser)
+ return nullptr;
- if (!m_pParser || !m_pParser->GetInfoObjNum())
+ uint32_t info_obj_num = m_pParser->GetInfoObjNum();
+ if (info_obj_num == 0)
return nullptr;
- auto ref =
- pdfium::MakeRetain<CPDF_Reference>(this, m_pParser->GetInfoObjNum());
- m_pInfoDict.Reset(ToDictionary(ref->GetDirect()));
- return m_pInfoDict.Get();
+ auto ref = pdfium::MakeRetain<CPDF_Reference>(this, info_obj_num);
+ m_pInfoDict = ToDictionary(ref->GetMutableDirect());
+ return m_pInfoDict;
+}
+
+RetainPtr<const CPDF_Array> CPDF_Document::GetFileIdentifier() const {
+ return m_pParser ? m_pParser->GetIDArray() : nullptr;
}
void CPDF_Document::DeletePage(int iPage) {
- CPDF_Dictionary* pPages = GetPagesDict();
+ RetainPtr<CPDF_Dictionary> pPages = GetMutablePagesDict();
if (!pPages)
return;
@@ -466,13 +551,21 @@ void CPDF_Document::DeletePage(int iPage) {
if (iPage < 0 || iPage >= nPages)
return;
- std::set<CPDF_Dictionary*> stack = {pPages};
- if (!InsertDeletePDFPage(pPages, iPage, nullptr, false, &stack))
+ std::set<RetainPtr<CPDF_Dictionary>> stack = {pPages};
+ if (!InsertDeletePDFPage(std::move(pPages), iPage, nullptr, false, &stack))
return;
m_PageList.erase(m_PageList.begin() + iPage);
}
+void CPDF_Document::SetRootForTesting(RetainPtr<CPDF_Dictionary> root) {
+ m_pRootDict = std::move(root);
+}
+
+void CPDF_Document::ResizePageListForTesting(size_t size) {
+ m_PageList.resize(size);
+}
+
CPDF_Document::StockFontClearer::StockFontClearer(
CPDF_Document::PageDataIface* pPageData)
: m_pPageData(pPageData) {}