From 16a9bb3f6f63497946d0efbf403df92d0ce30745 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 24 Jan 2021 03:55:18 -0500 Subject: name/number trees: newEmpty, increment/decrement end() --- include/qpdf/QPDFNameTreeObjectHelper.hh | 10 +++++- include/qpdf/QPDFNumberTreeObjectHelper.hh | 10 +++++- libqpdf/NNTree.cc | 6 ++-- libqpdf/QPDFNameTreeObjectHelper.cc | 7 ++++ libqpdf/QPDFNumberTreeObjectHelper.cc | 7 ++++ qpdf/qpdf.testcov | 1 + qpdf/test_driver.cc | 52 ++++++++++++++++++++++++++++++ 7 files changed, 88 insertions(+), 5 deletions(-) diff --git a/include/qpdf/QPDFNameTreeObjectHelper.hh b/include/qpdf/QPDFNameTreeObjectHelper.hh index 80a48b7f..f0a9b479 100644 --- a/include/qpdf/QPDFNameTreeObjectHelper.hh +++ b/include/qpdf/QPDFNameTreeObjectHelper.hh @@ -54,6 +54,12 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper // structure. QPDF_DLL QPDFNameTreeObjectHelper(QPDFObjectHandle); + + // Create an empty name tree + QPDF_DLL + static QPDFNameTreeObjectHelper newEmpty(QPDF&, bool auto_repair = true); + + // ABI: = default QPDF_DLL virtual ~QPDFNameTreeObjectHelper(); @@ -112,7 +118,9 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper }; // The iterator looks like map iterator, so i.first is a string - // and i.second is a QPDFObjectHandle. + // and i.second is a QPDFObjectHandle. Incrementing end() brings + // you to the first item. Decrementing end() brings you to the + // last item. QPDF_DLL iterator begin() const; QPDF_DLL diff --git a/include/qpdf/QPDFNumberTreeObjectHelper.hh b/include/qpdf/QPDFNumberTreeObjectHelper.hh index b4f31b12..43c438e4 100644 --- a/include/qpdf/QPDFNumberTreeObjectHelper.hh +++ b/include/qpdf/QPDFNumberTreeObjectHelper.hh @@ -51,11 +51,17 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper // structure. QPDF_DLL QPDFNumberTreeObjectHelper(QPDFObjectHandle); + + // ABI: = default QPDF_DLL virtual ~QPDFNumberTreeObjectHelper() { } + // Create an empty number tree + QPDF_DLL + static QPDFNumberTreeObjectHelper newEmpty(QPDF&, bool auto_repair = true); + typedef long long int numtree_number; // Return overall minimum and maximum indices @@ -131,7 +137,9 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper }; // The iterator looks like map iterator, so i.first is a string - // and i.second is a QPDFObjectHandle. + // and i.second is a QPDFObjectHandle. Incrementing end() brings + // you to the first item. Decrementing end() brings you to the + // last item. QPDF_DLL iterator begin() const; QPDF_DLL diff --git a/libqpdf/NNTree.cc b/libqpdf/NNTree.cc index 3d1388b4..05398602 100644 --- a/libqpdf/NNTree.cc +++ b/libqpdf/NNTree.cc @@ -103,9 +103,9 @@ NNTreeIterator::increment(bool backward) { if (this->item_number < 0) { - throw std::logic_error( - "attempt made to increment or decrement an invalid" - " name/number tree iterator"); + QTC::TC("qpdf", "NNTree increment end()"); + deepen(impl.oh, ! backward, true); + return; } bool found_valid_key = false; while (valid() && (! found_valid_key)) diff --git a/libqpdf/QPDFNameTreeObjectHelper.cc b/libqpdf/QPDFNameTreeObjectHelper.cc index 52201eff..ffcf95a3 100644 --- a/libqpdf/QPDFNameTreeObjectHelper.cc +++ b/libqpdf/QPDFNameTreeObjectHelper.cc @@ -56,6 +56,13 @@ QPDFNameTreeObjectHelper::~QPDFNameTreeObjectHelper() { } +QPDFNameTreeObjectHelper +QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) +{ + return QPDFNameTreeObjectHelper( + QPDFObjectHandle::parse("<< /Names [] >>"), qpdf, auto_repair); +} + QPDFNameTreeObjectHelper::iterator::iterator( std::shared_ptr const& i) : impl(i) diff --git a/libqpdf/QPDFNumberTreeObjectHelper.cc b/libqpdf/QPDFNumberTreeObjectHelper.cc index f21d1e51..053fa421 100644 --- a/libqpdf/QPDFNumberTreeObjectHelper.cc +++ b/libqpdf/QPDFNumberTreeObjectHelper.cc @@ -52,6 +52,13 @@ QPDFNumberTreeObjectHelper::QPDFNumberTreeObjectHelper(QPDFObjectHandle oh) : { } +QPDFNumberTreeObjectHelper +QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) +{ + return QPDFNumberTreeObjectHelper( + QPDFObjectHandle::parse("<< /Nums [] >>"), qpdf, auto_repair); +} + QPDFNumberTreeObjectHelper::iterator::iterator( std::shared_ptr const& i) : impl(i) diff --git a/qpdf/qpdf.testcov b/qpdf/qpdf.testcov index fdb004c9..996c565a 100644 --- a/qpdf/qpdf.testcov +++ b/qpdf/qpdf.testcov @@ -551,3 +551,4 @@ NNTree -1 in binary search 0 NNTree bad node during find 0 NNTree node is not a dictionary 0 NNTree limits didn't change 0 +NNTree increment end() 0 diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index c0e29854..526b0123 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -1776,6 +1776,32 @@ void runtest(int n, char const* filename1, char const* arg2) assert("six" == oh.getStringValue()); assert(2 == offset); + auto new1 = QPDFNumberTreeObjectHelper::newEmpty(pdf); + auto iter1 = new1.begin(); + assert(iter1 == new1.end()); + ++iter1; + assert(iter1 == new1.end()); + --iter1; + assert(iter1 == new1.end()); + new1.insert(1, QPDFObjectHandle::newString("1")); + ++iter1; + assert((*iter1).first == 1); + --iter1; + assert(iter1 == new1.end()); + --iter1; + assert((*iter1).first == 1); + new1.insert(2, QPDFObjectHandle::newString("2")); + ++iter1; + assert((*iter1).first == 2); + ++iter1; + assert(iter1 == new1.end()); + ++iter1; + assert((*iter1).first == 1); + --iter1; + assert(iter1 == new1.end()); + --iter1; + assert((*iter1).first == 2); + // Exercise deprecated API until qpdf 11 std::cout << "/Bad1: deprecated API" << std::endl; auto bad1 = QPDFNumberTreeObjectHelper( @@ -1909,6 +1935,32 @@ void runtest(int n, char const* filename1, char const* arg2) assert((*last).first == "29 twenty-nine"); assert((*last).second.getUTF8Value() == "twenty-nine!"); + auto new1 = QPDFNameTreeObjectHelper::newEmpty(pdf); + auto iter1 = new1.begin(); + assert(iter1 == new1.end()); + ++iter1; + assert(iter1 == new1.end()); + --iter1; + assert(iter1 == new1.end()); + new1.insert("1", QPDFObjectHandle::newString("1")); + ++iter1; + assert((*iter1).first == "1"); + --iter1; + assert(iter1 == new1.end()); + --iter1; + assert((*iter1).first == "1"); + new1.insert("2", QPDFObjectHandle::newString("2")); + ++iter1; + assert((*iter1).first == "2"); + ++iter1; + assert(iter1 == new1.end()); + ++iter1; + assert((*iter1).first == "1"); + --iter1; + assert(iter1 == new1.end()); + --iter1; + assert((*iter1).first == "2"); + std::vector empties = {"/Empty1", "/Empty2"}; for (auto const& k: empties) { -- cgit v1.2.3-70-g09d2