| Index: core/fpdfapi/parser/cpdf_document.cpp
|
| diff --git a/core/fpdfapi/parser/cpdf_document.cpp b/core/fpdfapi/parser/cpdf_document.cpp
|
| index ba20ff622395b76e3d1a1321cb5febabb862b92a..c5f64a790ca1d31f6cb4357f5a01b18d6b0585e1 100644
|
| --- a/core/fpdfapi/parser/cpdf_document.cpp
|
| +++ b/core/fpdfapi/parser/cpdf_document.cpp
|
| @@ -8,7 +8,6 @@
|
|
|
| #include <memory>
|
| #include <set>
|
| -#include <utility>
|
| #include <vector>
|
|
|
| #include "core/fpdfapi/cpdf_modulemgr.h"
|
| @@ -241,6 +240,83 @@
|
| InsertWidthArrayImpl(widths, size, pWidthArray);
|
| }
|
|
|
| +int InsertDeletePDFPage(CPDF_Document* pDoc,
|
| + CPDF_Dictionary* pPages,
|
| + int nPagesToGo,
|
| + CPDF_Dictionary* pPage,
|
| + FX_BOOL bInsert,
|
| + std::set<CPDF_Dictionary*>* pVisited) {
|
| + CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
|
| + if (!pKidList)
|
| + return -1;
|
| +
|
| + for (size_t i = 0; i < pKidList->GetCount(); i++) {
|
| + CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
|
| + if (pKid->GetStringFor("Type") == "Page") {
|
| + if (nPagesToGo == 0) {
|
| + if (bInsert) {
|
| + pKidList->InsertAt(i, new CPDF_Reference(pDoc, pPage->GetObjNum()));
|
| + pPage->SetReferenceFor("Parent", pDoc, pPages->GetObjNum());
|
| + } else {
|
| + pKidList->RemoveAt(i);
|
| + }
|
| + pPages->SetIntegerFor(
|
| + "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
|
| + return 1;
|
| + }
|
| + nPagesToGo--;
|
| + } else {
|
| + int nPages = pKid->GetIntegerFor("Count");
|
| + if (nPagesToGo < nPages) {
|
| + if (pdfium::ContainsKey(*pVisited, pKid))
|
| + return -1;
|
| +
|
| + pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid);
|
| + if (InsertDeletePDFPage(pDoc, pKid, nPagesToGo, pPage, bInsert,
|
| + pVisited) < 0) {
|
| + return -1;
|
| + }
|
| + pPages->SetIntegerFor(
|
| + "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
|
| + return 1;
|
| + }
|
| + nPagesToGo -= nPages;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +int InsertNewPage(CPDF_Document* pDoc,
|
| + int iPage,
|
| + CPDF_Dictionary* pPageDict,
|
| + CFX_ArrayTemplate<uint32_t>& pageList) {
|
| + CPDF_Dictionary* pRoot = pDoc->GetRoot();
|
| + CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr;
|
| + if (!pPages)
|
| + return -1;
|
| +
|
| + int nPages = pDoc->GetPageCount();
|
| + if (iPage < 0 || iPage > nPages)
|
| + return -1;
|
| +
|
| + if (iPage == nPages) {
|
| + CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
|
| + if (!pPagesList) {
|
| + pPagesList = new CPDF_Array;
|
| + pPages->SetFor("Kids", pPagesList);
|
| + }
|
| + pPagesList->Add(new CPDF_Reference(pDoc, pPageDict->GetObjNum()));
|
| + pPages->SetIntegerFor("Count", nPages + 1);
|
| + pPageDict->SetReferenceFor("Parent", pDoc, pPages->GetObjNum());
|
| + } else {
|
| + std::set<CPDF_Dictionary*> stack = {pPages};
|
| + if (InsertDeletePDFPage(pDoc, pPages, iPage, pPageDict, TRUE, &stack) < 0)
|
| + return -1;
|
| + }
|
| + pageList.InsertAt(iPage, pPageDict->GetObjNum());
|
| + return iPage;
|
| +}
|
| +
|
| int CountPages(CPDF_Dictionary* pPages,
|
| std::set<CPDF_Dictionary*>* visited_pages) {
|
| int count = pPages->GetIntegerFor("Count");
|
| @@ -337,7 +413,6 @@
|
| m_pParser(std::move(pParser)),
|
| m_pRootDict(nullptr),
|
| m_pInfoDict(nullptr),
|
| - m_iLastPageTraversed(-1),
|
| m_bLinearized(false),
|
| m_iFirstPageNo(0),
|
| m_dwFirstPageObjNum(0),
|
| @@ -402,63 +477,40 @@
|
| m_PageList.SetSize(RetrievePageCount());
|
| }
|
|
|
| -CPDF_Dictionary* CPDF_Document::TraversePDFPages(int iPage, int nPagesToGo) {
|
| - std::pair<CPDF_Dictionary*, int>* lastProc = &m_pTreeTraversal.top();
|
| - CPDF_Dictionary* pPages = lastProc->first;
|
| +CPDF_Dictionary* CPDF_Document::FindPDFPage(CPDF_Dictionary* pPages,
|
| + int iPage,
|
| + int nPagesToGo,
|
| + int level) {
|
| CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
|
| - if (!pKidList) {
|
| - m_pTreeTraversal.pop();
|
| - if (nPagesToGo != 1)
|
| - return nullptr;
|
| - m_PageList.SetAt(iPage, pPages->GetObjNum());
|
| - return pPages;
|
| - }
|
| -
|
| - if (m_pTreeTraversal.size() >= FX_MAX_PAGE_LEVEL) {
|
| - m_pTreeTraversal.pop();
|
| + if (!pKidList)
|
| + return nPagesToGo == 0 ? pPages : nullptr;
|
| +
|
| + if (level >= FX_MAX_PAGE_LEVEL)
|
| return nullptr;
|
| - }
|
| -
|
| - bool shouldFinish = pPages->GetIntegerFor("Count") <= nPagesToGo;
|
| - CPDF_Dictionary* page = nullptr;
|
| - for (size_t i = lastProc->second + 1; i < pKidList->GetCount(); i++) {
|
| +
|
| + for (size_t i = 0; i < pKidList->GetCount(); i++) {
|
| CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
|
| if (!pKid) {
|
| nPagesToGo--;
|
| - lastProc->second++;
|
| continue;
|
| }
|
| - if (pKid == pPages) {
|
| - lastProc->second++;
|
| + if (pKid == pPages)
|
| continue;
|
| - }
|
| if (!pKid->KeyExist("Kids")) {
|
| - m_PageList.SetAt(iPage - nPagesToGo + 1, pKid->GetObjNum());
|
| + if (nPagesToGo == 0)
|
| + return pKid;
|
| +
|
| + m_PageList.SetAt(iPage - nPagesToGo, pKid->GetObjNum());
|
| nPagesToGo--;
|
| - lastProc->second++;
|
| - if (nPagesToGo == 0) {
|
| - page = pKid;
|
| - break;
|
| - }
|
| } else {
|
| int nPages = pKid->GetIntegerFor("Count");
|
| - m_pTreeTraversal.push(std::make_pair(pKid, -1));
|
| - CPDF_Dictionary* pageKid = TraversePDFPages(iPage, nPagesToGo);
|
| - // If the stack top is current element, kid was completely processed.
|
| - if (lastProc == &m_pTreeTraversal.top())
|
| - lastProc->second++;
|
| - if (nPagesToGo <= nPages) {
|
| - page = pageKid;
|
| - break;
|
| - }
|
| + if (nPagesToGo < nPages)
|
| + return FindPDFPage(pKid, iPage, nPagesToGo, level + 1);
|
| +
|
| nPagesToGo -= nPages;
|
| }
|
| }
|
| - if (shouldFinish ||
|
| - lastProc->second == static_cast<int>(pKidList->GetCount() - 1)) {
|
| - m_pTreeTraversal.pop();
|
| - }
|
| - return page;
|
| + return nullptr;
|
| }
|
|
|
| CPDF_Dictionary* CPDF_Document::GetPagesDict() const {
|
| @@ -482,20 +534,21 @@
|
| }
|
|
|
| int objnum = m_PageList.GetAt(iPage);
|
| - if (!objnum || m_iLastPageTraversed < iPage) {
|
| - CPDF_Dictionary* pPages = GetPagesDict();
|
| - if (!pPages)
|
| - return nullptr;
|
| - if (m_pTreeTraversal.empty())
|
| - m_pTreeTraversal.push(std::make_pair(pPages, -1));
|
| - CPDF_Dictionary* page = TraversePDFPages(m_iLastPageTraversed + 1,
|
| - iPage - m_iLastPageTraversed);
|
| - m_iLastPageTraversed = iPage;
|
| - return page;
|
| - }
|
| - if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum)))
|
| - return pDict;
|
| - return nullptr;
|
| + if (objnum) {
|
| + if (CPDF_Dictionary* pDict = ToDictionary(GetOrParseIndirectObject(objnum)))
|
| + return pDict;
|
| + }
|
| +
|
| + CPDF_Dictionary* pPages = GetPagesDict();
|
| + if (!pPages)
|
| + return nullptr;
|
| +
|
| + CPDF_Dictionary* pPage = FindPDFPage(pPages, iPage, iPage, 0);
|
| + if (!pPage)
|
| + return nullptr;
|
| +
|
| + m_PageList.SetAt(iPage, pPage->GetObjNum());
|
| + return pPage;
|
| }
|
|
|
| void CPDF_Document::SetPageObjNum(int iPage, uint32_t objNum) {
|
| @@ -657,89 +710,11 @@
|
| CPDF_Dictionary* pDict = new CPDF_Dictionary(m_pByteStringPool);
|
| pDict->SetNameFor("Type", "Page");
|
| uint32_t dwObjNum = AddIndirectObject(pDict);
|
| - if (InsertNewPage(iPage, pDict, m_PageList) < 0) {
|
| + if (InsertNewPage(this, iPage, pDict, m_PageList) < 0) {
|
| ReleaseIndirectObject(dwObjNum);
|
| return nullptr;
|
| }
|
| return pDict;
|
| -}
|
| -
|
| -int CPDF_Document::InsertDeletePDFPage(CPDF_Dictionary* pPages,
|
| - int nPagesToGo,
|
| - CPDF_Dictionary* pPage,
|
| - FX_BOOL bInsert,
|
| - std::set<CPDF_Dictionary*>* pVisited) {
|
| - CPDF_Array* pKidList = pPages->GetArrayFor("Kids");
|
| - if (!pKidList)
|
| - return -1;
|
| -
|
| - for (size_t i = 0; i < pKidList->GetCount(); i++) {
|
| - CPDF_Dictionary* pKid = pKidList->GetDictAt(i);
|
| - if (pKid->GetStringFor("Type") == "Page") {
|
| - if (nPagesToGo == 0) {
|
| - if (bInsert) {
|
| - pKidList->InsertAt(i, new CPDF_Reference(this, pPage->GetObjNum()));
|
| - pPage->SetReferenceFor("Parent", this, pPages->GetObjNum());
|
| - } else {
|
| - pKidList->RemoveAt(i);
|
| - }
|
| - pPages->SetIntegerFor(
|
| - "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
|
| - // Tree will change, so reset tree transversal variables
|
| - m_iLastPageTraversed = -1;
|
| - m_pTreeTraversal = std::stack<std::pair<CPDF_Dictionary*, int>>();
|
| - return 1;
|
| - }
|
| - nPagesToGo--;
|
| - } else {
|
| - int nPages = pKid->GetIntegerFor("Count");
|
| - if (nPagesToGo < nPages) {
|
| - if (pdfium::ContainsKey(*pVisited, pKid))
|
| - return -1;
|
| -
|
| - pdfium::ScopedSetInsertion<CPDF_Dictionary*> insertion(pVisited, pKid);
|
| - if (InsertDeletePDFPage(pKid, nPagesToGo, pPage, bInsert, pVisited) <
|
| - 0) {
|
| - return -1;
|
| - }
|
| - pPages->SetIntegerFor(
|
| - "Count", pPages->GetIntegerFor("Count") + (bInsert ? 1 : -1));
|
| - return 1;
|
| - }
|
| - nPagesToGo -= nPages;
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -int CPDF_Document::InsertNewPage(int iPage,
|
| - CPDF_Dictionary* pPageDict,
|
| - CFX_ArrayTemplate<uint32_t>& pageList) {
|
| - CPDF_Dictionary* pRoot = GetRoot();
|
| - CPDF_Dictionary* pPages = pRoot ? pRoot->GetDictFor("Pages") : nullptr;
|
| - if (!pPages)
|
| - return -1;
|
| -
|
| - int nPages = GetPageCount();
|
| - if (iPage < 0 || iPage > nPages)
|
| - return -1;
|
| -
|
| - if (iPage == nPages) {
|
| - CPDF_Array* pPagesList = pPages->GetArrayFor("Kids");
|
| - if (!pPagesList) {
|
| - pPagesList = new CPDF_Array;
|
| - pPages->SetFor("Kids", pPagesList);
|
| - }
|
| - pPagesList->Add(new CPDF_Reference(this, pPageDict->GetObjNum()));
|
| - pPages->SetIntegerFor("Count", nPages + 1);
|
| - pPageDict->SetReferenceFor("Parent", this, pPages->GetObjNum());
|
| - } else {
|
| - std::set<CPDF_Dictionary*> stack = {pPages};
|
| - if (InsertDeletePDFPage(pPages, iPage, pPageDict, TRUE, &stack) < 0)
|
| - return -1;
|
| - }
|
| - pageList.InsertAt(iPage, pPageDict->GetObjNum());
|
| - return iPage;
|
| }
|
|
|
| void CPDF_Document::DeletePage(int iPage) {
|
| @@ -752,7 +727,7 @@
|
| return;
|
|
|
| std::set<CPDF_Dictionary*> stack = {pPages};
|
| - if (InsertDeletePDFPage(pPages, iPage, nullptr, FALSE, &stack) < 0)
|
| + if (InsertDeletePDFPage(this, pPages, iPage, nullptr, FALSE, &stack) < 0)
|
| return;
|
|
|
| m_PageList.RemoveAt(iPage);
|
|
|