Commit 5f0708418a0a9cbacc033f52efc11c759120fd09
1 parent
4a1cce0a
Add iterators to name/number tree helpers
Showing
10 changed files
with
628 additions
and
45 deletions
include/qpdf/QPDFNameTreeObjectHelper.hh
| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | #include <qpdf/QPDFObjGen.hh> |
| 27 | 27 | #include <map> |
| 28 | 28 | #include <memory> |
| 29 | +#include <iterator> | |
| 29 | 30 | |
| 30 | 31 | #include <qpdf/DLL.h> |
| 31 | 32 | |
| ... | ... | @@ -35,6 +36,8 @@ |
| 35 | 36 | // normalized for lookup purposes. |
| 36 | 37 | |
| 37 | 38 | class NNTreeImpl; |
| 39 | +class NNTreeIterator; | |
| 40 | +class NNTreeDetails; | |
| 38 | 41 | |
| 39 | 42 | class QPDFNameTreeObjectHelper: public QPDFObjectHelper |
| 40 | 43 | { |
| ... | ... | @@ -54,6 +57,66 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper |
| 54 | 57 | QPDF_DLL |
| 55 | 58 | bool findObject(std::string const& utf8, QPDFObjectHandle& oh); |
| 56 | 59 | |
| 60 | + class iterator: public std::iterator< | |
| 61 | + std::bidirectional_iterator_tag, | |
| 62 | + std::pair<std::string, QPDFObjectHandle>, | |
| 63 | + void, | |
| 64 | + std::pair<std::string, QPDFObjectHandle>*, | |
| 65 | + std::pair<std::string, QPDFObjectHandle>> | |
| 66 | + { | |
| 67 | + friend class QPDFNameTreeObjectHelper; | |
| 68 | + public: | |
| 69 | + QPDF_DLL | |
| 70 | + bool valid() const; | |
| 71 | + QPDF_DLL | |
| 72 | + iterator& operator++(); | |
| 73 | + QPDF_DLL | |
| 74 | + iterator operator++(int) | |
| 75 | + { | |
| 76 | + iterator t = *this; | |
| 77 | + ++(*this); | |
| 78 | + return t; | |
| 79 | + } | |
| 80 | + QPDF_DLL | |
| 81 | + iterator& operator--(); | |
| 82 | + QPDF_DLL | |
| 83 | + iterator operator--(int) | |
| 84 | + { | |
| 85 | + iterator t = *this; | |
| 86 | + --(*this); | |
| 87 | + return t; | |
| 88 | + } | |
| 89 | + QPDF_DLL | |
| 90 | + reference operator*(); | |
| 91 | + QPDF_DLL | |
| 92 | + bool operator==(iterator const& other) const; | |
| 93 | + QPDF_DLL | |
| 94 | + bool operator!=(iterator const& other) const | |
| 95 | + { | |
| 96 | + return ! operator==(other); | |
| 97 | + } | |
| 98 | + | |
| 99 | + private: | |
| 100 | + iterator(std::shared_ptr<NNTreeIterator> const&); | |
| 101 | + std::shared_ptr<NNTreeIterator> impl; | |
| 102 | + }; | |
| 103 | + | |
| 104 | + // The iterator looks like map iterator, so i.first is a string | |
| 105 | + // and i.second is a QPDFObjectHandle. | |
| 106 | + QPDF_DLL | |
| 107 | + iterator begin() const; | |
| 108 | + QPDF_DLL | |
| 109 | + iterator end() const; | |
| 110 | + // Return a bidirectional iterator that points to the last item. | |
| 111 | + QPDF_DLL | |
| 112 | + iterator last() const; | |
| 113 | + | |
| 114 | + // Find the entry with the given key. If return_prev_if_not_found | |
| 115 | + // is true and the item is not found, return the next lower item. | |
| 116 | + QPDF_DLL | |
| 117 | + iterator find(std::string const& key, | |
| 118 | + bool return_prev_if_not_found = false); | |
| 119 | + | |
| 57 | 120 | // Return the contents of the name tree as a map. Note that name |
| 58 | 121 | // trees may be very large, so this may use a lot of RAM. It is |
| 59 | 122 | // more efficient to use QPDFNameTreeObjectHelper's iterator. | ... | ... |
include/qpdf/QPDFNumberTreeObjectHelper.hh
| ... | ... | @@ -33,6 +33,8 @@ |
| 33 | 33 | // PDF spec (ISO 32000) for a description of number trees. |
| 34 | 34 | |
| 35 | 35 | class NNTreeImpl; |
| 36 | +class NNTreeIterator; | |
| 37 | +class NNTreeDetails; | |
| 36 | 38 | |
| 37 | 39 | class QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 38 | 40 | { |
| ... | ... | @@ -73,6 +75,65 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 73 | 75 | bool findObjectAtOrBelow(numtree_number idx, QPDFObjectHandle& oh, |
| 74 | 76 | numtree_number& offset); |
| 75 | 77 | |
| 78 | + class iterator: public std::iterator< | |
| 79 | + std::bidirectional_iterator_tag, | |
| 80 | + std::pair<numtree_number, QPDFObjectHandle>, | |
| 81 | + void, | |
| 82 | + std::pair<numtree_number, QPDFObjectHandle>*, | |
| 83 | + std::pair<numtree_number, QPDFObjectHandle>> | |
| 84 | + { | |
| 85 | + friend class QPDFNumberTreeObjectHelper; | |
| 86 | + public: | |
| 87 | + QPDF_DLL | |
| 88 | + bool valid() const; | |
| 89 | + QPDF_DLL | |
| 90 | + iterator& operator++(); | |
| 91 | + QPDF_DLL | |
| 92 | + iterator operator++(int) | |
| 93 | + { | |
| 94 | + iterator t = *this; | |
| 95 | + ++(*this); | |
| 96 | + return t; | |
| 97 | + } | |
| 98 | + QPDF_DLL | |
| 99 | + iterator& operator--(); | |
| 100 | + QPDF_DLL | |
| 101 | + iterator operator--(int) | |
| 102 | + { | |
| 103 | + iterator t = *this; | |
| 104 | + --(*this); | |
| 105 | + return t; | |
| 106 | + } | |
| 107 | + QPDF_DLL | |
| 108 | + reference operator*(); | |
| 109 | + QPDF_DLL | |
| 110 | + bool operator==(iterator const& other) const; | |
| 111 | + QPDF_DLL | |
| 112 | + bool operator!=(iterator const& other) const | |
| 113 | + { | |
| 114 | + return ! operator==(other); | |
| 115 | + } | |
| 116 | + | |
| 117 | + private: | |
| 118 | + iterator(std::shared_ptr<NNTreeIterator> const&); | |
| 119 | + std::shared_ptr<NNTreeIterator> impl; | |
| 120 | + }; | |
| 121 | + | |
| 122 | + // The iterator looks like map iterator, so i.first is a string | |
| 123 | + // and i.second is a QPDFObjectHandle. | |
| 124 | + QPDF_DLL | |
| 125 | + iterator begin() const; | |
| 126 | + QPDF_DLL | |
| 127 | + iterator end() const; | |
| 128 | + // Return a bidirectional iterator that points to the last item. | |
| 129 | + QPDF_DLL | |
| 130 | + iterator last() const; | |
| 131 | + | |
| 132 | + // Find the entry with the given key. If return_prev_if_not_found | |
| 133 | + // is true and the item is not found, return the next lower item. | |
| 134 | + QPDF_DLL | |
| 135 | + iterator find(numtree_number key, bool return_prev_if_not_found = false); | |
| 136 | + | |
| 76 | 137 | // Return the contents of the number tree as a map. Note that |
| 77 | 138 | // number trees may be very large, so this may use a lot of RAM. |
| 78 | 139 | // It is more efficient to use QPDFNumberTreeObjectHelper's | ... | ... |
libqpdf/QPDFNameTreeObjectHelper.cc
| ... | ... | @@ -48,19 +48,85 @@ QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() |
| 48 | 48 | { |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | +QPDFNameTreeObjectHelper::iterator::iterator( | |
| 52 | + std::shared_ptr<NNTreeIterator> const& i) : | |
| 53 | + impl(i) | |
| 54 | +{ | |
| 55 | +} | |
| 56 | + | |
| 57 | +bool | |
| 58 | +QPDFNameTreeObjectHelper::iterator::valid() const | |
| 59 | +{ | |
| 60 | + return impl->valid(); | |
| 61 | +} | |
| 62 | + | |
| 63 | +QPDFNameTreeObjectHelper::iterator& | |
| 64 | +QPDFNameTreeObjectHelper::iterator::operator++() | |
| 65 | +{ | |
| 66 | + ++(*impl); | |
| 67 | + return *this; | |
| 68 | +} | |
| 69 | + | |
| 70 | +QPDFNameTreeObjectHelper::iterator& | |
| 71 | +QPDFNameTreeObjectHelper::iterator::operator--() | |
| 72 | +{ | |
| 73 | + --(*impl); | |
| 74 | + return *this; | |
| 75 | +} | |
| 76 | + | |
| 77 | +QPDFNameTreeObjectHelper::iterator::reference | |
| 78 | +QPDFNameTreeObjectHelper::iterator::operator*() | |
| 79 | +{ | |
| 80 | + auto p = **impl; | |
| 81 | + return std::make_pair(p.first.getUTF8Value(), p.second); | |
| 82 | +} | |
| 83 | + | |
| 84 | +bool | |
| 85 | +QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 86 | +{ | |
| 87 | + return *(impl) == *(other.impl); | |
| 88 | +} | |
| 89 | + | |
| 90 | +QPDFNameTreeObjectHelper::iterator | |
| 91 | +QPDFNameTreeObjectHelper::begin() const | |
| 92 | +{ | |
| 93 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->begin())); | |
| 94 | +} | |
| 95 | + | |
| 96 | +QPDFNameTreeObjectHelper::iterator | |
| 97 | +QPDFNameTreeObjectHelper::end() const | |
| 98 | +{ | |
| 99 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->end())); | |
| 100 | +} | |
| 101 | + | |
| 102 | +QPDFNameTreeObjectHelper::iterator | |
| 103 | +QPDFNameTreeObjectHelper::last() const | |
| 104 | +{ | |
| 105 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->last())); | |
| 106 | +} | |
| 107 | + | |
| 108 | +QPDFNameTreeObjectHelper::iterator | |
| 109 | +QPDFNameTreeObjectHelper::find(std::string const& key, | |
| 110 | + bool return_prev_if_not_found) | |
| 111 | +{ | |
| 112 | + auto i = this->m->impl->find(QPDFObjectHandle::newUnicodeString(key), | |
| 113 | + return_prev_if_not_found); | |
| 114 | + return iterator(std::make_shared<NNTreeIterator>(i)); | |
| 115 | +} | |
| 116 | + | |
| 51 | 117 | bool |
| 52 | 118 | QPDFNameTreeObjectHelper::hasName(std::string const& name) |
| 53 | 119 | { |
| 54 | - auto i = this->m->impl->find(QPDFObjectHandle::newUnicodeString(name)); | |
| 55 | - return (i != this->m->impl->end()); | |
| 120 | + auto i = find(name); | |
| 121 | + return (i != end()); | |
| 56 | 122 | } |
| 57 | 123 | |
| 58 | 124 | bool |
| 59 | 125 | QPDFNameTreeObjectHelper::findObject( |
| 60 | 126 | std::string const& name, QPDFObjectHandle& oh) |
| 61 | 127 | { |
| 62 | - auto i = this->m->impl->find(QPDFObjectHandle::newUnicodeString(name)); | |
| 63 | - if (i == this->m->impl->end()) | |
| 128 | + auto i = find(name); | |
| 129 | + if (i == end()) | |
| 64 | 130 | { |
| 65 | 131 | return false; |
| 66 | 132 | } |
| ... | ... | @@ -72,11 +138,6 @@ std::map<std::string, QPDFObjectHandle> |
| 72 | 138 | QPDFNameTreeObjectHelper::getAsMap() const |
| 73 | 139 | { |
| 74 | 140 | std::map<std::string, QPDFObjectHandle> result; |
| 75 | - for (auto i: *(this->m->impl)) | |
| 76 | - { | |
| 77 | - result.insert( | |
| 78 | - std::make_pair(i.first.getUTF8Value(), | |
| 79 | - i.second)); | |
| 80 | - } | |
| 141 | + result.insert(begin(), end()); | |
| 81 | 142 | return result; |
| 82 | 143 | } | ... | ... |
libqpdf/QPDFNumberTreeObjectHelper.cc
| ... | ... | @@ -44,41 +44,107 @@ QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper(QPDFObjectHandle oh) : |
| 44 | 44 | { |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | +QPDFNumberTreeObjectHelper::iterator::iterator( | |
| 48 | + std::shared_ptr<NNTreeIterator> const& i) : | |
| 49 | + impl(i) | |
| 50 | +{ | |
| 51 | +} | |
| 52 | + | |
| 53 | +bool | |
| 54 | +QPDFNumberTreeObjectHelper::iterator::valid() const | |
| 55 | +{ | |
| 56 | + return impl->valid(); | |
| 57 | +} | |
| 58 | + | |
| 59 | +QPDFNumberTreeObjectHelper::iterator& | |
| 60 | +QPDFNumberTreeObjectHelper::iterator::operator++() | |
| 61 | +{ | |
| 62 | + ++(*impl); | |
| 63 | + return *this; | |
| 64 | +} | |
| 65 | + | |
| 66 | +QPDFNumberTreeObjectHelper::iterator& | |
| 67 | +QPDFNumberTreeObjectHelper::iterator::operator--() | |
| 68 | +{ | |
| 69 | + --(*impl); | |
| 70 | + return *this; | |
| 71 | +} | |
| 72 | + | |
| 73 | +QPDFNumberTreeObjectHelper::iterator::reference | |
| 74 | +QPDFNumberTreeObjectHelper::iterator::operator*() | |
| 75 | +{ | |
| 76 | + auto p = **impl; | |
| 77 | + return std::make_pair(p.first.getIntValue(), p.second); | |
| 78 | +} | |
| 79 | + | |
| 80 | +bool | |
| 81 | +QPDFNumberTreeObjectHelper::iterator::operator==(iterator const& other) const | |
| 82 | +{ | |
| 83 | + return *(impl) == *(other.impl); | |
| 84 | +} | |
| 85 | + | |
| 86 | +QPDFNumberTreeObjectHelper::iterator | |
| 87 | +QPDFNumberTreeObjectHelper::begin() const | |
| 88 | +{ | |
| 89 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->begin())); | |
| 90 | +} | |
| 91 | + | |
| 92 | +QPDFNumberTreeObjectHelper::iterator | |
| 93 | +QPDFNumberTreeObjectHelper::end() const | |
| 94 | +{ | |
| 95 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->end())); | |
| 96 | +} | |
| 97 | + | |
| 98 | +QPDFNumberTreeObjectHelper::iterator | |
| 99 | +QPDFNumberTreeObjectHelper::last() const | |
| 100 | +{ | |
| 101 | + return iterator(std::make_shared<NNTreeIterator>(this->m->impl->last())); | |
| 102 | +} | |
| 103 | + | |
| 104 | +QPDFNumberTreeObjectHelper::iterator | |
| 105 | +QPDFNumberTreeObjectHelper::find(numtree_number key, | |
| 106 | + bool return_prev_if_not_found) | |
| 107 | +{ | |
| 108 | + auto i = this->m->impl->find(QPDFObjectHandle::newInteger(key), | |
| 109 | + return_prev_if_not_found); | |
| 110 | + return iterator(std::make_shared<NNTreeIterator>(i)); | |
| 111 | +} | |
| 112 | + | |
| 47 | 113 | QPDFNumberTreeObjectHelper::numtree_number |
| 48 | 114 | QPDFNumberTreeObjectHelper::getMin() |
| 49 | 115 | { |
| 50 | - auto i = this->m->impl->begin(); | |
| 51 | - if (i == this->m->impl->end()) | |
| 116 | + auto i = begin(); | |
| 117 | + if (i == end()) | |
| 52 | 118 | { |
| 53 | 119 | return 0; |
| 54 | 120 | } |
| 55 | - return (*i).first.getIntValue(); | |
| 121 | + return (*i).first; | |
| 56 | 122 | } |
| 57 | 123 | |
| 58 | 124 | QPDFNumberTreeObjectHelper::numtree_number |
| 59 | 125 | QPDFNumberTreeObjectHelper::getMax() |
| 60 | 126 | { |
| 61 | - auto i = this->m->impl->last(); | |
| 62 | - if (i == this->m->impl->end()) | |
| 127 | + auto i = last(); | |
| 128 | + if (i == end()) | |
| 63 | 129 | { |
| 64 | 130 | return 0; |
| 65 | 131 | } |
| 66 | - return (*i).first.getIntValue(); | |
| 132 | + return (*i).first; | |
| 67 | 133 | } |
| 68 | 134 | |
| 69 | 135 | bool |
| 70 | 136 | QPDFNumberTreeObjectHelper::hasIndex(numtree_number idx) |
| 71 | 137 | { |
| 72 | - auto i = this->m->impl->find(QPDFObjectHandle::newInteger(idx)); | |
| 73 | - return (i != this->m->impl->end()); | |
| 138 | + auto i = find(idx); | |
| 139 | + return (i != this->end()); | |
| 74 | 140 | } |
| 75 | 141 | |
| 76 | 142 | bool |
| 77 | 143 | QPDFNumberTreeObjectHelper::findObject( |
| 78 | 144 | numtree_number idx, QPDFObjectHandle& oh) |
| 79 | 145 | { |
| 80 | - auto i = this->m->impl->find(QPDFObjectHandle::newInteger(idx)); | |
| 81 | - if (i == this->m->impl->end()) | |
| 146 | + auto i = find(idx); | |
| 147 | + if (i == end()) | |
| 82 | 148 | { |
| 83 | 149 | return false; |
| 84 | 150 | } |
| ... | ... | @@ -91,13 +157,13 @@ QPDFNumberTreeObjectHelper::findObjectAtOrBelow( |
| 91 | 157 | numtree_number idx, QPDFObjectHandle& oh, |
| 92 | 158 | numtree_number& offset) |
| 93 | 159 | { |
| 94 | - auto i = this->m->impl->find(QPDFObjectHandle::newInteger(idx), true); | |
| 95 | - if (i == this->m->impl->end()) | |
| 160 | + auto i = find(idx, true); | |
| 161 | + if (i == end()) | |
| 96 | 162 | { |
| 97 | 163 | return false; |
| 98 | 164 | } |
| 99 | 165 | oh = (*i).second; |
| 100 | - offset = idx - (*i).first.getIntValue(); | |
| 166 | + offset = idx - (*i).first; | |
| 101 | 167 | return true; |
| 102 | 168 | } |
| 103 | 169 | |
| ... | ... | @@ -105,11 +171,6 @@ std::map<QPDFNumberTreeObjectHelper::numtree_number, QPDFObjectHandle> |
| 105 | 171 | QPDFNumberTreeObjectHelper::getAsMap() const |
| 106 | 172 | { |
| 107 | 173 | std::map<numtree_number, QPDFObjectHandle> result; |
| 108 | - for (auto i: *(this->m->impl)) | |
| 109 | - { | |
| 110 | - result.insert( | |
| 111 | - std::make_pair(i.first.getIntValue(), | |
| 112 | - i.second)); | |
| 113 | - } | |
| 174 | + result.insert(begin(), end()); | |
| 114 | 175 | return result; |
| 115 | 176 | } | ... | ... |
libtests/nntree.cc
| 1 | 1 | #include <qpdf/QPDFNumberTreeObjectHelper.hh> |
| 2 | +#include <qpdf/QPDFNameTreeObjectHelper.hh> | |
| 2 | 3 | #include <qpdf/QPDF.hh> |
| 3 | 4 | #include <qpdf/QUtil.hh> |
| 4 | 5 | #include <iostream> |
| 5 | 6 | |
| 7 | +static bool any_failures = false; | |
| 8 | + | |
| 6 | 9 | bool report(QPDFObjectHandle oh, long long item, long long exp_item) |
| 7 | 10 | { |
| 8 | 11 | QPDFNumberTreeObjectHelper nh(oh); |
| ... | ... | @@ -56,7 +59,7 @@ bool report(QPDFObjectHandle oh, long long item, long long exp_item) |
| 56 | 59 | return failed; |
| 57 | 60 | } |
| 58 | 61 | |
| 59 | -int main() | |
| 62 | +void test_bsearch() | |
| 60 | 63 | { |
| 61 | 64 | QPDF q; |
| 62 | 65 | q.emptyPDF(); |
| ... | ... | @@ -78,8 +81,7 @@ int main() |
| 78 | 81 | return node; |
| 79 | 82 | }; |
| 80 | 83 | |
| 81 | - bool any_failures = false; | |
| 82 | - auto r = [&any_failures](QPDFObjectHandle& oh, int item, int exp) { | |
| 84 | + auto r = [](QPDFObjectHandle& oh, int item, int exp) { | |
| 83 | 85 | if (report(oh, item, exp)) |
| 84 | 86 | { |
| 85 | 87 | any_failures = true; |
| ... | ... | @@ -119,6 +121,133 @@ int main() |
| 119 | 121 | |
| 120 | 122 | if (! any_failures) |
| 121 | 123 | { |
| 122 | - std::cout << "all tests passed" << std::endl; | |
| 124 | + std::cout << "bsearch tests passed" << std::endl; | |
| 125 | + } | |
| 126 | +} | |
| 127 | + | |
| 128 | +QPDFObjectHandle new_node(QPDF& q, std::string const& key) | |
| 129 | +{ | |
| 130 | + auto dict = QPDFObjectHandle::newDictionary(); | |
| 131 | + dict.replaceKey(key, QPDFObjectHandle::newArray()); | |
| 132 | + return q.makeIndirectObject(dict); | |
| 133 | +} | |
| 134 | + | |
| 135 | +static void check_find(QPDFNameTreeObjectHelper& nh, | |
| 136 | + std::string const& key, bool prev_if_not_found) | |
| 137 | +{ | |
| 138 | + auto i = nh.find(key, prev_if_not_found); | |
| 139 | + std::cout << "find " << key << " (" << prev_if_not_found << "): "; | |
| 140 | + if (i == nh.end()) | |
| 141 | + { | |
| 142 | + std::cout << "not found"; | |
| 143 | + } | |
| 144 | + else | |
| 145 | + { | |
| 146 | + std::cout << (*i).first << " -> " << (*i).second.unparse(); | |
| 147 | + } | |
| 148 | + std::cout << std::endl; | |
| 149 | +} | |
| 150 | + | |
| 151 | +void test_depth() | |
| 152 | +{ | |
| 153 | + int constexpr NITEMS = 3; | |
| 154 | + QPDF q; | |
| 155 | + q.emptyPDF(); | |
| 156 | + auto root = q.getRoot(); | |
| 157 | + auto n0 = new_node(q, "/Kids"); | |
| 158 | + root.replaceKey("/NT", n0); | |
| 159 | + auto k0 = root.getKey("/NT").getKey("/Kids"); | |
| 160 | + for (int i1 = 0; i1 < NITEMS; ++i1) | |
| 161 | + { | |
| 162 | + auto n1 = new_node(q, "/Kids"); | |
| 163 | + k0.appendItem(n1); | |
| 164 | + auto k1 = n1.getKey("/Kids"); | |
| 165 | + for (int i2 = 0; i2 < NITEMS; ++i2) | |
| 166 | + { | |
| 167 | + auto n2 = new_node(q, "/Kids"); | |
| 168 | + k1.appendItem(n2); | |
| 169 | + auto k2 = n2.getKey("/Kids"); | |
| 170 | + for (int i3 = 0; i3 < NITEMS; ++i3) | |
| 171 | + { | |
| 172 | + auto n3 = new_node(q, "/Names"); | |
| 173 | + k2.appendItem(n3); | |
| 174 | + auto items = n3.getKey("/Names"); | |
| 175 | + std::string first; | |
| 176 | + std::string last; | |
| 177 | + for (int i4 = 0; i4 < NITEMS; ++i4) | |
| 178 | + { | |
| 179 | + int val = (((((i1 | |
| 180 | + * NITEMS) + i2) | |
| 181 | + * NITEMS) + i3) | |
| 182 | + * NITEMS) + i4; | |
| 183 | + std::string str = QUtil::int_to_string(10 * val, 6); | |
| 184 | + items.appendItem( | |
| 185 | + QPDFObjectHandle::newString(str)); | |
| 186 | + items.appendItem( | |
| 187 | + QPDFObjectHandle::newString("val " + str)); | |
| 188 | + if (i4 == 0) | |
| 189 | + { | |
| 190 | + first = str; | |
| 191 | + } | |
| 192 | + else if (i4 == NITEMS - 1) | |
| 193 | + { | |
| 194 | + last = str; | |
| 195 | + } | |
| 196 | + } | |
| 197 | + auto limits = QPDFObjectHandle::newArray(); | |
| 198 | + n3.replaceKey("/Limits", limits); | |
| 199 | + limits.appendItem(QPDFObjectHandle::newString(first)); | |
| 200 | + limits.appendItem(QPDFObjectHandle::newString(last)); | |
| 201 | + } | |
| 202 | + auto limits = QPDFObjectHandle::newArray(); | |
| 203 | + n2.replaceKey("/Limits", limits); | |
| 204 | + limits.appendItem(k2.getArrayItem(0) | |
| 205 | + .getKey("/Limits") | |
| 206 | + .getArrayItem(0)); | |
| 207 | + limits.appendItem(k2.getArrayItem(NITEMS - 1) | |
| 208 | + .getKey("/Limits") | |
| 209 | + .getArrayItem(1)); | |
| 210 | + } | |
| 211 | + auto limits = QPDFObjectHandle::newArray(); | |
| 212 | + n1.replaceKey("/Limits", limits); | |
| 213 | + limits.appendItem(k1.getArrayItem(0) | |
| 214 | + .getKey("/Limits") | |
| 215 | + .getArrayItem(0)); | |
| 216 | + limits.appendItem(k1.getArrayItem(NITEMS - 1) | |
| 217 | + .getKey("/Limits") | |
| 218 | + .getArrayItem(1)); | |
| 123 | 219 | } |
| 220 | + | |
| 221 | + QPDFNameTreeObjectHelper nh(n0); | |
| 222 | + std::cout << "--- forward ---" << std::endl; | |
| 223 | + for (auto i: nh) | |
| 224 | + { | |
| 225 | + std::cout << i.first << " -> " | |
| 226 | + << i.second.unparse() << std::endl; | |
| 227 | + } | |
| 228 | + std::cout << "--- backward ---" << std::endl; | |
| 229 | + for (auto i = nh.last(); i.valid(); --i) | |
| 230 | + { | |
| 231 | + std::cout << (*i).first << " -> " | |
| 232 | + << (*i).second.unparse() << std::endl; | |
| 233 | + } | |
| 234 | + | |
| 235 | + // Find | |
| 236 | + check_find(nh, "000300", false); | |
| 237 | + check_find(nh, "000305", true); | |
| 238 | + check_find(nh, "000305", false); | |
| 239 | + check_find(nh, "00000", false); | |
| 240 | + check_find(nh, "00000", true); | |
| 241 | + check_find(nh, "000800", false); | |
| 242 | + check_find(nh, "000805", false); | |
| 243 | + check_find(nh, "000805", true); | |
| 244 | +} | |
| 245 | + | |
| 246 | +int main() | |
| 247 | +{ | |
| 248 | + test_bsearch(); | |
| 249 | + test_depth(); | |
| 250 | + | |
| 251 | + return 0; | |
| 124 | 252 | } |
| 253 | + | ... | ... |
libtests/qtest/nntree.test
| ... | ... | @@ -3,14 +3,15 @@ require 5.008; |
| 3 | 3 | use warnings; |
| 4 | 4 | use strict; |
| 5 | 5 | |
| 6 | +chdir("nntree") or die "chdir testdir failed: $!\n"; | |
| 7 | + | |
| 6 | 8 | require TestDriver; |
| 7 | 9 | |
| 8 | 10 | my $td = new TestDriver('nntree'); |
| 9 | 11 | |
| 10 | 12 | $td->runtest("nntree", |
| 11 | 13 | {$td->COMMAND => "nntree"}, |
| 12 | - {$td->STRING => "all tests passed\n", | |
| 13 | - $td->EXIT_STATUS => 0}, | |
| 14 | + {$td->FILE => "nntree.out", $td->EXIT_STATUS => 0}, | |
| 14 | 15 | $td->NORMALIZE_NEWLINES); |
| 15 | 16 | |
| 16 | 17 | $td->report(1); | ... | ... |
libtests/qtest/nntree/nntree.out
0 → 100644
| 1 | +bsearch tests passed | |
| 2 | +--- forward --- | |
| 3 | +000000 -> (val 000000) | |
| 4 | +000010 -> (val 000010) | |
| 5 | +000020 -> (val 000020) | |
| 6 | +000030 -> (val 000030) | |
| 7 | +000040 -> (val 000040) | |
| 8 | +000050 -> (val 000050) | |
| 9 | +000060 -> (val 000060) | |
| 10 | +000070 -> (val 000070) | |
| 11 | +000080 -> (val 000080) | |
| 12 | +000090 -> (val 000090) | |
| 13 | +000100 -> (val 000100) | |
| 14 | +000110 -> (val 000110) | |
| 15 | +000120 -> (val 000120) | |
| 16 | +000130 -> (val 000130) | |
| 17 | +000140 -> (val 000140) | |
| 18 | +000150 -> (val 000150) | |
| 19 | +000160 -> (val 000160) | |
| 20 | +000170 -> (val 000170) | |
| 21 | +000180 -> (val 000180) | |
| 22 | +000190 -> (val 000190) | |
| 23 | +000200 -> (val 000200) | |
| 24 | +000210 -> (val 000210) | |
| 25 | +000220 -> (val 000220) | |
| 26 | +000230 -> (val 000230) | |
| 27 | +000240 -> (val 000240) | |
| 28 | +000250 -> (val 000250) | |
| 29 | +000260 -> (val 000260) | |
| 30 | +000270 -> (val 000270) | |
| 31 | +000280 -> (val 000280) | |
| 32 | +000290 -> (val 000290) | |
| 33 | +000300 -> (val 000300) | |
| 34 | +000310 -> (val 000310) | |
| 35 | +000320 -> (val 000320) | |
| 36 | +000330 -> (val 000330) | |
| 37 | +000340 -> (val 000340) | |
| 38 | +000350 -> (val 000350) | |
| 39 | +000360 -> (val 000360) | |
| 40 | +000370 -> (val 000370) | |
| 41 | +000380 -> (val 000380) | |
| 42 | +000390 -> (val 000390) | |
| 43 | +000400 -> (val 000400) | |
| 44 | +000410 -> (val 000410) | |
| 45 | +000420 -> (val 000420) | |
| 46 | +000430 -> (val 000430) | |
| 47 | +000440 -> (val 000440) | |
| 48 | +000450 -> (val 000450) | |
| 49 | +000460 -> (val 000460) | |
| 50 | +000470 -> (val 000470) | |
| 51 | +000480 -> (val 000480) | |
| 52 | +000490 -> (val 000490) | |
| 53 | +000500 -> (val 000500) | |
| 54 | +000510 -> (val 000510) | |
| 55 | +000520 -> (val 000520) | |
| 56 | +000530 -> (val 000530) | |
| 57 | +000540 -> (val 000540) | |
| 58 | +000550 -> (val 000550) | |
| 59 | +000560 -> (val 000560) | |
| 60 | +000570 -> (val 000570) | |
| 61 | +000580 -> (val 000580) | |
| 62 | +000590 -> (val 000590) | |
| 63 | +000600 -> (val 000600) | |
| 64 | +000610 -> (val 000610) | |
| 65 | +000620 -> (val 000620) | |
| 66 | +000630 -> (val 000630) | |
| 67 | +000640 -> (val 000640) | |
| 68 | +000650 -> (val 000650) | |
| 69 | +000660 -> (val 000660) | |
| 70 | +000670 -> (val 000670) | |
| 71 | +000680 -> (val 000680) | |
| 72 | +000690 -> (val 000690) | |
| 73 | +000700 -> (val 000700) | |
| 74 | +000710 -> (val 000710) | |
| 75 | +000720 -> (val 000720) | |
| 76 | +000730 -> (val 000730) | |
| 77 | +000740 -> (val 000740) | |
| 78 | +000750 -> (val 000750) | |
| 79 | +000760 -> (val 000760) | |
| 80 | +000770 -> (val 000770) | |
| 81 | +000780 -> (val 000780) | |
| 82 | +000790 -> (val 000790) | |
| 83 | +000800 -> (val 000800) | |
| 84 | +--- backward --- | |
| 85 | +000800 -> (val 000800) | |
| 86 | +000790 -> (val 000790) | |
| 87 | +000780 -> (val 000780) | |
| 88 | +000770 -> (val 000770) | |
| 89 | +000760 -> (val 000760) | |
| 90 | +000750 -> (val 000750) | |
| 91 | +000740 -> (val 000740) | |
| 92 | +000730 -> (val 000730) | |
| 93 | +000720 -> (val 000720) | |
| 94 | +000710 -> (val 000710) | |
| 95 | +000700 -> (val 000700) | |
| 96 | +000690 -> (val 000690) | |
| 97 | +000680 -> (val 000680) | |
| 98 | +000670 -> (val 000670) | |
| 99 | +000660 -> (val 000660) | |
| 100 | +000650 -> (val 000650) | |
| 101 | +000640 -> (val 000640) | |
| 102 | +000630 -> (val 000630) | |
| 103 | +000620 -> (val 000620) | |
| 104 | +000610 -> (val 000610) | |
| 105 | +000600 -> (val 000600) | |
| 106 | +000590 -> (val 000590) | |
| 107 | +000580 -> (val 000580) | |
| 108 | +000570 -> (val 000570) | |
| 109 | +000560 -> (val 000560) | |
| 110 | +000550 -> (val 000550) | |
| 111 | +000540 -> (val 000540) | |
| 112 | +000530 -> (val 000530) | |
| 113 | +000520 -> (val 000520) | |
| 114 | +000510 -> (val 000510) | |
| 115 | +000500 -> (val 000500) | |
| 116 | +000490 -> (val 000490) | |
| 117 | +000480 -> (val 000480) | |
| 118 | +000470 -> (val 000470) | |
| 119 | +000460 -> (val 000460) | |
| 120 | +000450 -> (val 000450) | |
| 121 | +000440 -> (val 000440) | |
| 122 | +000430 -> (val 000430) | |
| 123 | +000420 -> (val 000420) | |
| 124 | +000410 -> (val 000410) | |
| 125 | +000400 -> (val 000400) | |
| 126 | +000390 -> (val 000390) | |
| 127 | +000380 -> (val 000380) | |
| 128 | +000370 -> (val 000370) | |
| 129 | +000360 -> (val 000360) | |
| 130 | +000350 -> (val 000350) | |
| 131 | +000340 -> (val 000340) | |
| 132 | +000330 -> (val 000330) | |
| 133 | +000320 -> (val 000320) | |
| 134 | +000310 -> (val 000310) | |
| 135 | +000300 -> (val 000300) | |
| 136 | +000290 -> (val 000290) | |
| 137 | +000280 -> (val 000280) | |
| 138 | +000270 -> (val 000270) | |
| 139 | +000260 -> (val 000260) | |
| 140 | +000250 -> (val 000250) | |
| 141 | +000240 -> (val 000240) | |
| 142 | +000230 -> (val 000230) | |
| 143 | +000220 -> (val 000220) | |
| 144 | +000210 -> (val 000210) | |
| 145 | +000200 -> (val 000200) | |
| 146 | +000190 -> (val 000190) | |
| 147 | +000180 -> (val 000180) | |
| 148 | +000170 -> (val 000170) | |
| 149 | +000160 -> (val 000160) | |
| 150 | +000150 -> (val 000150) | |
| 151 | +000140 -> (val 000140) | |
| 152 | +000130 -> (val 000130) | |
| 153 | +000120 -> (val 000120) | |
| 154 | +000110 -> (val 000110) | |
| 155 | +000100 -> (val 000100) | |
| 156 | +000090 -> (val 000090) | |
| 157 | +000080 -> (val 000080) | |
| 158 | +000070 -> (val 000070) | |
| 159 | +000060 -> (val 000060) | |
| 160 | +000050 -> (val 000050) | |
| 161 | +000040 -> (val 000040) | |
| 162 | +000030 -> (val 000030) | |
| 163 | +000020 -> (val 000020) | |
| 164 | +000010 -> (val 000010) | |
| 165 | +000000 -> (val 000000) | |
| 166 | +find 000300 (0): 000300 -> (val 000300) | |
| 167 | +find 000305 (1): 000300 -> (val 000300) | |
| 168 | +find 000305 (0): not found | |
| 169 | +find 00000 (0): not found | |
| 170 | +find 00000 (1): not found | |
| 171 | +find 000800 (0): 000800 -> (val 000800) | |
| 172 | +find 000805 (0): not found | |
| 173 | +find 000805 (1): 000800 -> (val 000800) | ... | ... |
qpdf/qtest/qpdf/name-tree.out
| ... | ... | @@ -7,4 +7,13 @@ |
| 7 | 7 | 20 twenty -> twenty. |
| 8 | 8 | 22 twenty-two -> twenty-two! |
| 9 | 9 | 29 twenty-nine -> twenty-nine! |
| 10 | +01 one -> one! | |
| 11 | +06 σιχ -> six! | |
| 12 | +07 sev•n -> seven! | |
| 13 | +11 elephant -> elephant? | |
| 14 | +12 twelve -> twelve! | |
| 15 | +15 fifteen -> fifteen! | |
| 16 | +20 twenty -> twenty. | |
| 17 | +22 twenty-two -> twenty-two! | |
| 18 | +29 twenty-nine -> twenty-nine! | |
| 10 | 19 | test 48 done | ... | ... |
qpdf/qtest/qpdf/number-tree.out
| ... | ... | @@ -12,4 +12,18 @@ |
| 12 | 12 | 22 twenty-two |
| 13 | 13 | 23 twenty-three |
| 14 | 14 | 29 twenty-nine |
| 15 | +1 one | |
| 16 | +2 two | |
| 17 | +3 three | |
| 18 | +5 five | |
| 19 | +6 six | |
| 20 | +9 nine | |
| 21 | +11 elephant | |
| 22 | +12 twelve | |
| 23 | +15 fifteen | |
| 24 | +19 nineteen | |
| 25 | +20 twenty | |
| 26 | +22 twenty-two | |
| 27 | +23 twenty-three | |
| 28 | +29 twenty-nine | |
| 15 | 29 | test 46 done | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -1749,13 +1749,17 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1749 | 1749 | // number-tree.pdf |
| 1750 | 1750 | QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); |
| 1751 | 1751 | QPDFNumberTreeObjectHelper ntoh(qtest); |
| 1752 | + for (auto iter: ntoh) | |
| 1753 | + { | |
| 1754 | + std::cout << iter.first << " " | |
| 1755 | + << iter.second.getStringValue() | |
| 1756 | + << std::endl; | |
| 1757 | + } | |
| 1752 | 1758 | QPDFNumberTreeObjectHelper::idx_map ntoh_map = ntoh.getAsMap(); |
| 1753 | - for (QPDFNumberTreeObjectHelper::idx_map::iterator iter = | |
| 1754 | - ntoh_map.begin(); | |
| 1755 | - iter != ntoh_map.end(); ++iter) | |
| 1759 | + for (auto& iter: ntoh_map) | |
| 1756 | 1760 | { |
| 1757 | - std::cout << (*iter).first << " " | |
| 1758 | - << (*iter).second.getStringValue() | |
| 1761 | + std::cout << iter.first << " " | |
| 1762 | + << iter.second.getStringValue() | |
| 1759 | 1763 | << std::endl; |
| 1760 | 1764 | } |
| 1761 | 1765 | assert(1 == ntoh.getMin()); |
| ... | ... | @@ -1793,13 +1797,17 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1793 | 1797 | // name-tree.pdf |
| 1794 | 1798 | QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); |
| 1795 | 1799 | QPDFNameTreeObjectHelper ntoh(qtest); |
| 1800 | + for (auto iter: ntoh) | |
| 1801 | + { | |
| 1802 | + std::cout << iter.first << " -> " | |
| 1803 | + << iter.second.getStringValue() | |
| 1804 | + << std::endl; | |
| 1805 | + } | |
| 1796 | 1806 | std::map<std::string, QPDFObjectHandle> ntoh_map = ntoh.getAsMap(); |
| 1797 | - for (std::map<std::string, QPDFObjectHandle>::iterator iter = | |
| 1798 | - ntoh_map.begin(); | |
| 1799 | - iter != ntoh_map.end(); ++iter) | |
| 1807 | + for (auto& iter: ntoh_map) | |
| 1800 | 1808 | { |
| 1801 | - std::cout << (*iter).first << " -> " | |
| 1802 | - << (*iter).second.getStringValue() | |
| 1809 | + std::cout << iter.first << " -> " | |
| 1810 | + << iter.second.getStringValue() | |
| 1803 | 1811 | << std::endl; |
| 1804 | 1812 | } |
| 1805 | 1813 | assert(ntoh.hasName("11 elephant")); |
| ... | ... | @@ -1809,6 +1817,9 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1809 | 1817 | assert(! ntoh.findObject("potato", oh)); |
| 1810 | 1818 | assert(ntoh.findObject("07 sev\xe2\x80\xa2n", oh)); |
| 1811 | 1819 | assert("seven!" == oh.getStringValue()); |
| 1820 | + auto last = ntoh.last(); | |
| 1821 | + assert((*last).first == "29 twenty-nine"); | |
| 1822 | + assert((*last).second.getUTF8Value() == "twenty-nine!"); | |
| 1812 | 1823 | } |
| 1813 | 1824 | else if (n == 49) |
| 1814 | 1825 | { | ... | ... |