Fix unnecessary tree traversal in SearchNameNodeByNameInternal()
When SearchNameNodeByNameInternal() is searching the name tree for
`csName`, it encounters nodes with limits, designating a range of what
possible values can be found in its subtree. Logically, when one is
searching for `csName`, and encounters a node where `csName` is greater
than the node's greatest limit, that subtree should be skipped, and the
next sibling node (if it exists) should be processed instead. This was
the behavior prior to https://pdfium-review.googlesource.com/8271, but
that CL introduced a regression where the subtree still gets traversed
anyway. This behavior might make sense when trying to add to the name
tree, where there needs to be some tree balancing, but it is unnecessary
when only searching the tree, leading to slow performance for PDFs with
large name trees.
Fix this behavior by skipping the subtree when only trying to search for
`csName`.
Bug: 372523840
Change-Id: I805e0a32fbd6ffdbece6f831f1be6d3a977587fc
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/128231
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Andy Phan <andyphan@chromium.org>
diff --git a/core/fpdfdoc/cpdf_nametree.cpp b/core/fpdfdoc/cpdf_nametree.cpp
index adfb890..48157a9 100644
--- a/core/fpdfdoc/cpdf_nametree.cpp
+++ b/core/fpdfdoc/cpdf_nametree.cpp
@@ -221,17 +221,24 @@
if (pLimits) {
auto [csLeft, csRight] = GetNodeLimitsAndSanitize(pLimits.Get());
// Skip this node if the name to look for is smaller than its lower limit.
- if (csName.Compare(csLeft) < 0)
+ if (csName.Compare(csLeft) < 0) {
return nullptr;
+ }
- // Skip this node if the name to look for is greater than its higher limit,
- // and the node itself is a leaf node.
- if (csName.Compare(csRight) > 0 && pNames) {
- if (node_to_insert) {
+ if (csName.Compare(csRight) > 0) {
+ // If only trying to find the name node, and not where the name should be
+ // added, skip this node.
+ if (!node_to_insert) {
+ return nullptr;
+ }
+
+ // If the node itself is a leaf node, set `pNames` as the array `csName`
+ // should be added to.
+ if (pNames) {
node_to_insert->names = pNames;
node_to_insert->index = fxcrt::CollectionSize<int32_t>(*pNames) / 2 - 1;
+ return nullptr;
}
- return nullptr;
}
}