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 {