Commit 5816fb44b8ce24e8bb58cb30792e1c763d6cb163

Authored by Jay Berkenbilt
1 parent 16a9bb3f

name/number trees: insertAfter

include/qpdf/QPDFNameTreeObjectHelper.hh
@@ -112,6 +112,19 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -112,6 +112,19 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
112 return ! operator==(other); 112 return ! operator==(other);
113 } 113 }
114 114
  115 + // DANGER: this method can create inconsistent trees if not
  116 + // used properly! Insert a new item immediately after the
  117 + // current iterator and increment so that it points to the new
  118 + // item. If the current iterator is end(), insert at the
  119 + // beginning. This method does not check for proper ordering,
  120 + // so if you use it, you must ensure that the item you are
  121 + // inserting belongs where you are putting it. The reason for
  122 + // this method is that it is more efficient than insert() and
  123 + // can be used safely when you are creating a new tree and
  124 + // inserting items in sorted order.
  125 + QPDF_DLL
  126 + void insertAfter(std::string const& key, QPDFObjectHandle value);
  127 +
115 private: 128 private:
116 iterator(std::shared_ptr<NNTreeIterator> const&); 129 iterator(std::shared_ptr<NNTreeIterator> const&);
117 std::shared_ptr<NNTreeIterator> impl; 130 std::shared_ptr<NNTreeIterator> impl;
include/qpdf/QPDFNumberTreeObjectHelper.hh
@@ -131,6 +131,19 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -131,6 +131,19 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
131 return ! operator==(other); 131 return ! operator==(other);
132 } 132 }
133 133
  134 + // DANGER: this method can create inconsistent trees if not
  135 + // used properly! Insert a new item immediately after the
  136 + // current iterator and increment so that it points to the new
  137 + // item. If the current iterator is end(), insert at the
  138 + // beginning. This method does not check for proper ordering,
  139 + // so if you use it, you must ensure that the item you are
  140 + // inserting belongs where you are putting it. The reason for
  141 + // this method is that it is more efficient than insert() and
  142 + // can be used safely when you are creating a new tree and
  143 + // inserting items in sorted order.
  144 + QPDF_DLL
  145 + void insertAfter(numtree_number key, QPDFObjectHandle value);
  146 +
134 private: 147 private:
135 iterator(std::shared_ptr<NNTreeIterator> const&); 148 iterator(std::shared_ptr<NNTreeIterator> const&);
136 std::shared_ptr<NNTreeIterator> impl; 149 std::shared_ptr<NNTreeIterator> impl;
libqpdf/NNTree.cc
@@ -444,6 +444,14 @@ NNTreeIterator::lastPathElement() @@ -444,6 +444,14 @@ NNTreeIterator::lastPathElement()
444 void 444 void
445 NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value) 445 NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value)
446 { 446 {
  447 + if (! valid())
  448 + {
  449 + QTC::TC("qpdf", "NNTree insertAfter inserts first");
  450 + impl.insertFirst(key, value);
  451 + deepen(impl.oh, true, false);
  452 + return;
  453 + }
  454 +
447 auto items = this->node.getKey(impl.details.itemsKey()); 455 auto items = this->node.getKey(impl.details.itemsKey());
448 if (! items.isArray()) 456 if (! items.isArray())
449 { 457 {
@@ -457,6 +465,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value) @@ -457,6 +465,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value)
457 items.insertItem(this->item_number + 3, value); 465 items.insertItem(this->item_number + 3, value);
458 resetLimits(this->node, lastPathElement()); 466 resetLimits(this->node, lastPathElement());
459 split(this->node, lastPathElement()); 467 split(this->node, lastPathElement());
  468 + increment(false);
460 } 469 }
461 470
462 NNTreeIterator& 471 NNTreeIterator&
@@ -968,7 +977,6 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value) @@ -968,7 +977,6 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value)
968 { 977 {
969 QTC::TC("qpdf", "NNTree insert inserts after"); 978 QTC::TC("qpdf", "NNTree insert inserts after");
970 iter.insertAfter(key, value); 979 iter.insertAfter(key, value);
971 - ++iter;  
972 } 980 }
973 return iter; 981 return iter;
974 } 982 }
libqpdf/QPDFNameTreeObjectHelper.cc
@@ -102,6 +102,13 @@ QPDFNameTreeObjectHelper::iterator::operator==(iterator const&amp; other) const @@ -102,6 +102,13 @@ QPDFNameTreeObjectHelper::iterator::operator==(iterator const&amp; other) const
102 return *(impl) == *(other.impl); 102 return *(impl) == *(other.impl);
103 } 103 }
104 104
  105 +void
  106 +QPDFNameTreeObjectHelper::iterator::insertAfter(
  107 + std::string const& key, QPDFObjectHandle value)
  108 +{
  109 + impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value);
  110 +}
  111 +
