Commit 979dc51b57eb9207a5cc72737fefd4d579b9e983
Committed by
GitHub
Merge pull request #1531 from m-holger/nnt
Refactor NNTree
Showing
7 changed files
with
581 additions
and
686 deletions
include/qpdf/QPDFNameTreeObjectHelper.hh
| ... | ... | @@ -176,23 +176,7 @@ class QPDF_DLL_CLASS QPDFNameTreeObjectHelper: public QPDFObjectHelper |
| 176 | 176 | void setSplitThreshold(int); |
| 177 | 177 | |
| 178 | 178 | private: |
| 179 | - class QPDF_DLL_PRIVATE Members | |
| 180 | - { | |
| 181 | - friend class QPDFNameTreeObjectHelper; | |
| 182 | - | |
| 183 | - public: | |
| 184 | - ~Members() = default; | |
| 185 | - | |
| 186 | - private: | |
| 187 | - Members( | |
| 188 | - QPDFObjectHandle& oh, | |
| 189 | - QPDF&, | |
| 190 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 191 | - bool auto_repair); | |
| 192 | - Members(Members const&) = delete; | |
| 193 | - | |
| 194 | - std::shared_ptr<NNTreeImpl> impl; | |
| 195 | - }; | |
| 179 | + class QPDF_DLL_PRIVATE Members; | |
| 196 | 180 | |
| 197 | 181 | std::shared_ptr<Members> m; |
| 198 | 182 | }; | ... | ... |
include/qpdf/QPDFNumberTreeObjectHelper.hh
| ... | ... | @@ -192,24 +192,7 @@ class QPDF_DLL_CLASS QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 192 | 192 | void setSplitThreshold(int); |
| 193 | 193 | |
| 194 | 194 | private: |
| 195 | - class QPDF_DLL_PRIVATE Members | |
| 196 | - { | |
| 197 | - friend class QPDFNumberTreeObjectHelper; | |
| 198 | - typedef QPDFNumberTreeObjectHelper::numtree_number numtree_number; | |
| 199 | - | |
| 200 | - public: | |
| 201 | - ~Members() = default; | |
| 202 | - | |
| 203 | - private: | |
| 204 | - Members( | |
| 205 | - QPDFObjectHandle& oh, | |
| 206 | - QPDF&, | |
| 207 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 208 | - bool auto_repair); | |
| 209 | - Members(Members const&) = delete; | |
| 210 | - | |
| 211 | - std::shared_ptr<NNTreeImpl> impl; | |
| 212 | - }; | |
| 195 | + class QPDF_DLL_PRIVATE Members; | |
| 213 | 196 | |
| 214 | 197 | std::shared_ptr<Members> m; |
| 215 | 198 | }; | ... | ... |
libqpdf/CMakeLists.txt
libqpdf/NNTree.cc
| ... | ... | @@ -2,6 +2,9 @@ |
| 2 | 2 | |
| 3 | 3 | #include <qpdf/NNTree.hh> |
| 4 | 4 | |
| 5 | +#include <qpdf/QPDFNameTreeObjectHelper.hh> | |
| 6 | +#include <qpdf/QPDFNumberTreeObjectHelper.hh> | |
| 7 | + | |
| 5 | 8 | #include <qpdf/QPDFObjectHandle_private.hh> |
| 6 | 9 | #include <qpdf/QPDF_private.hh> |
| 7 | 10 | #include <qpdf/QTC.hh> |
| ... | ... | @@ -33,16 +36,11 @@ NNTreeImpl::warn(QPDFObjectHandle const& node, std::string const& msg) |
| 33 | 36 | } |
| 34 | 37 | |
| 35 | 38 | void |
| 36 | -NNTreeImpl::error(QPDFObjectHandle const& node, std::string const& msg) | |
| 39 | +NNTreeImpl::error(QPDFObjectHandle const& node, std::string const& msg) const | |
| 37 | 40 | { |
| 38 | 41 | throw QPDFExc(qpdf_e_damaged_pdf, qpdf.getFilename(), get_description(node), 0, msg); |
| 39 | 42 | } |
| 40 | 43 | |
| 41 | -NNTreeIterator::NNTreeIterator(NNTreeImpl& impl) : | |
| 42 | - impl(impl) | |
| 43 | -{ | |
| 44 | -} | |
| 45 | - | |
| 46 | 44 | void |
| 47 | 45 | NNTreeIterator::updateIValue(bool allow_invalid) |
| 48 | 46 | { |
| ... | ... | @@ -68,7 +66,7 @@ NNTreeIterator::updateIValue(bool allow_invalid) |
| 68 | 66 | ivalue.second = QPDFObjectHandle(); |
| 69 | 67 | return; |
| 70 | 68 | } |
| 71 | - Array items = node.getKey(impl.details.itemsKey()); | |
| 69 | + Array items = node.getKey(impl.itemsKey()); | |
| 72 | 70 | if (!std::cmp_less(item_number + 1, items.size())) { |
| 73 | 71 | impl.error(node, "update ivalue: items array is too short"); |
| 74 | 72 | } |
| ... | ... | @@ -91,7 +89,7 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward) |
| 91 | 89 | if (pe.kid_number >= 0 && std::cmp_less(pe.kid_number, kids.size())) { |
| 92 | 90 | auto result = kids[pe.kid_number]; |
| 93 | 91 | if (result.isDictionary() && |
| 94 | - (result.hasKey("/Kids") || result.hasKey(impl.details.itemsKey()))) { | |
| 92 | + (result.hasKey("/Kids") || result.hasKey(impl.itemsKey()))) { | |
| 95 | 93 | return result; |
| 96 | 94 | } else { |
| 97 | 95 | impl.warn( |
| ... | ... | @@ -102,15 +100,6 @@ NNTreeIterator::getNextKid(PathElement& pe, bool backward) |
| 102 | 100 | } |
| 103 | 101 | } |
| 104 | 102 | } |
| 105 | - | |
| 106 | -// iterator can be incremented or decremented, or dereferenced. This does not imply that it points | |
| 107 | -// to a valid item. | |
| 108 | -bool | |
| 109 | -NNTreeIterator::valid() const | |
| 110 | -{ | |
| 111 | - return item_number >= 0; | |
| 112 | -} | |
| 113 | - | |
| 114 | 103 | void |
| 115 | 104 | NNTreeIterator::increment(bool backward) |
| 116 | 105 | { |
| ... | ... | @@ -121,7 +110,7 @@ NNTreeIterator::increment(bool backward) |
| 121 | 110 | |
| 122 | 111 | while (valid()) { |
| 123 | 112 | item_number += backward ? -2 : 2; |
| 124 | - Array items = node.getKey(impl.details.itemsKey()); | |
| 113 | + Array items = node.getKey(impl.itemsKey()); | |
| 125 | 114 | if (item_number < 0 || std::cmp_greater_equal(item_number, items.size())) { |
| 126 | 115 | bool found = false; |
| 127 | 116 | setItemNumber(QPDFObjectHandle(), -1); |
| ... | ... | @@ -136,10 +125,10 @@ NNTreeIterator::increment(bool backward) |
| 136 | 125 | } |
| 137 | 126 | } |
| 138 | 127 | if (item_number >= 0) { |
| 139 | - items = node.getKey(impl.details.itemsKey()); | |
| 128 | + items = node.getKey(impl.itemsKey()); | |
| 140 | 129 | if (std::cmp_greater_equal(item_number + 1, items.size())) { |
| 141 | 130 | impl.warn(node, "items array doesn't have enough elements"); |
| 142 | - } else if (!impl.details.keyValid(items[item_number])) { | |
| 131 | + } else if (!impl.keyValid(items[item_number])) { | |
| 143 | 132 | impl.warn(node, ("item " + std::to_string(item_number) + " has the wrong type")); |
| 144 | 133 | } else if (!impl.value_valid(items[item_number + 1])) { |
| 145 | 134 | impl.warn(node, "item " + std::to_string(item_number + 1) + " is invalid"); |
| ... | ... | @@ -160,7 +149,7 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite |
| 160 | 149 | } |
| 161 | 150 | Array kids = a_node.getKey("/Kids"); |
| 162 | 151 | size_t nkids = kids.size(); |
| 163 | - Array items = a_node.getKey(impl.details.itemsKey()); | |
| 152 | + Array items = a_node.getKey(impl.itemsKey()); | |
| 164 | 153 | size_t nitems = items.size(); |
| 165 | 154 | |
| 166 | 155 | bool changed = true; |
| ... | ... | @@ -187,9 +176,8 @@ NNTreeIterator::resetLimits(QPDFObjectHandle a_node, std::list<PathElement>::ite |
| 187 | 176 | if (olimits.size() == 2) { |
| 188 | 177 | auto ofirst = olimits[0]; |
| 189 | 178 | 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) { | |
| 179 | + if (impl.keyValid(ofirst) && impl.keyValid(olast) && | |
| 180 | + impl.compareKeys(first, ofirst) == 0 && impl.compareKeys(last, olast) == 0) { | |
| 193 | 181 | changed = false; |
| 194 | 182 | } |
| 195 | 183 | } |
| ... | ... | @@ -246,7 +234,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato |
| 246 | 234 | // Find the array we actually need to split, which is either this node's kids or items. |
| 247 | 235 | Array kids = to_split.getKey("/Kids"); |
| 248 | 236 | size_t nkids = kids.size(); |
| 249 | - Array items = to_split.getKey(impl.details.itemsKey()); | |
| 237 | + Array items = to_split.getKey(impl.itemsKey()); | |
| 250 | 238 | size_t nitems = items.size(); |
| 251 | 239 | |
| 252 | 240 | Array first_half; |
| ... | ... | @@ -261,7 +249,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato |
| 261 | 249 | first_half = items; |
| 262 | 250 | n = nitems; |
| 263 | 251 | threshold *= 2; |
| 264 | - key = impl.details.itemsKey(); | |
| 252 | + key = impl.itemsKey(); | |
| 265 | 253 | } else { |
| 266 | 254 | throw std::logic_error("NNTreeIterator::split called on invalid node"); |
| 267 | 255 | } |
| ... | ... | @@ -295,7 +283,7 @@ NNTreeIterator::split(QPDFObjectHandle to_split, std::list<PathElement>::iterato |
| 295 | 283 | Array new_kids; |
| 296 | 284 | new_kids.push_back(first_node); |
| 297 | 285 | to_split.removeKey("/Limits"); // already shouldn't be there for root |
| 298 | - to_split.removeKey(impl.details.itemsKey()); | |
| 286 | + to_split.removeKey(impl.itemsKey()); | |
| 299 | 287 | to_split.replaceKey("/Kids", new_kids); |
| 300 | 288 | if (is_leaf) { |
| 301 | 289 | node = first_node; |
| ... | ... | @@ -375,7 +363,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle const& key, QPDFObjectHandle const& |
| 375 | 363 | return; |
| 376 | 364 | } |
| 377 | 365 | |
| 378 | - Array items = node.getKey(impl.details.itemsKey()); | |
| 366 | + Array items = node.getKey(impl.itemsKey()); | |
| 379 | 367 | if (!items) { |
| 380 | 368 | impl.error(node, "node contains no items array"); |
| 381 | 369 | } |
| ... | ... | @@ -404,7 +392,7 @@ NNTreeIterator::remove() |
| 404 | 392 | if (!valid()) { |
| 405 | 393 | throw std::logic_error("attempt made to remove an invalid iterator"); |
| 406 | 394 | } |
| 407 | - Array items = node.getKey(impl.details.itemsKey()); | |
| 395 | + Array items = node.getKey(impl.itemsKey()); | |
| 408 | 396 | int nitems = static_cast<int>(items.size()); |
| 409 | 397 | if (std::cmp_greater(item_number + 2, nitems)) { |
| 410 | 398 | impl.error(node, "found short items array while removing an item"); |
| ... | ... | @@ -478,7 +466,7 @@ NNTreeIterator::remove() |
| 478 | 466 | if (parent == path.end()) { |
| 479 | 467 | // We erased the very last item. Convert the root to an empty items array. |
| 480 | 468 | element->node.removeKey("/Kids"); |
| 481 | - element->node.replaceKey(impl.details.itemsKey(), Array()); | |
| 469 | + element->node.replaceKey(impl.itemsKey(), Array()); | |
| 482 | 470 | path.clear(); |
| 483 | 471 | setItemNumber(impl.oh, -1); |
| 484 | 472 | return; |
| ... | ... | @@ -489,34 +477,6 @@ NNTreeIterator::remove() |
| 489 | 477 | } |
| 490 | 478 | } |
| 491 | 479 | |
| 492 | -NNTreeIterator& | |
| 493 | -NNTreeIterator::operator++() | |
| 494 | -{ | |
| 495 | - increment(false); | |
| 496 | - return *this; | |
| 497 | -} | |
| 498 | - | |
| 499 | -NNTreeIterator& | |
| 500 | -NNTreeIterator::operator--() | |
| 501 | -{ | |
| 502 | - increment(true); | |
| 503 | - return *this; | |
| 504 | -} | |
| 505 | - | |
| 506 | -NNTreeIterator::reference | |
| 507 | -NNTreeIterator::operator*() | |
| 508 | -{ | |
| 509 | - updateIValue(false); | |
| 510 | - return ivalue; | |
| 511 | -} | |
| 512 | - | |
| 513 | -NNTreeIterator::pointer | |
| 514 | -NNTreeIterator::operator->() | |
| 515 | -{ | |
| 516 | - updateIValue(false); | |
| 517 | - return &ivalue; | |
| 518 | -} | |
| 519 | - | |
| 520 | 480 | bool |
| 521 | 481 | NNTreeIterator::operator==(NNTreeIterator const& other) const |
| 522 | 482 | { |
| ... | ... | @@ -538,20 +498,6 @@ NNTreeIterator::operator==(NNTreeIterator const& other) const |
| 538 | 498 | return item_number == other.item_number; |
| 539 | 499 | } |
| 540 | 500 | |
| 541 | -void | |
| 542 | -NNTreeIterator::setItemNumber(QPDFObjectHandle const& a_node, int n) | |
| 543 | -{ | |
| 544 | - node = a_node; | |
| 545 | - item_number = n; | |
| 546 | - updateIValue(); | |
| 547 | -} | |
| 548 | - | |
| 549 | -void | |
| 550 | -NNTreeIterator::addPathElement(QPDFObjectHandle const& a_node, int kid_number) | |
| 551 | -{ | |
| 552 | - path.emplace_back(a_node, kid_number); | |
| 553 | -} | |
| 554 | - | |
| 555 | 501 | bool |
| 556 | 502 | NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) |
| 557 | 503 | { |
| ... | ... | @@ -579,7 +525,7 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) |
| 579 | 525 | return fail(a_node, "non-dictionary node while traversing name/number tree"); |
| 580 | 526 | } |
| 581 | 527 | |
| 582 | - Array items = a_node.getKey(impl.details.itemsKey()); | |
| 528 | + Array items = a_node.getKey(impl.itemsKey()); | |
| 583 | 529 | int nitems = static_cast<int>(items.size()); |
| 584 | 530 | if (nitems > 1) { |
| 585 | 531 | setItemNumber(a_node, first ? 0 : nitems - 2); |
| ... | ... | @@ -616,33 +562,12 @@ NNTreeIterator::deepen(QPDFObjectHandle a_node, bool first, bool allow_empty) |
| 616 | 562 | } else { |
| 617 | 563 | return fail( |
| 618 | 564 | a_node, |
| 619 | - "name/number tree node has neither non-empty " + impl.details.itemsKey() + | |
| 620 | - " nor /Kids"); | |
| 565 | + "name/number tree node has neither non-empty " + impl.itemsKey() + " nor /Kids"); | |
| 621 | 566 | } |
| 622 | 567 | } |
| 623 | 568 | return true; |
| 624 | 569 | } |
| 625 | 570 | |
| 626 | -NNTreeImpl::NNTreeImpl( | |
| 627 | - NNTreeDetails const& details, | |
| 628 | - QPDF& qpdf, | |
| 629 | - QPDFObjectHandle& oh, | |
| 630 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 631 | - bool auto_repair) : | |
| 632 | - details(details), | |
| 633 | - qpdf(qpdf), | |
| 634 | - oh(oh), | |
| 635 | - value_valid(value_validator), | |
| 636 | - auto_repair(auto_repair) | |
| 637 | -{ | |
| 638 | -} | |
| 639 | - | |
| 640 | -void | |
| 641 | -NNTreeImpl::setSplitThreshold(int threshold) | |
| 642 | -{ | |
| 643 | - split_threshold = threshold; | |
| 644 | -} | |
| 645 | - | |
| 646 | 571 | NNTreeImpl::iterator |
| 647 | 572 | NNTreeImpl::begin() |
| 648 | 573 | { |
| ... | ... | @@ -652,12 +577,6 @@ NNTreeImpl::begin() |
| 652 | 577 | } |
| 653 | 578 | |
| 654 | 579 | NNTreeImpl::iterator |
| 655 | -NNTreeImpl::end() | |
| 656 | -{ | |
| 657 | - return {*this}; | |
| 658 | -} | |
| 659 | - | |
| 660 | -NNTreeImpl::iterator | |
| 661 | 580 | NNTreeImpl::last() |
| 662 | 581 | { |
| 663 | 582 | iterator result(*this); |
| ... | ... | @@ -666,28 +585,28 @@ NNTreeImpl::last() |
| 666 | 585 | } |
| 667 | 586 | |
| 668 | 587 | int |
| 669 | -NNTreeImpl::withinLimits(QPDFObjectHandle const& key, QPDFObjectHandle const& node) | |
| 588 | +NNTreeImpl::compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const | |
| 670 | 589 | { |
| 671 | - Array limits = node.getKey("/Limits"); | |
| 672 | - if (!(details.keyValid(limits[0]) && details.keyValid(limits[1]))) { | |
| 673 | - error(node, "node is missing /Limits"); | |
| 674 | - } | |
| 675 | - if (details.compareKeys(key, limits[0]) < 0) { | |
| 676 | - return -1; | |
| 590 | + // We don't call this without calling keyValid first | |
| 591 | + qpdf_assert_debug(keyValid(a)); | |
| 592 | + qpdf_assert_debug(keyValid(b)); | |
| 593 | + if (key_type == ::ot_string) { | |
| 594 | + auto as = a.getUTF8Value(); | |
| 595 | + auto bs = b.getUTF8Value(); | |
| 596 | + return as < bs ? -1 : (as > bs ? 1 : 0); | |
| 677 | 597 | } |
| 678 | - if (details.compareKeys(key, limits[1]) > 0) { | |
| 679 | - return 1; | |
| 680 | - } | |
| 681 | - return 0; | |
| 598 | + auto as = a.getIntValue(); | |
| 599 | + auto bs = b.getIntValue(); | |
| 600 | + return as < bs ? -1 : (as > bs ? 1 : 0); | |
| 682 | 601 | } |
| 683 | 602 | |
| 684 | 603 | int |
| 685 | 604 | NNTreeImpl::binarySearch( |
| 686 | - QPDFObjectHandle key, | |
| 687 | - QPDFObjectHandle items, | |
| 605 | + QPDFObjectHandle const& key, | |
| 606 | + Array const& items, | |
| 688 | 607 | size_t num_items, |
| 689 | 608 | bool return_prev_if_not_found, |
| 690 | - int (NNTreeImpl::*compare)(QPDFObjectHandle& key, QPDFObjectHandle& arr, int item)) | |
| 609 | + int (NNTreeImpl::*compare)(QPDFObjectHandle const& key, Array const& arr, int item) const) const | |
| 691 | 610 | { |
| 692 | 611 | size_t max_idx = std::bit_ceil(num_items); |
| 693 | 612 | |
| ... | ... | @@ -726,36 +645,46 @@ NNTreeImpl::binarySearch( |
| 726 | 645 | } |
| 727 | 646 | |
| 728 | 647 | int |
| 729 | -NNTreeImpl::compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx) | |
| 648 | +NNTreeImpl::compareKeyItem(QPDFObjectHandle const& key, Array const& items, int idx) const | |
| 730 | 649 | { |
| 731 | - if (!(std::cmp_greater(items.size(), 2 * idx) && details.keyValid(items[2 * idx]))) { | |
| 650 | + if (!keyValid(items[2 * idx])) { | |
| 732 | 651 | error(oh, ("item at index " + std::to_string(2 * idx) + " is not the right type")); |
| 733 | 652 | } |
| 734 | - return details.compareKeys(key, items[2 * idx]); | |
| 653 | + return compareKeys(key, items[2 * idx]); | |
| 735 | 654 | } |
| 736 | 655 | |
| 737 | 656 | int |
| 738 | -NNTreeImpl::compareKeyKid(QPDFObjectHandle& key, QPDFObjectHandle& kids, int idx) | |
| 657 | +NNTreeImpl::compareKeyKid(QPDFObjectHandle const& key, Array const& kids, int idx) const | |
| 739 | 658 | { |
| 740 | - if (!(std::cmp_less(idx, kids.size()) && kids[idx].isDictionary())) { | |
| 659 | + if (!kids[idx].isDictionary()) { | |
| 741 | 660 | error(oh, "invalid kid at index " + std::to_string(idx)); |
| 742 | 661 | } |
| 743 | - return withinLimits(key, kids[idx]); | |
| 662 | + Array limits = kids[idx].getKey("/Limits"); | |
| 663 | + if (!(keyValid(limits[0]) && keyValid(limits[1]))) { | |
| 664 | + error(kids[idx], "node is missing /Limits"); | |
| 665 | + } | |
| 666 | + if (compareKeys(key, limits[0]) < 0) { | |
| 667 | + return -1; | |
| 668 | + } | |
| 669 | + if (compareKeys(key, limits[1]) > 0) { | |
| 670 | + return 1; | |
| 671 | + } | |
| 672 | + return 0; | |
| 744 | 673 | } |
| 745 | 674 | |
| 746 | 675 | void |
| 747 | 676 | NNTreeImpl::repair() |
| 748 | 677 | { |
| 749 | 678 | auto new_node = QPDFObjectHandle::newDictionary(); |
| 750 | - new_node.replaceKey(details.itemsKey(), Array()); | |
| 751 | - NNTreeImpl repl(details, qpdf, new_node, value_valid, false); | |
| 679 | + new_node.replaceKey(itemsKey(), Array()); | |
| 680 | + NNTreeImpl repl(qpdf, new_node, key_type, value_valid, false); | |
| 752 | 681 | for (auto const& [key, value]: *this) { |
| 753 | 682 | if (key && value) { |
| 754 | 683 | repl.insert(key, value); |
| 755 | 684 | } |
| 756 | 685 | } |
| 757 | 686 | oh.replaceKey("/Kids", new_node.getKey("/Kids")); |
| 758 | - oh.replaceKey(details.itemsKey(), new_node.getKey(details.itemsKey())); | |
| 687 | + oh.replaceKey(itemsKey(), new_node.getKey(itemsKey())); | |
| 759 | 688 | } |
| 760 | 689 | |
| 761 | 690 | NNTreeImpl::iterator |
| ... | ... | @@ -783,13 +712,13 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo |
| 783 | 712 | return end(); |
| 784 | 713 | } |
| 785 | 714 | if (first_item.valid()) { |
| 786 | - if (!details.keyValid(first_item->first)) { | |
| 715 | + if (!keyValid(first_item->first)) { | |
| 787 | 716 | error(oh, "encountered invalid key in find"); |
| 788 | 717 | } |
| 789 | 718 | if (!value_valid(first_item->second)) { |
| 790 | 719 | error(oh, "encountered invalid value in find"); |
| 791 | 720 | } |
| 792 | - if (details.compareKeys(key, first_item->first) < 0) { | |
| 721 | + if (compareKeys(key, first_item->first) < 0) { | |
| 793 | 722 | // Before the first key |
| 794 | 723 | return end(); |
| 795 | 724 | } |
| ... | ... | @@ -805,14 +734,14 @@ NNTreeImpl::findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_fo |
| 805 | 734 | error(node, "loop detected in find"); |
| 806 | 735 | } |
| 807 | 736 | |
| 808 | - Array items = node.getKey(details.itemsKey()); | |
| 737 | + Array items = node.getKey(itemsKey()); | |
| 809 | 738 | size_t nitems = items.size(); |
| 810 | 739 | if (nitems > 1) { |
| 811 | 740 | int idx = binarySearch( |
| 812 | 741 | key, items, nitems / 2, return_prev_if_not_found, &NNTreeImpl::compareKeyItem); |
| 813 | 742 | if (idx >= 0) { |
| 814 | 743 | result.setItemNumber(node, 2 * idx); |
| 815 | - if (!result.impl.details.keyValid(result.ivalue.first)) { | |
| 744 | + if (!result.impl.keyValid(result.ivalue.first)) { | |
| 816 | 745 | error(node, "encountered invalid key in find"); |
| 817 | 746 | } |
| 818 | 747 | if (!result.impl.value_valid(result.ivalue.second)) { |
| ... | ... | @@ -843,7 +772,7 @@ NNTreeImpl::insertFirst(QPDFObjectHandle const& key, QPDFObjectHandle const& val |
| 843 | 772 | auto iter = begin(); |
| 844 | 773 | Array items(nullptr); |
| 845 | 774 | if (iter.node.isDictionary()) { |
| 846 | - items = iter.node.getKey(details.itemsKey()); | |
| 775 | + items = iter.node.getKey(itemsKey()); | |
| 847 | 776 | } |
| 848 | 777 | if (!items) { |
| 849 | 778 | error(oh, "unable to find a valid items node"); |
| ... | ... | @@ -868,8 +797,8 @@ NNTreeImpl::insert(QPDFObjectHandle const& key, QPDFObjectHandle const& value) |
| 868 | 797 | auto iter = find(key, true); |
| 869 | 798 | if (!iter.valid()) { |
| 870 | 799 | return insertFirst(key, value); |
| 871 | - } else if (details.compareKeys(key, iter->first) == 0) { | |
| 872 | - Array items = iter.node.getKey(details.itemsKey()); | |
| 800 | + } else if (compareKeys(key, iter->first) == 0) { | |
| 801 | + Array items = iter.node.getKey(itemsKey()); | |
| 873 | 802 | items.set(iter.item_number + 1, value); |
| 874 | 803 | iter.updateIValue(); |
| 875 | 804 | } else { |
| ... | ... | @@ -899,7 +828,7 @@ NNTreeImpl::validate(bool a_repair) |
| 899 | 828 | QPDFObjectHandle last_key; |
| 900 | 829 | try { |
| 901 | 830 | for (auto const& [key, value]: *this) { |
| 902 | - if (!details.keyValid(key)) { | |
| 831 | + if (!keyValid(key)) { | |
| 903 | 832 | error(oh, "invalid key in validate"); |
| 904 | 833 | } |
| 905 | 834 | if (!value_valid(value)) { |
| ... | ... | @@ -907,7 +836,7 @@ NNTreeImpl::validate(bool a_repair) |
| 907 | 836 | } |
| 908 | 837 | if (first) { |
| 909 | 838 | first = false; |
| 910 | - } else if (last_key && details.compareKeys(last_key, key) != -1) { | |
| 839 | + } else if (last_key && compareKeys(last_key, key) != -1) { | |
| 911 | 840 | error(oh, "keys are not sorted in validate"); |
| 912 | 841 | } |
| 913 | 842 | last_key = key; |
| ... | ... | @@ -921,3 +850,426 @@ NNTreeImpl::validate(bool a_repair) |
| 921 | 850 | } |
| 922 | 851 | return true; |
| 923 | 852 | } |
| 853 | + | |
| 854 | +class QPDFNameTreeObjectHelper::Members | |
| 855 | +{ | |
| 856 | + public: | |
| 857 | + Members( | |
| 858 | + QPDFObjectHandle& oh, | |
| 859 | + QPDF& q, | |
| 860 | + std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 861 | + bool auto_repair) : | |
| 862 | + impl(q, oh, ::ot_string, value_validator, auto_repair) | |
| 863 | + { | |
| 864 | + } | |
| 865 | + Members(Members const&) = delete; | |
| 866 | + ~Members() = default; | |
| 867 | + | |
| 868 | + NNTreeImpl impl; | |
| 869 | +}; | |
| 870 | + | |
| 871 | +// Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | |
| 872 | +// class, see github issue #745. | |
| 873 | +QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() = default; | |
| 874 | + | |
| 875 | +QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(QPDFObjectHandle oh, QPDF& q, bool auto_repair) : | |
| 876 | + QPDFNameTreeObjectHelper( | |
| 877 | + oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair) | |
| 878 | +{ | |
| 879 | +} | |
| 880 | + | |
| 881 | +QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper( | |
| 882 | + QPDFObjectHandle oh, | |
| 883 | + QPDF& q, | |
| 884 | + std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 885 | + bool auto_repair) : | |
| 886 | + QPDFObjectHelper(oh), | |
| 887 | + m(std::make_shared<Members>(oh, q, value_validator, auto_repair)) | |
| 888 | +{ | |
| 889 | +} | |
| 890 | + | |
| 891 | +QPDFNameTreeObjectHelper | |
| 892 | +QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) | |
| 893 | +{ | |
| 894 | + return {qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair}; | |
| 895 | +} | |
| 896 | + | |
| 897 | +QPDFNameTreeObjectHelper::iterator::iterator(std::shared_ptr<NNTreeIterator> const& i) : | |
| 898 | + impl(i) | |
| 899 | +{ | |
| 900 | +} | |
| 901 | + | |
| 902 | +bool | |
| 903 | +QPDFNameTreeObjectHelper::iterator::valid() const | |
| 904 | +{ | |
| 905 | + return impl->valid(); | |
| 906 | +} | |
| 907 | + | |
| 908 | +QPDFNameTreeObjectHelper::iterator& | |
| 909 | +QPDFNameTreeObjectHelper::iterator::operator++() | |
| 910 | +{ | |
| 911 | + ++(*impl); | |
| 912 | + updateIValue(); | |
| 913 | + return *this; | |
| 914 | +} | |
| 915 | + | |
| 916 | +QPDFNameTreeObjectHelper::iterator& | |
| 917 | +QPDFNameTreeObjectHelper::iterator::operator--() | |
| 918 | +{ | |
| 919 | + --(*impl); | |
| 920 | + updateIValue(); | |
| 921 | + return *this; | |
| 922 | +} | |
| 923 | + | |
| 924 | +void | |
| 925 | +QPDFNameTreeObjectHelper::iterator::updateIValue() | |
| 926 | +{ | |
| 927 | + if (impl->valid()) { | |
| 928 | + auto p = *impl; | |
| 929 | + ivalue.first = p->first.getUTF8Value(); | |
| 930 | + ivalue.second = p->second; | |
| 931 | + } else { | |
| 932 | + ivalue.first = ""; | |
| 933 | + ivalue.second = QPDFObjectHandle(); | |
| 934 | + } | |
| 935 | +} | |
| 936 | + | |
| 937 | +QPDFNameTreeObjectHelper::iterator::reference | |
| 938 | +QPDFNameTreeObjectHelper::iterator::operator*() | |
| 939 | +{ | |
| 940 | + updateIValue(); | |
| 941 | + return ivalue; | |
| 942 | +} | |
| 943 | + | |
| 944 | +QPDFNameTreeObjectHelper::iterator::pointer | |
| 945 | +QPDFNameTreeObjectHelper::iterator::operator->() | |
| 946 | +{ | |
| 947 | + updateIValue(); | |
| 948 | + return &ivalue; | |
| 949 | +} | |
| 950 | + | |
| 951 | +bool | |
| 952 | +QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 953 | +{ | |
| 954 | + return *(impl) == *(other.impl); | |
| 955 | +} | |
| 956 | + | |
| 957 | +void | |
| 958 | +QPDFNameTreeObjectHelper::iterator::insertAfter(std::string const& key, QPDFObjectHandle value) | |
| 959 | +{ | |
| 960 | + impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value); | |
| 961 | + updateIValue(); | |
| 962 | +} | |
| 963 | + | |
| 964 | +void | |
| 965 | +QPDFNameTreeObjectHelper::iterator::remove() | |
| 966 | +{ | |
| 967 | + impl->remove(); | |
| 968 | + updateIValue(); | |
| 969 | +} | |
| 970 | + | |
| 971 | +QPDFNameTreeObjectHelper::iterator | |
| 972 | +QPDFNameTreeObjectHelper::begin() const | |
| 973 | +{ | |
| 974 | + return {std::make_shared<NNTreeIterator>(m->impl.begin())}; | |
| 975 | +} | |
| 976 | + | |
| 977 | +QPDFNameTreeObjectHelper::iterator | |
| 978 | +QPDFNameTreeObjectHelper::end() const | |
| 979 | +{ | |
| 980 | + return {std::make_shared<NNTreeIterator>(m->impl.end())}; | |
| 981 | +} | |
| 982 | + | |
| 983 | +QPDFNameTreeObjectHelper::iterator | |
| 984 | +QPDFNameTreeObjectHelper::last() const | |
| 985 | +{ | |
| 986 | + return {std::make_shared<NNTreeIterator>(m->impl.last())}; | |
| 987 | +} | |
| 988 | + | |
| 989 | +QPDFNameTreeObjectHelper::iterator | |
| 990 | +QPDFNameTreeObjectHelper::find(std::string const& key, bool return_prev_if_not_found) | |
| 991 | +{ | |
| 992 | + auto i = m->impl.find(QPDFObjectHandle::newUnicodeString(key), return_prev_if_not_found); | |
| 993 | + return {std::make_shared<NNTreeIterator>(i)}; | |
| 994 | +} | |
| 995 | + | |
| 996 | +QPDFNameTreeObjectHelper::iterator | |
| 997 | +QPDFNameTreeObjectHelper::insert(std::string const& key, QPDFObjectHandle value) | |
| 998 | +{ | |
| 999 | + auto i = m->impl.insert(QPDFObjectHandle::newUnicodeString(key), value); | |
| 1000 | + return {std::make_shared<NNTreeIterator>(i)}; | |
| 1001 | +} | |
| 1002 | + | |
| 1003 | +bool | |
| 1004 | +QPDFNameTreeObjectHelper::remove(std::string const& key, QPDFObjectHandle* value) | |
| 1005 | +{ | |
| 1006 | + return m->impl.remove(QPDFObjectHandle::newUnicodeString(key), value); | |
| 1007 | +} | |
| 1008 | + | |
| 1009 | +bool | |
| 1010 | +QPDFNameTreeObjectHelper::hasName(std::string const& name) | |
| 1011 | +{ | |
| 1012 | + auto i = find(name); | |
| 1013 | + return (i != end()); | |
| 1014 | +} | |
| 1015 | + | |
| 1016 | +bool | |
| 1017 | +QPDFNameTreeObjectHelper::findObject(std::string const& name, QPDFObjectHandle& oh) | |
| 1018 | +{ | |
| 1019 | + auto i = find(name); | |
| 1020 | + if (i == end()) { | |
| 1021 | + return false; | |
| 1022 | + } | |
| 1023 | + oh = i->second; | |
| 1024 | + return true; | |
| 1025 | +} | |
| 1026 | + | |
| 1027 | +void | |
| 1028 | +QPDFNameTreeObjectHelper::setSplitThreshold(int t) | |
| 1029 | +{ | |
| 1030 | + m->impl.setSplitThreshold(t); | |
| 1031 | +} | |
| 1032 | + | |
| 1033 | +std::map<std::string, QPDFObjectHandle> | |
| 1034 | +QPDFNameTreeObjectHelper::getAsMap() const | |
| 1035 | +{ | |
| 1036 | + std::map<std::string, QPDFObjectHandle> result; | |
| 1037 | + result.insert(begin(), end()); | |
| 1038 | + return result; | |
| 1039 | +} | |
| 1040 | + | |
| 1041 | +bool | |
| 1042 | +QPDFNameTreeObjectHelper::validate(bool repair) | |
| 1043 | +{ | |
| 1044 | + return m->impl.validate(repair); | |
| 1045 | +} | |
| 1046 | + | |
| 1047 | +class QPDFNumberTreeObjectHelper::Members | |
| 1048 | +{ | |
| 1049 | + typedef QPDFNumberTreeObjectHelper::numtree_number numtree_number; | |
| 1050 | + | |
| 1051 | + public: | |
| 1052 | + Members( | |
| 1053 | + QPDFObjectHandle& oh, | |
| 1054 | + QPDF& q, | |
| 1055 | + std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 1056 | + bool auto_repair) : | |
| 1057 | + impl(q, oh, ::ot_integer, value_validator, auto_repair) | |
| 1058 | + { | |
| 1059 | + } | |
| 1060 | + Members(Members const&) = delete; | |
| 1061 | + ~Members() = default; | |
| 1062 | + | |
| 1063 | + NNTreeImpl impl; | |
| 1064 | +}; | |
| 1065 | + | |
| 1066 | +// Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | |
| 1067 | +// class, see github issue #745. | |
| 1068 | +QPDFNumberTreeObjectHelper::~QPDFNumberTreeObjectHelper() = default; | |
| 1069 | + | |
| 1070 | +QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( | |
| 1071 | + QPDFObjectHandle oh, QPDF& q, bool auto_repair) : | |
| 1072 | + QPDFNumberTreeObjectHelper( | |
| 1073 | + oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair) | |
| 1074 | +{ | |
| 1075 | +} | |
| 1076 | + | |
| 1077 | +QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( | |
| 1078 | + QPDFObjectHandle oh, | |
| 1079 | + QPDF& q, | |
| 1080 | + std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 1081 | + bool auto_repair) : | |
| 1082 | + QPDFObjectHelper(oh), | |
| 1083 | + m(std::make_shared<Members>(oh, q, value_validator, auto_repair)) | |
| 1084 | +{ | |
| 1085 | +} | |
| 1086 | + | |
| 1087 | +QPDFNumberTreeObjectHelper | |
| 1088 | +QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) | |
| 1089 | +{ | |
| 1090 | + return {qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair}; | |
| 1091 | +} | |
| 1092 | + | |
| 1093 | +QPDFNumberTreeObjectHelper::iterator::iterator(std::shared_ptr<NNTreeIterator> const& i) : | |
| 1094 | + impl(i) | |
| 1095 | +{ | |
| 1096 | +} | |
| 1097 | + | |
| 1098 | +bool | |
| 1099 | +QPDFNumberTreeObjectHelper::iterator::valid() const | |
| 1100 | +{ | |
| 1101 | + return impl->valid(); | |
| 1102 | +} | |
| 1103 | + | |
| 1104 | +QPDFNumberTreeObjectHelper::iterator& | |
| 1105 | +QPDFNumberTreeObjectHelper::iterator::operator++() | |
| 1106 | +{ | |
| 1107 | + ++(*impl); | |
| 1108 | + updateIValue(); | |
| 1109 | + return *this; | |
| 1110 | +} | |
| 1111 | + | |
| 1112 | +QPDFNumberTreeObjectHelper::iterator& | |
| 1113 | +QPDFNumberTreeObjectHelper::iterator::operator--() | |
| 1114 | +{ | |
| 1115 | + --(*impl); | |
| 1116 | + updateIValue(); | |
| 1117 | + return *this; | |
| 1118 | +} | |
| 1119 | + | |
| 1120 | +void | |
| 1121 | +QPDFNumberTreeObjectHelper::iterator::updateIValue() | |
| 1122 | +{ | |
| 1123 | + if (impl->valid()) { | |
| 1124 | + auto p = *impl; | |
| 1125 | + this->ivalue.first = p->first.getIntValue(); | |
| 1126 | + this->ivalue.second = p->second; | |
| 1127 | + } else { | |
| 1128 | + this->ivalue.first = 0; | |
| 1129 | + this->ivalue.second = QPDFObjectHandle(); | |
| 1130 | + } | |
| 1131 | +} | |
| 1132 | + | |
| 1133 | +QPDFNumberTreeObjectHelper::iterator::reference | |
| 1134 | +QPDFNumberTreeObjectHelper::iterator::operator*() | |
| 1135 | +{ | |
| 1136 | + updateIValue(); | |
| 1137 | + return this->ivalue; | |
| 1138 | +} | |
| 1139 | + | |
| 1140 | +QPDFNumberTreeObjectHelper::iterator::pointer | |
| 1141 | +QPDFNumberTreeObjectHelper::iterator::operator->() | |
| 1142 | +{ | |
| 1143 | + updateIValue(); | |
| 1144 | + return &this->ivalue; | |
| 1145 | +} | |
| 1146 | + | |
| 1147 | +bool | |
| 1148 | +QPDFNumberTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 1149 | +{ | |
| 1150 | + return *(impl) == *(other.impl); | |
| 1151 | +} | |
| 1152 | + | |
| 1153 | +void | |
| 1154 | +QPDFNumberTreeObjectHelper::iterator::insertAfter(numtree_number key, QPDFObjectHandle value) | |
| 1155 | +{ | |
| 1156 | + impl->insertAfter(QPDFObjectHandle::newInteger(key), value); | |
| 1157 | + updateIValue(); | |
| 1158 | +} | |
| 1159 | + | |
| 1160 | +void | |
| 1161 | +QPDFNumberTreeObjectHelper::iterator::remove() | |
| 1162 | +{ | |
| 1163 | + impl->remove(); | |
| 1164 | + updateIValue(); | |
| 1165 | +} | |
| 1166 | + | |
| 1167 | +QPDFNumberTreeObjectHelper::iterator | |
| 1168 | +QPDFNumberTreeObjectHelper::begin() const | |
| 1169 | +{ | |
| 1170 | + return {std::make_shared<NNTreeIterator>(m->impl.begin())}; | |
| 1171 | +} | |
| 1172 | + | |
| 1173 | +QPDFNumberTreeObjectHelper::iterator | |
| 1174 | +QPDFNumberTreeObjectHelper::end() const | |
| 1175 | +{ | |
| 1176 | + return {std::make_shared<NNTreeIterator>(m->impl.end())}; | |
| 1177 | +} | |
| 1178 | + | |
| 1179 | +QPDFNumberTreeObjectHelper::iterator | |
| 1180 | +QPDFNumberTreeObjectHelper::last() const | |
| 1181 | +{ | |
| 1182 | + return {std::make_shared<NNTreeIterator>(m->impl.last())}; | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +QPDFNumberTreeObjectHelper::iterator | |
| 1186 | +QPDFNumberTreeObjectHelper::find(numtree_number key, bool return_prev_if_not_found) | |
| 1187 | +{ | |
| 1188 | + auto i = m->impl.find(QPDFObjectHandle::newInteger(key), return_prev_if_not_found); | |
| 1189 | + return {std::make_shared<NNTreeIterator>(i)}; | |
| 1190 | +} | |
| 1191 | + | |
| 1192 | +QPDFNumberTreeObjectHelper::iterator | |
| 1193 | +QPDFNumberTreeObjectHelper::insert(numtree_number key, QPDFObjectHandle value) | |
| 1194 | +{ | |
| 1195 | + auto i = m->impl.insert(QPDFObjectHandle::newInteger(key), value); | |
| 1196 | + return {std::make_shared<NNTreeIterator>(i)}; | |
| 1197 | +} | |
| 1198 | + | |
| 1199 | +bool | |
| 1200 | +QPDFNumberTreeObjectHelper::remove(numtree_number key, QPDFObjectHandle* value) | |
| 1201 | +{ | |
| 1202 | + return m->impl.remove(QPDFObjectHandle::newInteger(key), value); | |
| 1203 | +} | |
| 1204 | + | |
| 1205 | +QPDFNumberTreeObjectHelper::numtree_number | |
| 1206 | +QPDFNumberTreeObjectHelper::getMin() | |
| 1207 | +{ | |
| 1208 | + auto i = begin(); | |
| 1209 | + if (i == end()) { | |
| 1210 | + return 0; | |
| 1211 | + } | |
| 1212 | + return i->first; | |
| 1213 | +} | |
| 1214 | + | |
| 1215 | +QPDFNumberTreeObjectHelper::numtree_number | |
| 1216 | +QPDFNumberTreeObjectHelper::getMax() | |
| 1217 | +{ | |
| 1218 | + auto i = last(); | |
| 1219 | + if (i == end()) { | |
| 1220 | + return 0; | |
| 1221 | + } | |
| 1222 | + return i->first; | |
| 1223 | +} | |
| 1224 | + | |
| 1225 | +bool | |
| 1226 | +QPDFNumberTreeObjectHelper::hasIndex(numtree_number idx) | |
| 1227 | +{ | |
| 1228 | + auto i = find(idx); | |
| 1229 | + return (i != this->end()); | |
| 1230 | +} | |
| 1231 | + | |
| 1232 | +bool | |
| 1233 | +QPDFNumberTreeObjectHelper::findObject(numtree_number idx, QPDFObjectHandle& oh) | |
| 1234 | +{ | |
| 1235 | + auto i = find(idx); | |
| 1236 | + if (i == end()) { | |
| 1237 | + return false; | |
| 1238 | + } | |
| 1239 | + oh = i->second; | |
| 1240 | + return true; | |
| 1241 | +} | |
| 1242 | + | |
| 1243 | +bool | |
| 1244 | +QPDFNumberTreeObjectHelper::findObjectAtOrBelow( | |
| 1245 | + numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset) | |
| 1246 | +{ | |
| 1247 | + auto i = find(idx, true); | |
| 1248 | + if (i == end()) { | |
| 1249 | + return false; | |
| 1250 | + } | |
| 1251 | + oh = i->second; | |
| 1252 | + QIntC::range_check_subtract(idx, i->first); | |
| 1253 | + offset = idx - i->first; | |
| 1254 | + return true; | |
| 1255 | +} | |
| 1256 | + | |
| 1257 | +void | |
| 1258 | +QPDFNumberTreeObjectHelper::setSplitThreshold(int t) | |
| 1259 | +{ | |
| 1260 | + m->impl.setSplitThreshold(t); | |
| 1261 | +} | |
| 1262 | + | |
| 1263 | +std::map<QPDFNumberTreeObjectHelper::numtree_number, QPDFObjectHandle> | |
| 1264 | +QPDFNumberTreeObjectHelper::getAsMap() const | |
| 1265 | +{ | |
| 1266 | + std::map<numtree_number, QPDFObjectHandle> result; | |
| 1267 | + result.insert(begin(), end()); | |
| 1268 | + return result; | |
| 1269 | +} | |
| 1270 | + | |
| 1271 | +bool | |
| 1272 | +QPDFNumberTreeObjectHelper::validate(bool repair) | |
| 1273 | +{ | |
| 1274 | + return m->impl.validate(repair); | |
| 1275 | +} | ... | ... |
libqpdf/QPDFNameTreeObjectHelper.cc
| 1 | -#include <qpdf/QPDFNameTreeObjectHelper.hh> | |
| 2 | - | |
| 3 | -#include <qpdf/NNTree.hh> | |
| 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) | |
| 38 | -{ | |
| 39 | - // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | |
| 40 | - // class, see github issue #745. | |
| 41 | -} | |
| 42 | - | |
| 43 | -QPDFNameTreeObjectHelper::Members::Members( | |
| 44 | - QPDFObjectHandle& oh, | |
| 45 | - QPDF& q, | |
| 46 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 47 | - bool auto_repair) : | |
| 48 | - impl(std::make_shared<NNTreeImpl>(name_tree_details, q, oh, value_validator, auto_repair)) | |
| 49 | -{ | |
| 50 | -} | |
| 51 | - | |
| 52 | -QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper(QPDFObjectHandle oh, QPDF& q, bool auto_repair) : | |
| 53 | - QPDFObjectHelper(oh), | |
| 54 | - m(new Members( | |
| 55 | - oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair)) | |
| 56 | -{ | |
| 57 | -} | |
| 58 | - | |
| 59 | -QPDFNameTreeObjectHelper::QPDFNameTreeObjectHelper( | |
| 60 | - QPDFObjectHandle oh, | |
| 61 | - QPDF& q, | |
| 62 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 63 | - bool auto_repair) : | |
| 64 | - QPDFObjectHelper(oh), | |
| 65 | - m(new Members(oh, q, value_validator, auto_repair)) | |
| 66 | -{ | |
| 67 | -} | |
| 68 | - | |
| 69 | -QPDFNameTreeObjectHelper | |
| 70 | -QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) | |
| 71 | -{ | |
| 72 | - return {qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair}; | |
| 73 | -} | |
| 74 | - | |
| 75 | -QPDFNameTreeObjectHelper::iterator::iterator(std::shared_ptr<NNTreeIterator> const& i) : | |
| 76 | - impl(i) | |
| 77 | -{ | |
| 78 | -} | |
| 79 | - | |
| 80 | -bool | |
| 81 | -QPDFNameTreeObjectHelper::iterator::valid() const | |
| 82 | -{ | |
| 83 | - return impl->valid(); | |
| 84 | -} | |
| 85 | - | |
| 86 | -QPDFNameTreeObjectHelper::iterator& | |
| 87 | -QPDFNameTreeObjectHelper::iterator::operator++() | |
| 88 | -{ | |
| 89 | - ++(*impl); | |
| 90 | - updateIValue(); | |
| 91 | - return *this; | |
| 92 | -} | |
| 93 | - | |
| 94 | -QPDFNameTreeObjectHelper::iterator& | |
| 95 | -QPDFNameTreeObjectHelper::iterator::operator--() | |
| 96 | -{ | |
| 97 | - --(*impl); | |
| 98 | - updateIValue(); | |
| 99 | - return *this; | |
| 100 | -} | |
| 101 | - | |
| 102 | -void | |
| 103 | -QPDFNameTreeObjectHelper::iterator::updateIValue() | |
| 104 | -{ | |
| 105 | - if (impl->valid()) { | |
| 106 | - auto p = *impl; | |
| 107 | - ivalue.first = p->first.getUTF8Value(); | |
| 108 | - ivalue.second = p->second; | |
| 109 | - } else { | |
| 110 | - ivalue.first = ""; | |
| 111 | - ivalue.second = QPDFObjectHandle(); | |
| 112 | - } | |
| 113 | -} | |
| 114 | - | |
| 115 | -QPDFNameTreeObjectHelper::iterator::reference | |
| 116 | -QPDFNameTreeObjectHelper::iterator::operator*() | |
| 117 | -{ | |
| 118 | - updateIValue(); | |
| 119 | - return ivalue; | |
| 120 | -} | |
| 121 | - | |
| 122 | -QPDFNameTreeObjectHelper::iterator::pointer | |
| 123 | -QPDFNameTreeObjectHelper::iterator::operator->() | |
| 124 | -{ | |
| 125 | - updateIValue(); | |
| 126 | - return &ivalue; | |
| 127 | -} | |
| 128 | - | |
| 129 | -bool | |
| 130 | -QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 131 | -{ | |
| 132 | - return *(impl) == *(other.impl); | |
| 133 | -} | |
| 134 | - | |
| 135 | -void | |
| 136 | -QPDFNameTreeObjectHelper::iterator::insertAfter(std::string const& key, QPDFObjectHandle value) | |
| 137 | -{ | |
| 138 | - impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value); | |
| 139 | - updateIValue(); | |
| 140 | -} | |
| 141 | - | |
| 142 | -void | |
| 143 | -QPDFNameTreeObjectHelper::iterator::remove() | |
| 144 | -{ | |
| 145 | - impl->remove(); | |
| 146 | - updateIValue(); | |
| 147 | -} | |
| 148 | - | |
| 149 | -QPDFNameTreeObjectHelper::iterator | |
| 150 | -QPDFNameTreeObjectHelper::begin() const | |
| 151 | -{ | |
| 152 | - return {std::make_shared<NNTreeIterator>(m->impl->begin())}; | |
| 153 | -} | |
| 154 | - | |
| 155 | -QPDFNameTreeObjectHelper::iterator | |
| 156 | -QPDFNameTreeObjectHelper::end() const | |
| 157 | -{ | |
| 158 | - return {std::make_shared<NNTreeIterator>(m->impl->end())}; | |
| 159 | -} | |
| 160 | - | |
| 161 | -QPDFNameTreeObjectHelper::iterator | |
| 162 | -QPDFNameTreeObjectHelper::last() const | |
| 163 | -{ | |
| 164 | - return {std::make_shared<NNTreeIterator>(m->impl->last())}; | |
| 165 | -} | |
| 166 | - | |
| 167 | -QPDFNameTreeObjectHelper::iterator | |
| 168 | -QPDFNameTreeObjectHelper::find(std::string const& key, bool return_prev_if_not_found) | |
| 169 | -{ | |
| 170 | - auto i = m->impl->find(QPDFObjectHandle::newUnicodeString(key), return_prev_if_not_found); | |
| 171 | - return {std::make_shared<NNTreeIterator>(i)}; | |
| 172 | -} | |
| 173 | - | |
| 174 | -QPDFNameTreeObjectHelper::iterator | |
| 175 | -QPDFNameTreeObjectHelper::insert(std::string const& key, QPDFObjectHandle value) | |
| 176 | -{ | |
| 177 | - auto i = m->impl->insert(QPDFObjectHandle::newUnicodeString(key), value); | |
| 178 | - return {std::make_shared<NNTreeIterator>(i)}; | |
| 179 | -} | |
| 180 | - | |
| 181 | -bool | |
| 182 | -QPDFNameTreeObjectHelper::remove(std::string const& key, QPDFObjectHandle* value) | |
| 183 | -{ | |
| 184 | - return m->impl->remove(QPDFObjectHandle::newUnicodeString(key), value); | |
| 185 | -} | |
| 186 | - | |
| 187 | -bool | |
| 188 | -QPDFNameTreeObjectHelper::hasName(std::string const& name) | |
| 189 | -{ | |
| 190 | - auto i = find(name); | |
| 191 | - return (i != end()); | |
| 192 | -} | |
| 193 | - | |
| 194 | -bool | |
| 195 | -QPDFNameTreeObjectHelper::findObject(std::string const& name, QPDFObjectHandle& oh) | |
| 196 | -{ | |
| 197 | - auto i = find(name); | |
| 198 | - if (i == end()) { | |
| 199 | - return false; | |
| 200 | - } | |
| 201 | - oh = i->second; | |
| 202 | - return true; | |
| 203 | -} | |
| 204 | - | |
| 205 | -void | |
| 206 | -QPDFNameTreeObjectHelper::setSplitThreshold(int t) | |
| 207 | -{ | |
| 208 | - m->impl->setSplitThreshold(t); | |
| 209 | -} | |
| 210 | - | |
| 211 | -std::map<std::string, QPDFObjectHandle> | |
| 212 | -QPDFNameTreeObjectHelper::getAsMap() const | |
| 213 | -{ | |
| 214 | - std::map<std::string, QPDFObjectHandle> result; | |
| 215 | - result.insert(begin(), end()); | |
| 216 | - return result; | |
| 217 | -} | |
| 218 | - | |
| 219 | -bool | |
| 220 | -QPDFNameTreeObjectHelper::validate(bool repair) | |
| 221 | -{ | |
| 222 | - return m->impl->validate(repair); | |
| 223 | -} |
libqpdf/QPDFNumberTreeObjectHelper.cc
| 1 | -#include <qpdf/QPDFNumberTreeObjectHelper.hh> | |
| 2 | - | |
| 3 | -#include <qpdf/NNTree.hh> | |
| 4 | -#include <qpdf/QIntC.hh> | |
| 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) | |
| 39 | -{ | |
| 40 | - // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer. For this specific | |
| 41 | - // class, see github issue #745. | |
| 42 | -} | |
| 43 | - | |
| 44 | -QPDFNumberTreeObjectHelper::Members::Members( | |
| 45 | - QPDFObjectHandle& oh, | |
| 46 | - QPDF& q, | |
| 47 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 48 | - bool auto_repair) : | |
| 49 | - impl(std::make_shared<NNTreeImpl>(number_tree_details, q, oh, value_validator, auto_repair)) | |
| 50 | -{ | |
| 51 | -} | |
| 52 | - | |
| 53 | -QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( | |
| 54 | - QPDFObjectHandle oh, QPDF& q, bool auto_repair) : | |
| 55 | - QPDFObjectHelper(oh), | |
| 56 | - m(new Members( | |
| 57 | - oh, q, [](QPDFObjectHandle const& o) -> bool { return static_cast<bool>(o); }, auto_repair)) | |
| 58 | -{ | |
| 59 | -} | |
| 60 | - | |
| 61 | -QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper( | |
| 62 | - QPDFObjectHandle oh, | |
| 63 | - QPDF& q, | |
| 64 | - std::function<bool(QPDFObjectHandle const&)> value_validator, | |
| 65 | - bool auto_repair) : | |
| 66 | - QPDFObjectHelper(oh), | |
| 67 | - m(new Members(oh, q, value_validator, auto_repair)) | |
| 68 | -{ | |
| 69 | -} | |
| 70 | - | |
| 71 | -QPDFNumberTreeObjectHelper | |
| 72 | -QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) | |
| 73 | -{ | |
| 74 | - return {qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair}; | |
| 75 | -} | |
| 76 | - | |
| 77 | -QPDFNumberTreeObjectHelper::iterator::iterator(std::shared_ptr<NNTreeIterator> const& i) : | |
| 78 | - impl(i) | |
| 79 | -{ | |
| 80 | -} | |
| 81 | - | |
| 82 | -bool | |
| 83 | -QPDFNumberTreeObjectHelper::iterator::valid() const | |
| 84 | -{ | |
| 85 | - return impl->valid(); | |
| 86 | -} | |
| 87 | - | |
| 88 | -QPDFNumberTreeObjectHelper::iterator& | |
| 89 | -QPDFNumberTreeObjectHelper::iterator::operator++() | |
| 90 | -{ | |
| 91 | - ++(*impl); | |
| 92 | - updateIValue(); | |
| 93 | - return *this; | |
| 94 | -} | |
| 95 | - | |
| 96 | -QPDFNumberTreeObjectHelper::iterator& | |
| 97 | -QPDFNumberTreeObjectHelper::iterator::operator--() | |
| 98 | -{ | |
| 99 | - --(*impl); | |
| 100 | - updateIValue(); | |
| 101 | - return *this; | |
| 102 | -} | |
| 103 | - | |
| 104 | -void | |
| 105 | -QPDFNumberTreeObjectHelper::iterator::updateIValue() | |
| 106 | -{ | |
| 107 | - if (impl->valid()) { | |
| 108 | - auto p = *impl; | |
| 109 | - this->ivalue.first = p->first.getIntValue(); | |
| 110 | - this->ivalue.second = p->second; | |
| 111 | - } else { | |
| 112 | - this->ivalue.first = 0; | |
| 113 | - this->ivalue.second = QPDFObjectHandle(); | |
| 114 | - } | |
| 115 | -} | |
| 116 | - | |
| 117 | -QPDFNumberTreeObjectHelper::iterator::reference | |
| 118 | -QPDFNumberTreeObjectHelper::iterator::operator*() | |
| 119 | -{ | |
| 120 | - updateIValue(); | |
| 121 | - return this->ivalue; | |
| 122 | -} | |
| 123 | - | |
| 124 | -QPDFNumberTreeObjectHelper::iterator::pointer | |
| 125 | -QPDFNumberTreeObjectHelper::iterator::operator->() | |
| 126 | -{ | |
| 127 | - updateIValue(); | |
| 128 | - return &this->ivalue; | |
| 129 | -} | |
| 130 | - | |
| 131 | -bool | |
| 132 | -QPDFNumberTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 133 | -{ | |
| 134 | - return *(impl) == *(other.impl); | |
| 135 | -} | |
| 136 | - | |
| 137 | -void | |
| 138 | -QPDFNumberTreeObjectHelper::iterator::insertAfter(numtree_number key, QPDFObjectHandle value) | |
| 139 | -{ | |
| 140 | - impl->insertAfter(QPDFObjectHandle::newInteger(key), value); | |
| 141 | - updateIValue(); | |
| 142 | -} | |
| 143 | - | |
| 144 | -void | |
| 145 | -QPDFNumberTreeObjectHelper::iterator::remove() | |
| 146 | -{ | |
| 147 | - impl->remove(); | |
| 148 | - updateIValue(); | |
| 149 | -} | |
| 150 | - | |
| 151 | -QPDFNumberTreeObjectHelper::iterator | |
| 152 | -QPDFNumberTreeObjectHelper::begin() const | |
| 153 | -{ | |
| 154 | - return {std::make_shared<NNTreeIterator>(m->impl->begin())}; | |
| 155 | -} | |
| 156 | - | |
| 157 | -QPDFNumberTreeObjectHelper::iterator | |
| 158 | -QPDFNumberTreeObjectHelper::end() const | |
| 159 | -{ | |
| 160 | - return {std::make_shared<NNTreeIterator>(m->impl->end())}; | |
| 161 | -} | |
| 162 | - | |
| 163 | -QPDFNumberTreeObjectHelper::iterator | |
| 164 | -QPDFNumberTreeObjectHelper::last() const | |
| 165 | -{ | |
| 166 | - return {std::make_shared<NNTreeIterator>(m->impl->last())}; | |
| 167 | -} | |
| 168 | - | |
| 169 | -QPDFNumberTreeObjectHelper::iterator | |
| 170 | -QPDFNumberTreeObjectHelper::find(numtree_number key, bool return_prev_if_not_found) | |
| 171 | -{ | |
| 172 | - auto i = m->impl->find(QPDFObjectHandle::newInteger(key), return_prev_if_not_found); | |
| 173 | - return {std::make_shared<NNTreeIterator>(i)}; | |
| 174 | -} | |
| 175 | - | |
| 176 | -QPDFNumberTreeObjectHelper::iterator | |
| 177 | -QPDFNumberTreeObjectHelper::insert(numtree_number key, QPDFObjectHandle value) | |
| 178 | -{ | |
| 179 | - auto i = m->impl->insert(QPDFObjectHandle::newInteger(key), value); | |
| 180 | - return {std::make_shared<NNTreeIterator>(i)}; | |
| 181 | -} | |
| 182 | - | |
| 183 | -bool | |
| 184 | -QPDFNumberTreeObjectHelper::remove(numtree_number key, QPDFObjectHandle* value) | |
| 185 | -{ | |
| 186 | - return m->impl->remove(QPDFObjectHandle::newInteger(key), value); | |
| 187 | -} | |
| 188 | - | |
| 189 | -QPDFNumberTreeObjectHelper::numtree_number | |
| 190 | -QPDFNumberTreeObjectHelper::getMin() | |
| 191 | -{ | |
| 192 | - auto i = begin(); | |
| 193 | - if (i == end()) { | |
| 194 | - return 0; | |
| 195 | - } | |
| 196 | - return i->first; | |
| 197 | -} | |
| 198 | - | |
| 199 | -QPDFNumberTreeObjectHelper::numtree_number | |
| 200 | -QPDFNumberTreeObjectHelper::getMax() | |
| 201 | -{ | |
| 202 | - auto i = last(); | |
| 203 | - if (i == end()) { | |
| 204 | - return 0; | |
| 205 | - } | |
| 206 | - return i->first; | |
| 207 | -} | |
| 208 | - | |
| 209 | -bool | |
| 210 | -QPDFNumberTreeObjectHelper::hasIndex(numtree_number idx) | |
| 211 | -{ | |
| 212 | - auto i = find(idx); | |
| 213 | - return (i != this->end()); | |
| 214 | -} | |
| 215 | - | |
| 216 | -bool | |
| 217 | -QPDFNumberTreeObjectHelper::findObject(numtree_number idx, QPDFObjectHandle& oh) | |
| 218 | -{ | |
| 219 | - auto i = find(idx); | |
| 220 | - if (i == end()) { | |
| 221 | - return false; | |
| 222 | - } | |
| 223 | - oh = i->second; | |
| 224 | - return true; | |
| 225 | -} | |
| 226 | - | |
| 227 | -bool | |
| 228 | -QPDFNumberTreeObjectHelper::findObjectAtOrBelow( | |
| 229 | - numtree_number idx, QPDFObjectHandle& oh, numtree_number& offset) | |
| 230 | -{ | |
| 231 | - auto i = find(idx, true); | |
| 232 | - if (i == end()) { | |
| 233 | - return false; | |
| 234 | - } | |
| 235 | - oh = i->second; | |
| 236 | - QIntC::range_check_subtract(idx, i->first); | |
| 237 | - offset = idx - i->first; | |
| 238 | - return true; | |
| 239 | -} | |
| 240 | - | |
| 241 | -void | |
| 242 | -QPDFNumberTreeObjectHelper::setSplitThreshold(int t) | |
| 243 | -{ | |
| 244 | - m->impl->setSplitThreshold(t); | |
| 245 | -} | |
| 246 | - | |
| 247 | -std::map<QPDFNumberTreeObjectHelper::numtree_number, QPDFObjectHandle> | |
| 248 | -QPDFNumberTreeObjectHelper::getAsMap() const | |
| 249 | -{ | |
| 250 | - std::map<numtree_number, QPDFObjectHandle> result; | |
| 251 | - result.insert(begin(), end()); | |
| 252 | - return result; | |
| 253 | -} | |
| 254 | - | |
| 255 | -bool | |
| 256 | -QPDFNumberTreeObjectHelper::validate(bool repair) | |
| 257 | -{ | |
| 258 | - return m->impl->validate(repair); | |
| 259 | -} |
libqpdf/qpdf/NNTree.hh
| ... | ... | @@ -2,22 +2,14 @@ |
| 2 | 2 | #define NNTREE_HH |
| 3 | 3 | |
| 4 | 4 | #include <qpdf/QPDF.hh> |
| 5 | -#include <qpdf/QPDFObjectHandle.hh> | |
| 5 | +#include <qpdf/QPDFObjectHandle_private.hh> | |
| 6 | 6 | |
| 7 | 7 | #include <iterator> |
| 8 | 8 | #include <list> |
| 9 | 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 | 11 | class NNTreeImpl; |
| 20 | -class NNTreeIterator | |
| 12 | +class NNTreeIterator final | |
| 21 | 13 | { |
| 22 | 14 | friend class NNTreeImpl; |
| 23 | 15 | |
| ... | ... | @@ -29,9 +21,20 @@ class NNTreeIterator |
| 29 | 21 | using pointer = T*; |
| 30 | 22 | using reference = T&; |
| 31 | 23 | |
| 32 | - virtual ~NNTreeIterator() = default; | |
| 33 | - bool valid() const; | |
| 34 | - NNTreeIterator& operator++(); | |
| 24 | + ~NNTreeIterator() = default; | |
| 25 | + // iterator can be incremented or decremented, or dereferenced. This does not imply that it | |
| 26 | + // points to a valid item. | |
| 27 | + bool | |
| 28 | + valid() const | |
| 29 | + { | |
| 30 | + return item_number >= 0; | |
| 31 | + } | |
| 32 | + NNTreeIterator& | |
| 33 | + operator++() | |
| 34 | + { | |
| 35 | + increment(false); | |
| 36 | + return *this; | |
| 37 | + } | |
| 35 | 38 | NNTreeIterator |
| 36 | 39 | operator++(int) |
| 37 | 40 | { |
| ... | ... | @@ -39,7 +42,12 @@ class NNTreeIterator |
| 39 | 42 | ++(*this); |
| 40 | 43 | return t; |
| 41 | 44 | } |
| 42 | - NNTreeIterator& operator--(); | |
| 45 | + NNTreeIterator& | |
| 46 | + operator--() | |
| 47 | + { | |
| 48 | + increment(true); | |
| 49 | + return *this; | |
| 50 | + } | |
| 43 | 51 | NNTreeIterator |
| 44 | 52 | operator--(int) |
| 45 | 53 | { |
| ... | ... | @@ -47,8 +55,18 @@ class NNTreeIterator |
| 47 | 55 | --(*this); |
| 48 | 56 | return t; |
| 49 | 57 | } |
| 50 | - reference operator*(); | |
| 51 | - pointer operator->(); | |
| 58 | + reference | |
| 59 | + operator*() | |
| 60 | + { | |
| 61 | + updateIValue(false); | |
| 62 | + return ivalue; | |
| 63 | + } | |
| 64 | + pointer | |
| 65 | + operator->() | |
| 66 | + { | |
| 67 | + updateIValue(false); | |
| 68 | + return &ivalue; | |
| 69 | + } | |
| 52 | 70 | bool operator==(NNTreeIterator const& other) const; |
| 53 | 71 | bool |
| 54 | 72 | operator!=(NNTreeIterator const& other) const |
| ... | ... | @@ -69,11 +87,24 @@ class NNTreeIterator |
| 69 | 87 | int kid_number; |
| 70 | 88 | }; |
| 71 | 89 | |
| 72 | - NNTreeIterator(NNTreeImpl& impl); | |
| 90 | + NNTreeIterator(NNTreeImpl& impl) : | |
| 91 | + impl(impl) | |
| 92 | + { | |
| 93 | + } | |
| 73 | 94 | void updateIValue(bool allow_invalid = true); |
| 74 | 95 | bool deepen(QPDFObjectHandle node, bool first, bool allow_empty); |
| 75 | - void setItemNumber(QPDFObjectHandle const& node, int); | |
| 76 | - void addPathElement(QPDFObjectHandle const& node, int kid_number); | |
| 96 | + void | |
| 97 | + setItemNumber(QPDFObjectHandle const& a_node, int n) | |
| 98 | + { | |
| 99 | + node = a_node; | |
| 100 | + item_number = n; | |
| 101 | + updateIValue(); | |
| 102 | + } | |
| 103 | + void | |
| 104 | + addPathElement(QPDFObjectHandle const& a_node, int kid_number) | |
| 105 | + { | |
| 106 | + path.emplace_back(a_node, kid_number); | |
| 107 | + } | |
| 77 | 108 | QPDFObjectHandle getNextKid(PathElement& element, bool backward); |
| 78 | 109 | void increment(bool backward); |
| 79 | 110 | void resetLimits(QPDFObjectHandle node, std::list<PathElement>::iterator parent); |
| ... | ... | @@ -88,7 +119,7 @@ class NNTreeIterator |
| 88 | 119 | value_type ivalue; |
| 89 | 120 | }; |
| 90 | 121 | |
| 91 | -class NNTreeImpl | |
| 122 | +class NNTreeImpl final | |
| 92 | 123 | { |
| 93 | 124 | friend class NNTreeIterator; |
| 94 | 125 | |
| ... | ... | @@ -96,13 +127,25 @@ class NNTreeImpl |
| 96 | 127 | typedef NNTreeIterator iterator; |
| 97 | 128 | |
| 98 | 129 | NNTreeImpl( |
| 99 | - NNTreeDetails const&, | |
| 100 | - QPDF&, | |
| 101 | - QPDFObjectHandle&, | |
| 130 | + QPDF& qpdf, | |
| 131 | + QPDFObjectHandle& oh, | |
| 132 | + qpdf_object_type_e key_type, | |
| 102 | 133 | std::function<bool(QPDFObjectHandle const&)> value_validator, |
| 103 | - bool auto_repair = true); | |
| 134 | + bool auto_repair) : | |
| 135 | + qpdf(qpdf), | |
| 136 | + oh(oh), | |
| 137 | + key_type(key_type), | |
| 138 | + items_key(key_type == ::ot_string ? "/Names" : "/Nums"), | |
| 139 | + value_valid(value_validator), | |
| 140 | + auto_repair(auto_repair) | |
| 141 | + { | |
| 142 | + } | |
| 104 | 143 | iterator begin(); |
| 105 | - iterator end(); | |
| 144 | + iterator | |
| 145 | + end() | |
| 146 | + { | |
| 147 | + return {*this}; | |
| 148 | + } | |
| 106 | 149 | iterator last(); |
| 107 | 150 | iterator find(QPDFObjectHandle key, bool return_prev_if_not_found = false); |
| 108 | 151 | iterator insertFirst(QPDFObjectHandle const& key, QPDFObjectHandle const& value); |
| ... | ... | @@ -113,27 +156,44 @@ class NNTreeImpl |
| 113 | 156 | |
| 114 | 157 | // Change the split threshold for easier testing. There's no real reason to expose this to |
| 115 | 158 | // downstream tree helpers, but it has to be public so we can call it from the test suite. |
| 116 | - void setSplitThreshold(int split_threshold); | |
| 159 | + void | |
| 160 | + setSplitThreshold(int threshold) | |
| 161 | + { | |
| 162 | + split_threshold = threshold; | |
| 163 | + } | |
| 117 | 164 | |
| 118 | 165 | private: |
| 119 | 166 | void repair(); |
| 120 | 167 | iterator findInternal(QPDFObjectHandle const& key, bool return_prev_if_not_found = false); |
| 121 | - int withinLimits(QPDFObjectHandle const& key, QPDFObjectHandle const& node); | |
| 122 | 168 | int binarySearch( |
| 123 | - QPDFObjectHandle key, | |
| 124 | - QPDFObjectHandle items, | |
| 169 | + QPDFObjectHandle const& key, | |
| 170 | + qpdf::Array const& items, | |
| 125 | 171 | size_t num_items, |
| 126 | 172 | bool return_prev_if_not_found, |
| 127 | - int (NNTreeImpl::*compare)(QPDFObjectHandle& key, QPDFObjectHandle& arr, int item)); | |
| 128 | - int compareKeyItem(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx); | |
| 129 | - int compareKeyKid(QPDFObjectHandle& key, QPDFObjectHandle& items, int idx); | |
| 173 | + int (NNTreeImpl::*compare)(QPDFObjectHandle const& key, qpdf::Array const& arr, int item) | |
| 174 | + const) const; | |
| 175 | + int compareKeyItem(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; | |
| 176 | + int compareKeyKid(QPDFObjectHandle const& key, qpdf::Array const& items, int idx) const; | |
| 130 | 177 | void warn(QPDFObjectHandle const& node, std::string const& msg); |
| 131 | - void error(QPDFObjectHandle const& node, std::string const& msg); | |
| 178 | + void error(QPDFObjectHandle const& node, std::string const& msg) const; | |
| 179 | + | |
| 180 | + std::string const& | |
| 181 | + itemsKey() const | |
| 182 | + { | |
| 183 | + return items_key; | |
| 184 | + } | |
| 185 | + bool | |
| 186 | + keyValid(QPDFObjectHandle o) const | |
| 187 | + { | |
| 188 | + return o.resolved_type_code() == key_type; | |
| 189 | + } | |
| 190 | + int compareKeys(QPDFObjectHandle a, QPDFObjectHandle b) const; | |
| 132 | 191 | |
| 133 | - NNTreeDetails const& details; | |
| 134 | 192 | QPDF& qpdf; |
| 135 | 193 | int split_threshold{32}; |
| 136 | 194 | QPDFObjectHandle oh; |
| 195 | + const qpdf_object_type_e key_type; | |
| 196 | + const std::string items_key; | |
| 137 | 197 | const std::function<bool(QPDFObjectHandle const&)> value_valid; |
| 138 | 198 | bool auto_repair{true}; |
| 139 | 199 | size_t error_count{0}; | ... | ... |