diff options
Diffstat (limited to 'core/fpdfapi/parser/cpdf_document.cpp')
-rw-r--r-- | core/fpdfapi/parser/cpdf_document.cpp | 385 |
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) {} |