Commit 67796b3ff0c3503a78d45646568c7fae4f545d22
1 parent
5e7b37e1
Refactor `NNTree` implementation to simplify key validation logic
- Removed `NNTreeDetails` and moved key validation logic directly into `NNTreeImpl`. - Replaced type determination with `qpdf_object_type_e` for improved clarity. - Updated `QPDFNameTreeObjectHelper` and `QPDFNumberTreeObjectHelper` to align with the new `NNTreeImpl` structure. - Simplified methods accessing tree items and validating keys.
Showing
4 changed files
with
71 additions
and
114 deletions
libqpdf/NNTree.cc
| @@ -68,7 +68,7 @@ NNTreeIterator::updateIValue(bool allow_invalid) | @@ -68,7 +68,7 @@ NNTreeIterator::updateIValue(bool allow_invalid) | ||
| 68 | ivalue.second = QPDFObjectHandle(); | 68 | ivalue.second = QPDFObjectHandle(); |
| 69 | return; | 69 | return; |
| 70 | } | 70 | } |
| 71 | - Array items = node.getKey(impl.details.itemsKey()); | 71 | + Array items = node.getKey(impl.itemsKey()); |
| 72 | if (!std::cmp_less(item_number + 1, items.size())) { | 72 | if (!std::cmp_less(item_number + 1, items.size())) { |
| 73 | impl.error(node, "update ivalue: items array is too short"); | 73 | impl.error(node, "update ivalue: items array is too short"); |
| 74 | } | 74 | } |
| @@ -91,7 +91,7 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward) | @@ -91,7 +91,7 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward) | ||
| 91 | if (pe.kid_number >= 0 && std::cmp_less(pe.kid_number, kids.size())) { | 91 | if (pe.kid_number >= 0 && std::cmp_less(pe.kid_number, kids.size())) { |
| 92 | auto result = kids[pe.kid_number]; | 92 | auto result = kids[pe.kid_number]; |
| 93 | if (result.isDictionary() && | 93 | if (result.isDictionary() && |
| 94 | - (result.hasKey("/Kids") || result.hasKey(impl.details.itemsKey()))) { | 94 | + (result.hasKey("/Kids") || result.hasKey(impl.itemsKey()))) { |
| 95 | return result; | 95 | return result; |
| 96 | } else { | 96 | } else { |
| 97 | impl.warn( | 97 | impl.warn( |
| @@ -121,7 +121,7 @@ NNTreeIterator::increment(bool backward) | @@ -121,7 +121,7 @@ NNTreeIterator::increment(bool backward) | ||
| 121 | 121 | ||
| 122 | while (valid()) { | 122 | while (valid()) { |
| 123 | item_number += backward ? -2 : 2; | 123 | item_number += backward ? -2 : 2; |
| 124 | - Array items = node.getKey(impl.details.itemsKey()); | 124 | + Array items = node.getKey(impl.itemsKey()); |
| 125 | if (item_number < 0 || std::cmp_greater_equal(item_number, items.size())) { | 125 | if (item_number < 0 || std::cmp_greater_equal(item_number, items.size())) { |
| 126 | bool found = false; | 126 | bool found = false; |
| 127 | setItemNumber(QPDFObjectHandle(), -1); | 127 | setItemNumber(QPDFObjectHandle(), -1); |
| @@ -136,10 +136,10 @@ NNTreeIterator::increment(bool backward) | @@ -136,10 +136,10 @@ NNTreeIterator::increment(bool backward) | ||
| 136 | } | 136 | } |
| 137 | } | 137 | } |
| 138 | if (item_number >= 0) { | 138 | if (item_number >= 0) { |
| 139 | - items = node.getKey(impl.details.itemsKey()); | 139 | + items = node.getKey(impl.itemsKey()); |
| 140 | if (std::cmp_greater_equal(item_number + 1, items.size())) { | 140 | if (std::cmp_greater_equal(item_number + 1, items.size())) { |
| 141 | impl.warn(node, "items array doesn't have enough elements"); | 141 | impl.warn(node, "items array doesn't have enough elements"); |
| 142 | - } else if (!impl.details.keyValid(items[item_number])) { | 142 | + } else if (!impl.keyValid(items[item_number])) { |
| 143 | impl.warn(node, ("item " + std::to_string(item_number) + " has the wrong type")); | 143 | impl.warn(node, ("item " + std::to_string(item_number) + " has the wrong type")); |
| 144 | } else if (!impl.value_valid(items[item_number + 1])) { | 144 | } else if (!impl.value_valid(items[item_number + 1])) { |
| 145 | impl.warn(node, "item " + std::to_string(item_number + 1) + " is invalid"); | 145 | impl.warn(node, "item " + std::to_string(item_number + 1) + " is invalid"); |
| @@ -160,7 +160,7 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite | @@ -160,7 +160,7 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite | ||
| 160 | } | 160 | } |
| 161 | Array kids = a_node.getKey("/Kids"); | 161 | Array kids = a_node.getKey("/Kids"); |
| 162 | size_t nkids = kids.size(); | 162 | size_t nkids = kids.size(); |
| 163 | - Array items = a_node.getKey(impl.details.itemsKey()); | 163 | + Array items = a_node.getKey(impl.itemsKey()); |
| 164 | size_t nitems = items.size(); | 164 | size_t nitems = items.size(); |
| 165 | 165 | ||
| 166 | bool changed = true; | 166 | bool changed = true; |
| @@ -187,9 +187,8 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite | @@ -187,9 +187,8 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite | ||
| 187 | if (olimits.size() == 2) { | 187 | if (olimits.size() == 2) { |
| 188 | auto ofirst = olimits[0]; | 188 | auto ofirst = olimits[0]; |
| 189 | auto olast = olimits[1]; | 189 | auto olast = olimits[1]; |
| 190 | - if (impl.details.keyValid(ofirst) && impl.details.keyValid(olast) && | ||
| 191 | - impl.details.compareKeys(first, ofirst) == 0 && | ||
| 192 | - impl.details.compareKeys(last, olast) == 0) { | 190 | + if (impl.keyValid(ofirst) && impl.keyValid(olast) && |
| 191 | + impl.compareKeys(first, ofirst) == 0 && impl.compareKeys(last, olast) == 0) { | ||
| 193 | changed = false; | 192 | changed = false; |
| 194 | } | 193 | } |
| 195 | } | 194 | } |
| @@ -246,7 +245,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | @@ -246,7 +245,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | ||
| 246 | // Find the array we actually need to split, which is either this node's kids or items. | 245 | // Find the array we actually need to split, which is either this node's kids or items. |
| 247 | Array kids = to_split.getKey("/Kids"); | 246 | Array kids = to_split.getKey("/Kids"); |
| 248 | size_t nkids = kids.size(); | 247 | size_t nkids = kids.size(); |
| 249 | - Array items = to_split.getKey(impl.details.itemsKey()); | 248 | + Array items = to_split.getKey(impl.itemsKey()); |
| 250 | size_t nitems = items.size(); | 249 | size_t nitems = items.size(); |
| 251 | 250 | ||
| 252 | Array first_half; | 251 | Array first_half; |
| @@ -261,7 +260,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | @@ -261,7 +260,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | ||
| 261 | first_half = items; | 260 | first_half = items; |
| 262 | n = nitems; | 261 | n = nitems; |
| 263 | threshold *= 2; | 262 | threshold *= 2; |
| 264 | - key = impl.details.itemsKey(); | 263 | + key = impl.itemsKey(); |
| 265 | } else { | 264 | } else { |
| 266 | throw std::logic_error("NNTreeIterator::split called on invalid node"); | 265 | throw std::logic_error("NNTreeIterator::split called on invalid node"); |
| 267 | } | 266 | } |
| @@ -295,7 +294,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | @@ -295,7 +294,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato | ||
| 295 | Array new_kids; | 294 | Array new_kids; |
| 296 | new_kids.push_back(first_node); | 295 | new_kids.push_back(first_node); |
| 297 | to_split.removeKey("/Limits"); // already shouldn't be there for root | 296 | to_split.removeKey("/Limits"); // already shouldn't be there for root |
| 298 | - to_split.removeKey(impl.details.itemsKey()); | 297 | + to_split.removeKey(impl.itemsKey()); |
| 299 | to_split.replaceKey("/Kids", new_kids); | 298 | to_split.replaceKey("/Kids", new_kids); |
| 300 | if (is_leaf) { | 299 | if (is_leaf) { |
| 301 | node = first_node; | 300 | node = first_node; |
| @@ -375,7 +374,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle const& key, QPDFObjectHandle const& | @@ -375,7 +374,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle const& key, QPDFObjectHandle const& | ||
| 375 | return; | 374 | return; |
| 376 | } | 375 | } |
| 377 | 376 | ||
| 378 | - Array items = node.getKey(impl.details.itemsKey()); | 377 | + Array items = node.getKey(impl.itemsKey()); |
| 379 | if (!items) { | 378 | if (!items) { |
| 380 | impl.error(node, "node contains no items array"); | 379 | impl.error(node, "node contains no items array"); |
| 381 | } | 380 | } |
| @@ -404,7 +403,7 @@ NNTreeIterator::remove() | @@ -404,7 +403,7 @@ NNTreeIterator::remove() | ||
| 404 | if (!valid()) { | 403 | if (!valid()) { |
| 405 | throw std::logic_error("attempt made to remove an invalid iterator"); | 404 | throw std::logic_error("attempt made to remove an invalid iterator"); |
| 406 | } | 405 | } |
| 407 | - Array items = node.getKey(impl.details.itemsKey()); | 406 | + Array items = node.getKey(impl.itemsKey()); |
| 408 | int nitems = static_cast<int>(items.size()); | 407 | int nitems = static_cast<int>(items.size()); |
| 409 | if (std::cmp_greater(item_number + 2, nitems)) { | 408 | if (std::cmp_greater(item_number + 2, nitems)) { |
| 410 | impl.error(node, "found short items array while removing an item"); | 409 | impl.error(node, "found short items array while removing an item"); |
| @@ -478,7 +477,7 @@ NNTreeIterator::remove() | @@ -478,7 +477,7 @@ NNTreeIterator::remove() | ||
| 478 | if (parent == path.end()) { | 477 | if (parent == path.end()) { |
| 479 | // We erased the very last item. Convert the root to an empty items array. | 478 | // We erased the very last item. Convert the root to an empty items array. |
| 480 | element->node.removeKey("/Kids"); | 479 | element->node.removeKey("/Kids"); |
| 481 | - element->node.replaceKey(impl.details.itemsKey(), Array()); | 480 | + element->node.replaceKey(impl.itemsKey(), Array()); |
| 482 | path.clear(); | 481 | path.clear(); |
| 483 | setItemNumber(impl.oh, -1); | 482 | setItemNumber(impl.oh, -1); |
| 484 | return; | 483 | return; |
| @@ -579,7 +578,7 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) | @@ -579,7 +578,7 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) | ||
| 579 | return fail(a_node, "non-dictionary node while traversing name/number tree"); | 578 | return fail(a_node, "non-dictionary node while traversing name/number tree"); |
| 580 | } | 579 | } |
| 581 | 580 | ||
| 582 | - Array items = a_node.getKey(impl.details.itemsKey()); | 581 | + Array items = a_node.getKey(impl.itemsKey()); |
| 583 | int nitems = static_cast<int>(items.size()); | 582 | int nitems = static_cast<int>(items.size()); |
| 584 | if (nitems > 1) { | 583 | if (nitems > 1) { |
| 585 | setItemNumber(a_node, first ? 0 : nitems - 2); | 584 | setItemNumber(a_node, first ? 0 : nitems - 2); |
| @@ -616,22 +615,22 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) | @@ -616,22 +615,22 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) | ||
| 616 | } else { | 615 | } else { |
| 617 | return fail( | 616 | return fail( |
| 618 | a_node, | 617 | a_node, |
| 619 | - "name/number tree node has neither non-empty " + impl.details.itemsKey() + | ||
| 620 | - " nor /Kids"); | 618 | + "name/number tree node has neither non-empty " + impl.itemsKey() + " nor /Kids"); |
| 621 | } | 619 | } |
| 622 | } | 620 | } |
| 623 | return true; | 621 | return true; |
| 624 | } | 622 | } |
| 625 | 623 | ||
| 626 | NNTreeImpl::NNTreeImpl( | 624 | NNTreeImpl::NNTreeImpl( |
| 627 | - NNTreeDetails const& details, | ||
| 628 | QPDF& qpdf, | 625 | QPDF& qpdf, |
| 629 | QPDFObjectHandle& oh, | 626 | QPDFObjectHandle& oh, |
| 627 | + qpdf_object_type_e key_type, | ||
| 630 | std::function<bool(QPDFObjectHandle const&)> value_validator, | 628 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 631 | bool auto_repair) : | 629 | bool auto_repair) : |
| 632 | - details(details), | ||
| 633 | qpdf(qpdf), | 630 | qpdf(qpdf), |
| 634 | oh(oh), | 631 | oh(oh), |
| 632 | + key_type(key_type), | ||
| 633 | + items_key(key_type == ::ot_string ? "/Names" : "/Nums"), | ||
| 635 | value_valid(value_validator), | 634 | value_valid(value_validator), |
| 636 | auto_repair(auto_repair) | 635 | auto_repair(auto_repair) |
| 637 | { | 636 | { |
| @@ -666,16 +665,32 @@ NNTreeImpl::last() | @@ -666,16 +665,32 @@ NNTreeImpl::last() | ||
| 666 | } | 665 | } |
| 667 | 666 | ||
| 668 | int | 667 | int |
| 668 | +NNTreeImpl::compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const | ||
| 669 | +{ | ||
| 670 | + // We don't call this without calling keyValid first | ||
| 671 | + qpdf_assert_debug(keyValid(a)); | ||
| 672 | + qpdf_assert_debug(keyValid(b)); | ||
| 673 | + if (key_type == ::ot_string) { | ||
| 674 | + auto as = a.getUTF8Value(); | ||
| 675 | + auto bs = b.getUTF8Value(); | ||
| 676 | + return as < bs ? -1 : (as > bs ? 1 : 0); | ||
| 677 | + } | ||
| 678 | + auto as = a.getIntValue(); | ||
| 679 | + auto bs = b.getIntValue(); | ||
| 680 | + return as < bs ? -1 : (as > bs ? 1 : 0); | ||
| 681 | +} | ||
| 682 | + | ||
| 683 | +int | ||
| 669 | NNTreeImpl::withinLimits(QPDFObjectHandle const& key, QPDFObjectHandle const& node) | 684 | NNTreeImpl::withinLimits(QPDFObjectHandle const& key, QPDFObjectHandle const& node) |
| 670 | { | 685 | { |
| 671 | Array limits = node.getKey("/Limits"); | 686 | Array limits = node.getKey("/Limits"); |
| 672 | - if (!(details.keyValid(limits[0]) && details.keyValid(limits[1]))) { | 687 | + if (!(keyValid(limits[0]) && keyValid(limits[1]))) { |
| 673 | error(node, "node is missing /Limits"); | 688 | error(node, "node is missing /Limits"); |
| 674 | } | 689 | } |
| 675 | - if (details.compareKeys(key, limits[0]) < 0) { | 690 | + if (compareKeys(key, limits[0]) < 0) { |
| 676 | return -1; | 691 | return -1; |
| 677 | } | 692 | } |
| 678 | - if (details.compareKeys(key, limits[1]) > 0) { | 693 | + if (compareKeys(key, limits[1]) > 0) { |
| 679 | return 1; | 694 | return 1; |
| 680 | } | 695 | } |
| 681 | return 0; | 696 | return 0; |
| @@ -728,10 +743,10 @@ NNTreeImpl::binarySearch( | @@ -728,10 +743,10 @@ NNTreeImpl::binarySearch( | ||
| 728 | int | 743 | int |
| 729 | NNTreeImpl::compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx) | 744 | NNTreeImpl::compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx) |
| 730 | { | 745 | { |
| 731 | - if (!(std::cmp_greater(items.size(), 2 * idx) && details.keyValid(items[2 * idx]))) { | 746 | + if (!(std::cmp_greater(items.size(), 2 * idx) && keyValid(items[2 * idx]))) { |
| 732 | error(oh, ("item at index " + std::to_string(2 * idx) + " is not the right type")); | 747 | error(oh, ("item at index " + std::to_string(2 * idx) + " is not the right type")); |
| 733 | } | 748 | } |
| 734 | - return details.compareKeys(key, items[2 * idx]); | 749 | + return compareKeys(key, items[2 * idx]); |
| 735 | } | 750 | } |
| 736 | 751 | ||
| 737 | int | 752 | int |
| @@ -747,15 +762,15 @@ void | @@ -747,15 +762,15 @@ void | ||
| 747 | NNTreeImpl::repair() | 762 | NNTreeImpl::repair() |
| 748 | { | 763 | { |
| 749 | auto new_node = QPDFObjectHandle::newDictionary(); | 764 | auto new_node = QPDFObjectHandle::newDictionary(); |
| 750 | - new_node.replaceKey(details.itemsKey(), Array()); | ||
| 751 | - NNTreeImpl repl(details, qpdf, new_node, value_valid, false); | 765 | + new_node.replaceKey(itemsKey(), Array()); |
| 766 | + NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); | ||
| 752 | for (auto const& [key, value]: *this) { | 767 | for (auto const& [key, value]: *this) { |
| 753 | if (key && value) { | 768 | if (key && value) { |
| 754 | repl.insert(key, value); | 769 | repl.insert(key, value); |
| 755 | } | 770 | } |
| 756 | } | 771 | } |
| 757 | oh.replaceKey("/Kids", new_node.getKey("/Kids")); | 772 | oh.replaceKey("/Kids", new_node.getKey("/Kids")); |
| 758 | - oh.replaceKey(details.itemsKey(), new_node.getKey(details.itemsKey())); | 773 | + oh.replaceKey(itemsKey(), new_node.getKey(itemsKey())); |
| 759 | } | 774 | } |
| 760 | 775 | ||
| 761 | NNTreeImpl::iterator | 776 | NNTreeImpl::iterator |
| @@ -783,13 +798,13 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | @@ -783,13 +798,13 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | ||
| 783 | return end(); | 798 | return end(); |
| 784 | } | 799 | } |
| 785 | if (first_item.valid()) { | 800 | if (first_item.valid()) { |
| 786 | - if (!details.keyValid(first_item->first)) { | 801 | + if (!keyValid(first_item->first)) { |
| 787 | error(oh, "encountered invalid key in find"); | 802 | error(oh, "encountered invalid key in find"); |
| 788 | } | 803 | } |
| 789 | if (!value_valid(first_item->second)) { | 804 | if (!value_valid(first_item->second)) { |
| 790 | error(oh, "encountered invalid value in find"); | 805 | error(oh, "encountered invalid value in find"); |
| 791 | } | 806 | } |
| 792 | - if (details.compareKeys(key, first_item->first) < 0) { | 807 | + if (compareKeys(key, first_item->first) < 0) { |
| 793 | // Before the first key | 808 | // Before the first key |
| 794 | return end(); | 809 | return end(); |
| 795 | } | 810 | } |
| @@ -805,14 +820,14 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | @@ -805,14 +820,14 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo | ||
| 805 | error(node, "loop detected in find"); | 820 | error(node, "loop detected in find"); |
| 806 | } | 821 | } |
| 807 | 822 | ||
| 808 | - Array items = node.getKey(details.itemsKey()); | 823 | + Array items = node.getKey(itemsKey()); |
| 809 | size_t nitems = items.size(); | 824 | size_t nitems = items.size(); |
| 810 | if (nitems > 1) { | 825 | if (nitems > 1) { |
| 811 | int idx = binarySearch( | 826 | int idx = binarySearch( |
| 812 | key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem); | 827 | key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem); |
| 813 | if (idx >= 0) { | 828 | if (idx >= 0) { |
| 814 | result.setItemNumber(node, 2 * idx); | 829 | result.setItemNumber(node, 2 * idx); |
| 815 | - if (!result.impl.details.keyValid(result.ivalue.first)) { | 830 | + if (!result.impl.keyValid(result.ivalue.first)) { |
| 816 | error(node, "encountered invalid key in find"); | 831 | error(node, "encountered invalid key in find"); |
| 817 | } | 832 | } |
| 818 | if (!result.impl.value_valid(result.ivalue.second)) { | 833 | if (!result.impl.value_valid(result.ivalue.second)) { |
| @@ -843,7 +858,7 @@ NNTreeImpl::insertFirst(QPDFObjectHandle const& key, QPDFObjectHandle const& val | @@ -843,7 +858,7 @@ NNTreeImpl::insertFirst(QPDFObjectHandle const& key, QPDFObjectHandle const& val | ||
| 843 | auto iter = begin(); | 858 | auto iter = begin(); |
| 844 | Array items(nullptr); | 859 | Array items(nullptr); |
| 845 | if (iter.node.isDictionary()) { | 860 | if (iter.node.isDictionary()) { |
| 846 | - items = iter.node.getKey(details.itemsKey()); | 861 | + items = iter.node.getKey(itemsKey()); |
| 847 | } | 862 | } |
| 848 | if (!items) { | 863 | if (!items) { |
| 849 | error(oh, "unable to find a valid items node"); | 864 | error(oh, "unable to find a valid items node"); |
| @@ -868,8 +883,8 @@ NNTreeImpl::insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value) | @@ -868,8 +883,8 @@ NNTreeImpl::insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value) | ||
| 868 | auto iter = find(key, true); | 883 | auto iter = find(key, true); |
| 869 | if (!iter.valid()) { | 884 | if (!iter.valid()) { |
| 870 | return insertFirst(key, value); | 885 | return insertFirst(key, value); |
| 871 | - } else if (details.compareKeys(key, iter->first) == 0) { | ||
| 872 | - Array items = iter.node.getKey(details.itemsKey()); | 886 | + } else if (compareKeys(key, iter->first) == 0) { |
| 887 | + Array items = iter.node.getKey(itemsKey()); | ||
| 873 | items.set(iter.item_number + 1, value); | 888 | items.set(iter.item_number + 1, value); |
| 874 | iter.updateIValue(); | 889 | iter.updateIValue(); |
| 875 | } else { | 890 | } else { |
| @@ -899,7 +914,7 @@ NNTreeImpl::validate(bool a_repair) | @@ -899,7 +914,7 @@ NNTreeImpl::validate(bool a_repair) | ||
| 899 | QPDFObjectHandle last_key; | 914 | QPDFObjectHandle last_key; |
| 900 | try { | 915 | try { |
| 901 | for (auto const& [key, value]: *this) { | 916 | for (auto const& [key, value]: *this) { |
| 902 | - if (!details.keyValid(key)) { | 917 | + if (!keyValid(key)) { |
| 903 | error(oh, "invalid key in validate"); | 918 | error(oh, "invalid key in validate"); |
| 904 | } | 919 | } |
| 905 | if (!value_valid(value)) { | 920 | if (!value_valid(value)) { |
| @@ -907,7 +922,7 @@ NNTreeImpl::validate(bool a_repair) | @@ -907,7 +922,7 @@ NNTreeImpl::validate(bool a_repair) | ||
| 907 | } | 922 | } |
| 908 | if (first) { | 923 | if (first) { |
| 909 | first = false; | 924 | first = false; |
| 910 | - } else if (last_key && details.compareKeys(last_key, key) != -1) { | 925 | + } else if (last_key && compareKeys(last_key, key) != -1) { |
| 911 | error(oh, "keys are not sorted in validate"); | 926 | error(oh, "keys are not sorted in validate"); |
| 912 | } | 927 | } |
| 913 | last_key = key; | 928 | last_key = key; |
libqpdf/QPDFNameTreeObjectHelper.cc
| @@ -2,38 +2,6 @@ | @@ -2,38 +2,6 @@ | ||
| 2 | 2 | ||
| 3 | #include <qpdf/NNTree.hh> | 3 | #include <qpdf/NNTree.hh> |
| 4 | 4 | ||
| 5 | -namespace | ||
| 6 | -{ | ||
| 7 | - class NameTreeDetails: public NNTreeDetails | ||
| 8 | - { | ||
| 9 | - public: | ||
| 10 | - std::string const& | ||
| 11 | - itemsKey() const override | ||
| 12 | - { | ||
| 13 | - static std::string k("/Names"); | ||
| 14 | - return k; | ||
| 15 | - } | ||
| 16 | - bool | ||
| 17 | - keyValid(QPDFObjectHandle oh) const override | ||
| 18 | - { | ||
| 19 | - return oh.isString(); | ||
| 20 | - } | ||
| 21 | - int | ||
| 22 | - compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const override | ||
| 23 | - { | ||
| 24 | - if (!(keyValid(a) && keyValid(b))) { | ||
| 25 | - // We don't call this without calling keyValid first | ||
| 26 | - throw std::logic_error("comparing invalid keys"); | ||
| 27 | - } | ||
| 28 | - auto as = a.getUTF8Value(); | ||
| 29 | - auto bs = b.getUTF8Value(); | ||
| 30 | - return ((as < bs) ? -1 : (as > bs) ? 1 : 0); | ||
| 31 | - } | ||
| 32 | - }; | ||
| 33 | -} // namespace | ||
| 34 | - | ||
| 35 | -static NameTreeDetails name_tree_details; | ||
| 36 | - | ||
| 37 | QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() // NOLINT (modernize-use-equals-default) | 5 | QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() // NOLINT (modernize-use-equals-default) |
| 38 | { | 6 | { |
| 39 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | 7 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific |
| @@ -45,7 +13,7 @@ QPDFNameTreeObjectHelper::Members::Members( | @@ -45,7 +13,7 @@ QPDFNameTreeObjectHelper::Members::Members( | ||
| 45 | QPDF& q, | 13 | QPDF& q, |
| 46 | std::function<bool(QPDFObjectHandle const&)> value_validator, | 14 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 47 | bool auto_repair) : | 15 | bool auto_repair) : |
| 48 | - impl(std::make_shared<NNTreeImpl>(name_tree_details, q, oh, value_validator, auto_repair)) | 16 | + impl(std::make_shared<NNTreeImpl>(q, oh, ::ot_string, value_validator, auto_repair)) |
| 49 | { | 17 | { |
| 50 | } | 18 | } |
| 51 | 19 |
libqpdf/QPDFNumberTreeObjectHelper.cc
| @@ -3,38 +3,6 @@ | @@ -3,38 +3,6 @@ | ||
| 3 | #include <qpdf/NNTree.hh> | 3 | #include <qpdf/NNTree.hh> |
| 4 | #include <qpdf/QIntC.hh> | 4 | #include <qpdf/QIntC.hh> |
| 5 | 5 | ||
| 6 | -namespace | ||
| 7 | -{ | ||
| 8 | - class NumberTreeDetails: public NNTreeDetails | ||
| 9 | - { | ||
| 10 | - public: | ||
| 11 | - std::string const& | ||
| 12 | - itemsKey() const override | ||
| 13 | - { | ||
| 14 | - static std::string k("/Nums"); | ||
| 15 | - return k; | ||
| 16 | - } | ||
| 17 | - bool | ||
| 18 | - keyValid(QPDFObjectHandle oh) const override | ||
| 19 | - { | ||
| 20 | - return oh.isInteger(); | ||
| 21 | - } | ||
| 22 | - int | ||
| 23 | - compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const override | ||
| 24 | - { | ||
| 25 | - if (!(keyValid(a) && keyValid(b))) { | ||
| 26 | - // We don't call this without calling keyValid first | ||
| 27 | - throw std::logic_error("comparing invalid keys"); | ||
| 28 | - } | ||
| 29 | - auto as = a.getIntValue(); | ||
| 30 | - auto bs = b.getIntValue(); | ||
| 31 | - return ((as < bs) ? -1 : (as > bs) ? 1 : 0); | ||
| 32 | - } | ||
| 33 | - }; | ||
| 34 | -} // namespace | ||
| 35 | - | ||
| 36 | -static NumberTreeDetails number_tree_details; | ||
| 37 | - | ||
| 38 | QPDFNumberTreeObjectHelper::~QPDFNumberTreeObjectHelper() // NOLINT (modernize-use-equals-default) | 6 | QPDFNumberTreeObjectHelper::~QPDFNumberTreeObjectHelper() // NOLINT (modernize-use-equals-default) |
| 39 | { | 7 | { |
| 40 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | 8 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific |
| @@ -46,7 +14,7 @@ QPDFNumberTreeObjectHelper::Members::Members( | @@ -46,7 +14,7 @@ QPDFNumberTreeObjectHelper::Members::Members( | ||
| 46 | QPDF& q, | 14 | QPDF& q, |
| 47 | std::function<bool(QPDFObjectHandle const&)> value_validator, | 15 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 48 | bool auto_repair) : | 16 | bool auto_repair) : |
| 49 | - impl(std::make_shared<NNTreeImpl>(number_tree_details, q, oh, value_validator, auto_repair)) | 17 | + impl(std::make_shared<NNTreeImpl>(q, oh, ::ot_integer, value_validator, auto_repair)) |
| 50 | { | 18 | { |
| 51 | } | 19 | } |
| 52 | 20 |
libqpdf/qpdf/NNTree.hh
| @@ -2,20 +2,12 @@ | @@ -2,20 +2,12 @@ | ||
| 2 | #define NNTREE_HH | 2 | #define NNTREE_HH |
| 3 | 3 | ||
| 4 | #include <qpdf/QPDF.hh> | 4 | #include <qpdf/QPDF.hh> |
| 5 | -#include <qpdf/QPDFObjectHandle.hh> | 5 | +#include <qpdf/QPDFObjectHandle_private.hh> |
| 6 | 6 | ||
| 7 | #include <iterator> | 7 | #include <iterator> |
| 8 | #include <list> | 8 | #include <list> |
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | 10 | ||
| 11 | -class NNTreeDetails | ||
| 12 | -{ | ||
| 13 | - public: | ||
| 14 | - virtual std::string const& itemsKey() const = 0; | ||
| 15 | - virtual bool keyValid(QPDFObjectHandle) const = 0; | ||
| 16 | - virtual int compareKeys(QPDFObjectHandle, QPDFObjectHandle) const = 0; | ||
| 17 | -}; | ||
| 18 | - | ||
| 19 | class NNTreeImpl; | 11 | class NNTreeImpl; |
| 20 | class NNTreeIterator | 12 | class NNTreeIterator |
| 21 | { | 13 | { |
| @@ -96,9 +88,9 @@ class NNTreeImpl | @@ -96,9 +88,9 @@ class NNTreeImpl | ||
| 96 | typedef NNTreeIterator iterator; | 88 | typedef NNTreeIterator iterator; |
| 97 | 89 | ||
| 98 | NNTreeImpl( | 90 | NNTreeImpl( |
| 99 | - NNTreeDetails const&, | ||
| 100 | QPDF&, | 91 | QPDF&, |
| 101 | QPDFObjectHandle&, | 92 | QPDFObjectHandle&, |
| 93 | + qpdf_object_type_e key_type, | ||
| 102 | std::function<bool(QPDFObjectHandle const&)> value_validator, | 94 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 103 | bool auto_repair = true); | 95 | bool auto_repair = true); |
| 104 | iterator begin(); | 96 | iterator begin(); |
| @@ -130,10 +122,24 @@ class NNTreeImpl | @@ -130,10 +122,24 @@ class NNTreeImpl | ||
| 130 | void warn(QPDFObjectHandle const& node, std::string const& msg); | 122 | void warn(QPDFObjectHandle const& node, std::string const& msg); |
| 131 | void error(QPDFObjectHandle const& node, std::string const& msg); | 123 | void error(QPDFObjectHandle const& node, std::string const& msg); |
| 132 | 124 | ||
| 133 | - NNTreeDetails const& details; | 125 | + std::string const& |
| 126 | + itemsKey() const | ||
| 127 | + { | ||
| 128 | + return items_key; | ||
| 129 | + } | ||
| 130 | + bool | ||
| 131 | + keyValid(QPDFObjectHandle o) const | ||
| 132 | + { | ||
| 133 | + return o.resolved_type_code() == key_type; | ||
| 134 | + } | ||
| 135 | + int | ||
| 136 | + compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const; | ||
| 137 | + | ||
| 134 | QPDF& qpdf; | 138 | QPDF& qpdf; |
| 135 | int split_threshold{32}; | 139 | int split_threshold{32}; |
| 136 | QPDFObjectHandle oh; | 140 | QPDFObjectHandle oh; |
| 141 | + const qpdf_object_type_e key_type; | ||
| 142 | + const std::string items_key; | ||
| 137 | const std::function<bool(QPDFObjectHandle const&)> value_valid; | 143 | const std::function<bool(QPDFObjectHandle const&)> value_valid; |
| 138 | bool auto_repair{true}; | 144 | bool auto_repair{true}; |
| 139 | size_t error_count{0}; | 145 | size_t error_count{0}; |