Index: core/fpdfdoc/cpdf_nametree.cpp |
diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e046b6bf1a6c6e308c0155bc1137eecabbf0eb90 |
--- /dev/null |
+++ b/core/fpdfdoc/cpdf_nametree.cpp |
@@ -0,0 +1,198 @@ |
+// Copyright 2016 PDFium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
+ |
+#include "core/fpdfdoc/include/cpdf_nametree.h" |
+ |
+#include "core/fpdfapi/fpdf_parser/include/cpdf_array.h" |
+#include "core/fpdfapi/fpdf_parser/include/cpdf_dictionary.h" |
+#include "core/fpdfapi/fpdf_parser/include/cpdf_document.h" |
+ |
+namespace { |
+ |
+const int nMaxRecursion = 32; |
+ |
+CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, |
+ const CFX_ByteString& csName, |
+ size_t& nIndex, |
+ CPDF_Array** ppFind, |
+ int nLevel = 0) { |
+ if (nLevel > nMaxRecursion) |
+ return nullptr; |
+ |
+ CPDF_Array* pLimits = pNode->GetArrayBy("Limits"); |
+ if (pLimits) { |
+ CFX_ByteString csLeft = pLimits->GetStringAt(0); |
+ CFX_ByteString csRight = pLimits->GetStringAt(1); |
+ if (csLeft.Compare(csRight.AsStringC()) > 0) { |
+ CFX_ByteString csTmp = csRight; |
+ csRight = csLeft; |
+ csLeft = csTmp; |
+ } |
+ if (csName.Compare(csLeft.AsStringC()) < 0 || |
+ csName.Compare(csRight.AsStringC()) > 0) { |
+ return nullptr; |
+ } |
+ } |
+ |
+ CPDF_Array* pNames = pNode->GetArrayBy("Names"); |
+ if (pNames) { |
+ size_t dwCount = pNames->GetCount() / 2; |
+ for (size_t i = 0; i < dwCount; i++) { |
+ CFX_ByteString csValue = pNames->GetStringAt(i * 2); |
+ int32_t iCompare = csValue.Compare(csName.AsStringC()); |
+ if (iCompare <= 0) { |
+ if (ppFind) |
+ *ppFind = pNames; |
+ if (iCompare < 0) |
+ continue; |
+ } else { |
+ break; |
+ } |
+ nIndex += i; |
+ return pNames->GetDirectObjectAt(i * 2 + 1); |
+ } |
+ nIndex += dwCount; |
+ return nullptr; |
+ } |
+ |
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids"); |
+ if (!pKids) |
+ return nullptr; |
+ |
+ for (size_t i = 0; i < pKids->GetCount(); i++) { |
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i); |
+ if (!pKid) |
+ continue; |
+ |
+ CPDF_Object* pFound = |
+ SearchNameNode(pKid, csName, nIndex, ppFind, nLevel + 1); |
+ if (pFound) |
+ return pFound; |
+ } |
+ return nullptr; |
+} |
+ |
+CPDF_Object* SearchNameNode(CPDF_Dictionary* pNode, |
+ size_t nIndex, |
+ size_t& nCurIndex, |
+ CFX_ByteString& csName, |
+ CPDF_Array** ppFind, |
+ int nLevel = 0) { |
+ if (nLevel > nMaxRecursion) |
+ return nullptr; |
+ |
+ CPDF_Array* pNames = pNode->GetArrayBy("Names"); |
+ if (pNames) { |
+ size_t nCount = pNames->GetCount() / 2; |
+ if (nIndex >= nCurIndex + nCount) { |
+ nCurIndex += nCount; |
+ return nullptr; |
+ } |
+ if (ppFind) |
+ *ppFind = pNames; |
+ csName = pNames->GetStringAt((nIndex - nCurIndex) * 2); |
+ return pNames->GetDirectObjectAt((nIndex - nCurIndex) * 2 + 1); |
+ } |
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids"); |
+ if (!pKids) |
+ return nullptr; |
+ for (size_t i = 0; i < pKids->GetCount(); i++) { |
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i); |
+ if (!pKid) |
+ continue; |
+ CPDF_Object* pFound = |
+ SearchNameNode(pKid, nIndex, nCurIndex, csName, ppFind, nLevel + 1); |
+ if (pFound) |
+ return pFound; |
+ } |
+ return nullptr; |
+} |
+ |
+size_t CountNames(CPDF_Dictionary* pNode, int nLevel = 0) { |
+ if (nLevel > nMaxRecursion) |
+ return 0; |
+ |
+ CPDF_Array* pNames = pNode->GetArrayBy("Names"); |
+ if (pNames) |
+ return pNames->GetCount() / 2; |
+ |
+ CPDF_Array* pKids = pNode->GetArrayBy("Kids"); |
+ if (!pKids) |
+ return 0; |
+ |
+ size_t nCount = 0; |
+ for (size_t i = 0; i < pKids->GetCount(); i++) { |
+ CPDF_Dictionary* pKid = pKids->GetDictAt(i); |
+ if (!pKid) |
+ continue; |
+ |
+ nCount += CountNames(pKid, nLevel + 1); |
+ } |
+ return nCount; |
+} |
+ |
+} // namespace |
+ |
+CPDF_NameTree::CPDF_NameTree(CPDF_Document* pDoc, |
+ const CFX_ByteString& category) |
+ : m_pRoot(nullptr) { |
+ CPDF_Dictionary* pRoot = pDoc->GetRoot(); |
+ if (!pRoot) |
+ return; |
+ |
+ CPDF_Dictionary* pNames = pRoot->GetDictBy("Names"); |
+ if (!pNames) |
+ return; |
+ |
+ m_pRoot = pNames->GetDictBy(category); |
+} |
+ |
+size_t CPDF_NameTree::GetCount() const { |
+ return m_pRoot ? ::CountNames(m_pRoot) : 0; |
+} |
+ |
+int CPDF_NameTree::GetIndex(const CFX_ByteString& csName) const { |
+ if (!m_pRoot) |
+ return -1; |
+ |
+ size_t nIndex = 0; |
+ if (!SearchNameNode(m_pRoot, csName, nIndex, nullptr)) |
+ return -1; |
+ return nIndex; |
+} |
+ |
+CPDF_Object* CPDF_NameTree::LookupValue(int nIndex, |
+ CFX_ByteString& csName) const { |
+ if (!m_pRoot) |
+ return nullptr; |
+ size_t nCurIndex = 0; |
+ return SearchNameNode(m_pRoot, nIndex, nCurIndex, csName, nullptr); |
+} |
+ |
+CPDF_Object* CPDF_NameTree::LookupValue(const CFX_ByteString& csName) const { |
+ if (!m_pRoot) |
+ return nullptr; |
+ size_t nIndex = 0; |
+ return SearchNameNode(m_pRoot, csName, nIndex, nullptr); |
+} |
+ |
+CPDF_Array* CPDF_NameTree::LookupNamedDest(CPDF_Document* pDoc, |
+ const CFX_ByteString& sName) { |
+ CPDF_Object* pValue = LookupValue(sName); |
+ if (!pValue) { |
+ CPDF_Dictionary* pDests = pDoc->GetRoot()->GetDictBy("Dests"); |
+ if (!pDests) |
+ return nullptr; |
+ pValue = pDests->GetDirectObjectBy(sName); |
+ } |
+ if (!pValue) |
+ return nullptr; |
+ if (CPDF_Array* pArray = pValue->AsArray()) |
+ return pArray; |
+ if (CPDF_Dictionary* pDict = pValue->AsDictionary()) |
+ return pDict->GetArrayBy("D"); |
+ return nullptr; |
+} |