Change SearchNameNodeByIndex() to return an optional struct.
Do the same for SearchNameNodeByIndexImpl() and get rid of many
out-parameters.
Change-Id: I1af2a055844ae88c5598053d9c100e4ea8a513cf
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/86936
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp
index ab5d59c..fce1fae 100644
--- a/core/fpdfdoc/cpdf_nametree.cpp
+++ b/core/fpdfdoc/cpdf_nametree.cpp
@@ -239,62 +239,70 @@
return nullptr;
}
-// Get the key-value pair at |nIndex| in the tree with root |pNode|. If
-// successful, return the value object; |csName| will be the key, |ppFind|
-// will be the leaf array that this pair is in, and |pFindIndex| will be the
-// index of the pair in |pFind|.
-CPDF_Object* SearchNameNodeByIndexInternal(CPDF_Dictionary* pNode,
- size_t nIndex,
- int nLevel,
- size_t* nCurIndex,
- WideString* csName,
- CPDF_Array** ppFind,
- int* pFindIndex) {
+struct IndexSearchResult {
+ // For the n-th object in a tree, the key and value.
+ WideString key;
+ CPDF_Object* value;
+ // The leaf node that holds `key` and `value`.
+ CPDF_Array* container;
+ // The pair index for `key` and `value` in `container`.
+ // Note that a value of 3 means `key` is at index 6 and `value` is at index 7.
+ int pair_index;
+};
+
+// Find the `nIndex` node in the tree with root `pNode`. `nLevel` tracks the
+// recursion level and `nCurIndex` tracks the progress towards `nIndex`.
+absl::optional<IndexSearchResult> SearchNameNodeByIndexInternal(
+ CPDF_Dictionary* pNode,
+ size_t nIndex,
+ int nLevel,
+ size_t* nCurIndex) {
if (nLevel > kNameTreeMaxRecursion)
- return nullptr;
+ return absl::nullopt;
CPDF_Array* pNames = pNode->GetArrayFor("Names");
if (pNames) {
size_t nCount = pNames->size() / 2;
if (nIndex >= *nCurIndex + nCount) {
*nCurIndex += nCount;
- return nullptr;
+ return absl::nullopt;
}
- if (ppFind)
- *ppFind = pNames;
- if (pFindIndex)
- *pFindIndex = nIndex - *nCurIndex;
- *csName = pNames->GetUnicodeTextAt((nIndex - *nCurIndex) * 2);
- return pNames->GetDirectObjectAt((nIndex - *nCurIndex) * 2 + 1);
+ int pair_index = nIndex - *nCurIndex;
+ CPDF_Object* value = pNames->GetDirectObjectAt(pair_index * 2 + 1);
+ if (!value)
+ return absl::nullopt;
+
+ IndexSearchResult result;
+ result.key = pNames->GetUnicodeTextAt(pair_index * 2);
+ result.value = value;
+ result.container = pNames;
+ result.pair_index = pair_index;
+ return result;
}
CPDF_Array* pKids = pNode->GetArrayFor("Kids");
if (!pKids)
- return nullptr;
+ return absl::nullopt;
for (size_t i = 0; i < pKids->size(); i++) {
CPDF_Dictionary* pKid = pKids->GetDictAt(i);
if (!pKid)
continue;
- CPDF_Object* pFound = SearchNameNodeByIndexInternal(
- pKid, nIndex, nLevel + 1, nCurIndex, csName, ppFind, pFindIndex);
- if (pFound)
- return pFound;
+ absl::optional<IndexSearchResult> result =
+ SearchNameNodeByIndexInternal(pKid, nIndex, nLevel + 1, nCurIndex);
+ if (result.has_value())
+ return result;
}
- return nullptr;
+ return absl::nullopt;
}
// Wrapper for SearchNameNodeByIndexInternal() so callers do not need to know
// about the details.
-CPDF_Object* SearchNameNodeByIndex(CPDF_Dictionary* pNode,
- size_t nIndex,
- WideString* csName,
- CPDF_Array** ppFind,
- int* pFindIndex) {
+absl::optional<IndexSearchResult> SearchNameNodeByIndex(CPDF_Dictionary* pNode,
+ size_t nIndex) {
size_t nCurIndex = 0;
- return SearchNameNodeByIndexInternal(pNode, nIndex, 0, &nCurIndex, csName,
- ppFind, pFindIndex);
+ return SearchNameNodeByIndexInternal(pNode, nIndex, 0, &nCurIndex);
}
// Get the total number of key-value pairs in the tree with root |pNode|.
@@ -440,12 +448,16 @@
// |name| into. We instead will find the leftmost leaf array in which to place
// |name| and |pObj|.
if (!pFind) {
- WideString csName;
- SearchNameNodeByIndex(m_pRoot.Get(), 0, &csName, &pFind, nullptr);
+ absl::optional<IndexSearchResult> result =
+ SearchNameNodeByIndex(m_pRoot.Get(), 0);
+ if (!result.has_value()) {
+ // Give up if that fails too.
+ return false;
+ }
+
+ pFind = result.value().container;
+ DCHECK(pFind);
}
- // Give up if that fails too.
- if (!pFind)
- return false;
// Insert the name and the object into the leaf array found. Note that the
// insertion position is right after the key-value pair returned by |index|.
@@ -472,28 +484,34 @@
}
bool CPDF_NameTree::DeleteValueAndName(int nIndex) {
- WideString csName;
- CPDF_Array* pFind = nullptr;
- int nFindIndex = -1;
- // Fail if the tree does not contain |nIndex|.
- if (!SearchNameNodeByIndex(m_pRoot.Get(), nIndex, &csName, &pFind,
- &nFindIndex)) {
+ absl::optional<IndexSearchResult> result =
+ SearchNameNodeByIndex(m_pRoot.Get(), nIndex);
+ if (!result) {
+ // Fail if the tree does not contain |nIndex|.
return false;
}
// Remove the name and the object from the leaf array |pFind|.
- pFind->RemoveAt(nFindIndex * 2);
- pFind->RemoveAt(nFindIndex * 2);
+ CPDF_Array* pFind = result.value().container;
+ pFind->RemoveAt(result.value().pair_index * 2 + 1);
+ pFind->RemoveAt(result.value().pair_index * 2);
// Delete empty nodes and update the limits of |pFind|'s ancestors as needed.
- UpdateNodesAndLimitsUponDeletion(m_pRoot.Get(), pFind, csName, 0);
+ UpdateNodesAndLimitsUponDeletion(m_pRoot.Get(), pFind, result.value().key, 0);
return true;
}
CPDF_Object* CPDF_NameTree::LookupValueAndName(int nIndex,
WideString* csName) const {
- csName->clear();
- return SearchNameNodeByIndex(m_pRoot.Get(), nIndex, csName, nullptr, nullptr);
+ absl::optional<IndexSearchResult> result =
+ SearchNameNodeByIndex(m_pRoot.Get(), nIndex);
+ if (!result) {
+ csName->clear();
+ return nullptr;
+ }
+
+ *csName = std::move(result.value().key);
+ return result.value().value;
}
CPDF_Object* CPDF_NameTree::LookupValue(const WideString& csName) const {