aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/qpdf/QPDFNameTreeObjectHelper.hh13
-rw-r--r--include/qpdf/QPDFNumberTreeObjectHelper.hh13
-rw-r--r--libqpdf/NNTree.cc10
-rw-r--r--libqpdf/QPDFNameTreeObjectHelper.cc7
-rw-r--r--libqpdf/QPDFNumberTreeObjectHelper.cc7
-rw-r--r--qpdf/qpdf.testcov1
-rw-r--r--qpdf/qtest/qpdf/name-tree.out3
-rw-r--r--qpdf/qtest/qpdf/number-tree.out3
-rw-r--r--qpdf/test_driver.cc26
9 files changed, 82 insertions, 1 deletions
diff --git a/include/qpdf/QPDFNameTreeObjectHelper.hh b/include/qpdf/QPDFNameTreeObjectHelper.hh
index f0a9b479..ebc84735 100644
--- a/include/qpdf/QPDFNameTreeObjectHelper.hh
+++ b/include/qpdf/QPDFNameTreeObjectHelper.hh
@@ -112,6 +112,19 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
return ! operator==(other);
}
+ // DANGER: this method can create inconsistent trees if not
+ // used properly! Insert a new item immediately after the
+ // current iterator and increment so that it points to the new
+ // item. If the current iterator is end(), insert at the
+ // beginning. This method does not check for proper ordering,
+ // so if you use it, you must ensure that the item you are
+ // inserting belongs where you are putting it. The reason for
+ // this method is that it is more efficient than insert() and
+ // can be used safely when you are creating a new tree and
+ // inserting items in sorted order.
+ QPDF_DLL
+ void insertAfter(std::string const& key, QPDFObjectHandle value);
+
private:
iterator(std::shared_ptr<NNTreeIterator> const&);
std::shared_ptr<NNTreeIterator> impl;
diff --git a/include/qpdf/QPDFNumberTreeObjectHelper.hh b/include/qpdf/QPDFNumberTreeObjectHelper.hh
index 43c438e4..040dc3b1 100644
--- a/include/qpdf/QPDFNumberTreeObjectHelper.hh
+++ b/include/qpdf/QPDFNumberTreeObjectHelper.hh
@@ -131,6 +131,19 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
return ! operator==(other);
}
+ // DANGER: this method can create inconsistent trees if not
+ // used properly! Insert a new item immediately after the
+ // current iterator and increment so that it points to the new
+ // item. If the current iterator is end(), insert at the
+ // beginning. This method does not check for proper ordering,
+ // so if you use it, you must ensure that the item you are
+ // inserting belongs where you are putting it. The reason for
+ // this method is that it is more efficient than insert() and
+ // can be used safely when you are creating a new tree and
+ // inserting items in sorted order.
+ QPDF_DLL
+ void insertAfter(numtree_number key, QPDFObjectHandle value);
+
private:
iterator(std::shared_ptr<NNTreeIterator> const&);
std::shared_ptr<NNTreeIterator> impl;
diff --git a/libqpdf/NNTree.cc b/libqpdf/NNTree.cc
index 05398602..02237939 100644
--- a/libqpdf/NNTree.cc
+++ b/libqpdf/NNTree.cc
@@ -444,6 +444,14 @@ NNTreeIterator::lastPathElement()
void
NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value)
{
+ if (! valid())
+ {
+ QTC::TC("qpdf", "NNTree insertAfter inserts first");
+ impl.insertFirst(key, value);
+ deepen(impl.oh, true, false);
+ return;
+ }
+
auto items = this->node.getKey(impl.details.itemsKey());
if (! items.isArray())
{
@@ -457,6 +465,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value)
items.insertItem(this->item_number + 3, value);
resetLimits(this->node, lastPathElement());
split(this->node, lastPathElement());
+ increment(false);
}
NNTreeIterator&
@@ -968,7 +977,6 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value)
{
QTC::TC("qpdf", "NNTree insert inserts after");
iter.insertAfter(key, value);
- ++iter;
}
return iter;
}
diff --git a/libqpdf/QPDFNameTreeObjectHelper.cc b/libqpdf/QPDFNameTreeObjectHelper.cc
index ffcf95a3..c43281bd 100644
--- a/libqpdf/QPDFNameTreeObjectHelper.cc
+++ b/libqpdf/QPDFNameTreeObjectHelper.cc
@@ -102,6 +102,13 @@ QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const
return *(impl) == *(other.impl);
}
+void
+QPDFNameTreeObjectHelper::iterator::insertAfter(
+ std::string const& key, QPDFObjectHandle value)
+{
+ impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value);
+}
+
QPDFNameTreeObjectHelper::iterator
QPDFNameTreeObjectHelper::begin() const
{
diff --git a/libqpdf/QPDFNumberTreeObjectHelper.cc b/libqpdf/QPDFNumberTreeObjectHelper.cc
index 053fa421..ceda9482 100644
--- a/libqpdf/QPDFNumberTreeObjectHelper.cc
+++ b/libqpdf/QPDFNumberTreeObjectHelper.cc
@@ -98,6 +98,13 @@ QPDFNumberTreeObjectHelper::iterator::operator==(iterator const& other) const
return *(impl) == *(other.impl);
}
+void
+QPDFNumberTreeObjectHelper::iterator::insertAfter(
+ numtree_number key, QPDFObjectHandle value)
+{
+ impl->insertAfter(QPDFObjectHandle::newInteger(key), value);
+}
+
QPDFNumberTreeObjectHelper::iterator
QPDFNumberTreeObjectHelper::begin() const
{
diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov
index 996c565a..aa07b45f 100644
--- a/qpdf/qpdf.testcov
+++ b/qpdf/qpdf.testcov
@@ -552,3 +552,4 @@ NNTree bad node during find 0
NNTree node is not a dictionary 0
NNTree limits didn't change 0
NNTree increment end() 0
+NNTree insertAfter inserts first 0
diff --git a/qpdf/qtest/qpdf/name-tree.out b/qpdf/qtest/qpdf/name-tree.out
index 2292d5d7..377d3ab5 100644
--- a/qpdf/qtest/qpdf/name-tree.out
+++ b/qpdf/qtest/qpdf/name-tree.out
@@ -16,6 +16,9 @@
20 twenty -> twenty.
22 twenty-two -> twenty-two!
29 twenty-nine -> twenty-nine!
+insertAfter
+3 (3!)
+4 (4!)
/Empty1
/Empty2
/Bad1: deprecated API
diff --git a/qpdf/qtest/qpdf/number-tree.out b/qpdf/qtest/qpdf/number-tree.out
index 4ea689ce..d1ad8302 100644
--- a/qpdf/qtest/qpdf/number-tree.out
+++ b/qpdf/qtest/qpdf/number-tree.out
@@ -26,6 +26,9 @@
22 twenty-two
23 twenty-three
29 twenty-nine
+insertAfter
+3 (3!)
+4 (4!)
/Bad1: deprecated API
/Bad1
WARNING: number-tree.pdf (Name/Number tree node (object 14)): name/number tree node has neither non-empty /Nums nor /Kids
diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc
index 526b0123..a0aab3a8 100644
--- a/qpdf/test_driver.cc
+++ b/qpdf/test_driver.cc
@@ -1802,6 +1802,19 @@ void runtest(int n, char const* filename1, char const* arg2)
--iter1;
assert((*iter1).first == 2);
+ std::cout << "insertAfter" << std::endl;
+ auto new2 = QPDFNumberTreeObjectHelper::newEmpty(pdf);
+ auto iter2 = new2.begin();
+ assert(iter2 == new2.end());
+ iter2.insertAfter(3, QPDFObjectHandle::newString("3!"));
+ assert((*iter2).first == 3);
+ iter2.insertAfter(4, QPDFObjectHandle::newString("4!"));
+ assert((*iter2).first == 4);
+ for (auto i: new2)
+ {
+ std::cout << i.first << " " << i.second.unparse() << std::endl;
+ }
+
// Exercise deprecated API until qpdf 11
std::cout << "/Bad1: deprecated API" << std::endl;
auto bad1 = QPDFNumberTreeObjectHelper(
@@ -1961,6 +1974,19 @@ void runtest(int n, char const* filename1, char const* arg2)
--iter1;
assert((*iter1).first == "2");
+ std::cout << "insertAfter" << std::endl;
+ auto new2 = QPDFNameTreeObjectHelper::newEmpty(pdf);
+ auto iter2 = new2.begin();
+ assert(iter2 == new2.end());
+ iter2.insertAfter("3", QPDFObjectHandle::newString("3!"));
+ assert((*iter2).first == "3");
+ iter2.insertAfter("4", QPDFObjectHandle::newString("4!"));
+ assert((*iter2).first == "4");
+ for (auto i: new2)
+ {
+ std::cout << i.first << " " << i.second.unparse() << std::endl;
+ }
+
std::vector<std::string> empties = {"/Empty1", "/Empty2"};
for (auto const& k: empties)
{