105 QPDFNameTreeObjectHelper::iterator 112 QPDFNameTreeObjectHelper::iterator
106 QPDFNameTreeObjectHelper::begin() const 113 QPDFNameTreeObjectHelper::begin() const
107 { 114 {
libqpdf/QPDFNumberTreeObjectHelper.cc
@@ -98,6 +98,13 @@ QPDFNumberTreeObjectHelper::iterator::operator==(iterator const&amp; other) const @@ -98,6 +98,13 @@ QPDFNumberTreeObjectHelper::iterator::operator==(iterator const&amp; other) const
98 return *(impl) == *(other.impl); 98 return *(impl) == *(other.impl);
99 } 99 }
100 100
  101 +void
  102 +QPDFNumberTreeObjectHelper::iterator::insertAfter(
  103 + numtree_number key, QPDFObjectHandle value)
  104 +{
  105 + impl->insertAfter(QPDFObjectHandle::newInteger(key), value);
  106 +}
  107 +
101 QPDFNumberTreeObjectHelper::iterator 108 QPDFNumberTreeObjectHelper::iterator
102 QPDFNumberTreeObjectHelper::begin() const 109 QPDFNumberTreeObjectHelper::begin() const
103 { 110 {
qpdf/qpdf.testcov
@@ -552,3 +552,4 @@ NNTree bad node during find 0 @@ -552,3 +552,4 @@ NNTree bad node during find 0
552 NNTree node is not a dictionary 0 552 NNTree node is not a dictionary 0
553 NNTree limits didn't change 0 553 NNTree limits didn't change 0
554 NNTree increment end() 0 554 NNTree increment end() 0
  555 +NNTree insertAfter inserts first 0
qpdf/qtest/qpdf/name-tree.out
@@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
16 20 twenty -> twenty. 16 20 twenty -> twenty.
17 22 twenty-two -> twenty-two! 17 22 twenty-two -> twenty-two!
18 29 twenty-nine -> twenty-nine! 18 29 twenty-nine -> twenty-nine!
  19 +insertAfter
  20 +3 (3!)
  21 +4 (4!)
19 /Empty1 22 /Empty1
20 /Empty2 23 /Empty2
21 /Bad1: deprecated API 24 /Bad1: deprecated API
qpdf/qtest/qpdf/number-tree.out
@@ -26,6 +26,9 @@ @@ -26,6 +26,9 @@
26 22 twenty-two 26 22 twenty-two
27 23 twenty-three 27 23 twenty-three
28 29 twenty-nine 28 29 twenty-nine
  29 +insertAfter
  30 +3 (3!)
  31 +4 (4!)
29 /Bad1: deprecated API 32 /Bad1: deprecated API
30 /Bad1 33 /Bad1
31 WARNING: number-tree.pdf (Name/Number tree node (object 14)): name/number tree node has neither non-empty /Nums nor /Kids 34 WARNING: number-tree.pdf (Name/Number tree node (object 14)): name/number tree node has neither non-empty /Nums nor /Kids
qpdf/test_driver.cc
@@ -1802,6 +1802,19 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1802,6 +1802,19 @@ void runtest(int n, char const* filename1, char const* arg2)
1802 --iter1; 1802 --iter1;
1803 assert((*iter1).first == 2); 1803 assert((*iter1).first == 2);
1804 1804
  1805 + std::cout << "insertAfter" << std::endl;
  1806 + auto new2 = QPDFNumberTreeObjectHelper::newEmpty(pdf);
  1807 + auto iter2 = new2.begin();
  1808 + assert(iter2 == new2.end());
  1809 + iter2.insertAfter(3, QPDFObjectHandle::newString("3!"));
  1810 + assert((*iter2).first == 3);
  1811 + iter2.insertAfter(4, QPDFObjectHandle::newString("4!"));
  1812 + assert((*iter2).first == 4);
  1813 + for (auto i: new2)
  1814 + {
  1815 + std::cout << i.first << " " << i.second.unparse() << std::endl;
  1816 + }
  1817 +
1805 // Exercise deprecated API until qpdf 11 1818 // Exercise deprecated API until qpdf 11
1806 std::cout << "/Bad1: deprecated API" << std::endl; 1819 std::cout << "/Bad1: deprecated API" << std::endl;
1807 auto bad1 = QPDFNumberTreeObjectHelper( 1820 auto bad1 = QPDFNumberTreeObjectHelper(
@@ -1961,6 +1974,19 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1961,6 +1974,19 @@ void runtest(int n, char const* filename1, char const* arg2)
1961 --iter1; 1974 --iter1;
1962 assert((*iter1).first == "2"); 1975 assert((*iter1).first == "2");
1963 1976
  1977 + std::cout << "insertAfter" << std::endl;
  1978 + auto new2 = QPDFNameTreeObjectHelper::newEmpty(pdf);
  1979 + auto iter2 = new2.begin();
  1980 + assert(iter2 == new2.end());
  1981 + iter2.insertAfter("3", QPDFObjectHandle::newString("3!"));
  1982 + assert((*iter2).first == "3");
  1983 + iter2.insertAfter("4", QPDFObjectHandle::newString("4!"));
  1984 + assert((*iter2).first == "4");
  1985 + for (auto i: new2)
  1986 + {
  1987 + std::cout << i.first << " " << i.second.unparse() << std::endl;
  1988 + }
  1989 +
1964 std::vector<std::string> empties = {"/Empty1", "/Empty2"}; 1990 std::vector<std::string> empties = {"/Empty1", "/Empty2"};
1965 for (auto const& k: empties) 1991 for (auto const& k: empties)
1966 { 1992 {