diff --git a/ChangeLog b/ChangeLog index 5c3e6229..7bc6670f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -137,16 +137,15 @@ 2021-01-29 Jay Berkenbilt - * Add wrappers QPDFDictItems and QPDFArrayItems around - QPDFObjectHandle that provide a C++ iterator API, including C++11 - range-for iteration, over arrays and dictionaries. With this, you - can do + * Add methods to QPDFObjectHandle that provide a C++ iterator API, + including C++11 range-for iteration, over arrays and dictionaries. + With this, you can do - for (auto i: QPDFDictItems(oh)) + for (auto i: dict_oh.ditems()) { // i.first is a string, i.second is a QPDFObjectHandle } - for (auto i: QPDFArrayItems(oh)) + for (auto i: array_oh.aitems()) { // i is a QPDFObjectHandle } diff --git a/examples/pdf-mod-info.cc b/examples/pdf-mod-info.cc index 03fa2354..55b0c8c4 100644 --- a/examples/pdf-mod-info.cc +++ b/examples/pdf-mod-info.cc @@ -32,7 +32,7 @@ void dumpInfoDict(QPDF& pdf, QPDFObjectHandle trailer = pdf.getTrailer(); if (trailer.hasKey("/Info")) { - for (auto& it: QPDFDictItems(trailer.getKey("/Info"))) + for (auto& it: trailer.getKey("/Info").ditems()) { std::string val; if (it.second.isString()) diff --git a/examples/pdf-name-number-tree.cc b/examples/pdf-name-number-tree.cc index f1df6f14..cfae4a6b 100644 --- a/examples/pdf-name-number-tree.cc +++ b/examples/pdf-name-number-tree.cc @@ -93,7 +93,7 @@ int main(int argc, char* argv[]) // look at it using dictionary and array iterators. std::cout << "Keys in name tree object:" << std::endl; QPDFObjectHandle names; - for (auto const& i: QPDFDictItems(name_tree_oh)) + for (auto const& i: name_tree_oh.ditems()) { std::cout << i.first << std::endl; if (i.first == "/Names") @@ -103,7 +103,7 @@ int main(int argc, char* argv[]) } // Values in names array: std::cout << "Values in names:" << std::endl; - for (auto& i: QPDFArrayItems(names)) + for (auto& i: names.aitems()) { std::cout << " " << i.unparse() << std::endl; } diff --git a/include/qpdf/QPDFObjectHandle.hh b/include/qpdf/QPDFObjectHandle.hh index dc883102..356eb4e2 100644 --- a/include/qpdf/QPDFObjectHandle.hh +++ b/include/qpdf/QPDFObjectHandle.hh @@ -659,8 +659,19 @@ class QPDFObjectHandle QPDF_DLL std::string getInlineImageValue(); - // Methods for array objects; see also name and array objects. See - // also QPDFArrayItems later in this file. + // Methods for array objects; see also name and array objects. + + // Return an object that enables iteration over members. You can + // do + // + // for (auto iter: obj.aitems()) + // { + // // iter is an array element + // } + class QPDFArrayItems; + QPDF_DLL + QPDFArrayItems aitems(); + QPDF_DLL int getArrayNItems(); QPDF_DLL @@ -684,8 +695,20 @@ class QPDFObjectHandle QPDF_DLL Matrix getArrayAsMatrix(); - // Methods for dictionary objects. See also QPDFDictItems later in - // this file. + // Methods for dictionary objects. + + // Return an object that enables iteration over members. You can + // do + // + // for (auto iter: obj.ditems()) + // { + // // iter.first is the key + // // iter.second is the value + // } + class QPDFDictItems; + QPDF_DLL + QPDFDictItems ditems(); + QPDF_DLL bool hasKey(std::string const&); QPDF_DLL @@ -1288,7 +1311,7 @@ class QPDFObjectHandle bool reserved; }; -class QPDFDictItems +class QPDFObjectHandle::QPDFDictItems { // This class allows C++-style iteration, including range-for // iteration, around dictionaries. You can write @@ -1379,7 +1402,7 @@ class QPDFDictItems QPDFObjectHandle oh; }; -class QPDFArrayItems +class QPDFObjectHandle::QPDFArrayItems { // This class allows C++-style iteration, including range-for // iteration, around arrays. You can write diff --git a/libqpdf/QPDFAcroFormDocumentHelper.cc b/libqpdf/QPDFAcroFormDocumentHelper.cc index 2991e578..84ddd432 100644 --- a/libqpdf/QPDFAcroFormDocumentHelper.cc +++ b/libqpdf/QPDFAcroFormDocumentHelper.cc @@ -439,7 +439,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( } }; - for (auto annot: QPDFArrayItems(old_annots)) + for (auto annot: old_annots.aitems()) { if (annot.isStream()) { @@ -620,7 +620,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( }; if (apdict.isDictionary()) { - for (auto& ap: QPDFDictItems(apdict)) + for (auto& ap: apdict.ditems()) { if (ap.second.isStream()) { @@ -629,7 +629,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( } else if (ap.second.isDictionary()) { - for (auto& ap2: QPDFDictItems(ap.second)) + for (auto& ap2: ap.second.ditems()) { if (ap2.second.isStream()) { diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc index f6ba3093..3a7bb2f9 100644 --- a/libqpdf/QPDFObjectHandle.cc +++ b/libqpdf/QPDFObjectHandle.cc @@ -705,6 +705,12 @@ QPDFObjectHandle::getInlineImageValue() // Array accessors +QPDFObjectHandle::QPDFArrayItems +QPDFObjectHandle::aitems() +{ + return QPDFArrayItems(*this); +} + int QPDFObjectHandle::getArrayNItems() { @@ -931,6 +937,12 @@ QPDFObjectHandle::eraseItem(int at) // Dictionary accessors +QPDFObjectHandle::QPDFDictItems +QPDFObjectHandle::ditems() +{ + return QPDFDictItems(*this); +} + bool QPDFObjectHandle::hasKey(std::string const& key) { @@ -3211,43 +3223,44 @@ QPDFObjectHandle::warn(QPDF* qpdf, QPDFExc const& e) } } -QPDFDictItems::QPDFDictItems(QPDFObjectHandle const& oh) : +QPDFObjectHandle::QPDFDictItems::QPDFDictItems(QPDFObjectHandle const& oh) : oh(oh) { } -QPDFDictItems::iterator& -QPDFDictItems::iterator::operator++() +QPDFObjectHandle::QPDFDictItems::iterator& +QPDFObjectHandle::QPDFDictItems::iterator::operator++() { ++this->m->iter; updateIValue(); return *this; } -QPDFDictItems::iterator& -QPDFDictItems::iterator::operator--() +QPDFObjectHandle::QPDFDictItems::iterator& +QPDFObjectHandle::QPDFDictItems::iterator::operator--() { --this->m->iter; updateIValue(); return *this; } -QPDFDictItems::iterator::reference -QPDFDictItems::iterator:: operator*() +QPDFObjectHandle::QPDFDictItems::iterator::reference +QPDFObjectHandle::QPDFDictItems::iterator:: operator*() { updateIValue(); return this->ivalue; } -QPDFDictItems::iterator::pointer -QPDFDictItems::iterator::operator->() +QPDFObjectHandle::QPDFDictItems::iterator::pointer +QPDFObjectHandle::QPDFDictItems::iterator::operator->() { updateIValue(); return &this->ivalue; } bool -QPDFDictItems::iterator::operator==(iterator const& other) const +QPDFObjectHandle::QPDFDictItems::iterator::operator==( + iterator const& other) const { if (this->m->is_end && other.m->is_end) { @@ -3260,14 +3273,15 @@ QPDFDictItems::iterator::operator==(iterator const& other) const return (this->ivalue.first == other.ivalue.first); } -QPDFDictItems::iterator::iterator(QPDFObjectHandle& oh, bool for_begin) : +QPDFObjectHandle::QPDFDictItems::iterator::iterator( + QPDFObjectHandle& oh, bool for_begin) : m(new Members(oh, for_begin)) { updateIValue(); } void -QPDFDictItems::iterator::updateIValue() +QPDFObjectHandle::QPDFDictItems::iterator::updateIValue() { this->m->is_end = (this->m->iter == this->m->keys.end()); if (this->m->is_end) @@ -3282,7 +3296,7 @@ QPDFDictItems::iterator::updateIValue() } } -QPDFDictItems::iterator::Members::Members( +QPDFObjectHandle::QPDFDictItems::iterator::Members::Members( QPDFObjectHandle& oh, bool for_begin) : oh(oh) { @@ -3290,25 +3304,25 @@ QPDFDictItems::iterator::Members::Members( this->iter = for_begin ? this->keys.begin() : this->keys.end(); } -QPDFDictItems::iterator -QPDFDictItems::begin() +QPDFObjectHandle::QPDFDictItems::iterator +QPDFObjectHandle::QPDFDictItems::begin() { return iterator(oh, true); } -QPDFDictItems::iterator -QPDFDictItems::end() +QPDFObjectHandle::QPDFDictItems::iterator +QPDFObjectHandle::QPDFDictItems::end() { return iterator(oh, false); } -QPDFArrayItems::QPDFArrayItems(QPDFObjectHandle const& oh) : +QPDFObjectHandle::QPDFArrayItems::QPDFArrayItems(QPDFObjectHandle const& oh) : oh(oh) { } -QPDFArrayItems::iterator& -QPDFArrayItems::iterator::operator++() +QPDFObjectHandle::QPDFArrayItems::iterator& +QPDFObjectHandle::QPDFArrayItems::iterator::operator++() { if (! this->m->is_end) { @@ -3318,8 +3332,8 @@ QPDFArrayItems::iterator::operator++() return *this; } -QPDFArrayItems::iterator& -QPDFArrayItems::iterator::operator--() +QPDFObjectHandle::QPDFArrayItems::iterator& +QPDFObjectHandle::QPDFArrayItems::iterator::operator--() { if (this->m->item_number > 0) { @@ -3329,34 +3343,36 @@ QPDFArrayItems::iterator::operator--() return *this; } -QPDFArrayItems::iterator::reference -QPDFArrayItems::iterator:: operator*() +QPDFObjectHandle::QPDFArrayItems::iterator::reference +QPDFObjectHandle::QPDFArrayItems::iterator:: operator*() { updateIValue(); return this->ivalue; } -QPDFArrayItems::iterator::pointer -QPDFArrayItems::iterator::operator->() +QPDFObjectHandle::QPDFArrayItems::iterator::pointer +QPDFObjectHandle::QPDFArrayItems::iterator::operator->() { updateIValue(); return &this->ivalue; } bool -QPDFArrayItems::iterator::operator==(iterator const& other) const +QPDFObjectHandle::QPDFArrayItems::iterator::operator==( + iterator const& other) const { return (this->m->item_number == other.m->item_number); } -QPDFArrayItems::iterator::iterator(QPDFObjectHandle& oh, bool for_begin) : +QPDFObjectHandle::QPDFArrayItems::iterator::iterator( + QPDFObjectHandle& oh, bool for_begin) : m(new Members(oh, for_begin)) { updateIValue(); } void -QPDFArrayItems::iterator::updateIValue() +QPDFObjectHandle::QPDFArrayItems::iterator::updateIValue() { this->m->is_end = (this->m->item_number >= this->m->oh.getArrayNItems()); if (this->m->is_end) @@ -3369,21 +3385,21 @@ QPDFArrayItems::iterator::updateIValue() } } -QPDFArrayItems::iterator::Members::Members( +QPDFObjectHandle::QPDFArrayItems::iterator::Members::Members( QPDFObjectHandle& oh, bool for_begin) : oh(oh) { this->item_number = for_begin ? 0 : oh.getArrayNItems(); } -QPDFArrayItems::iterator -QPDFArrayItems::begin() +QPDFObjectHandle::QPDFArrayItems::iterator +QPDFObjectHandle::QPDFArrayItems::begin() { return iterator(oh, true); } -QPDFArrayItems::iterator -QPDFArrayItems::end() +QPDFObjectHandle::QPDFArrayItems::iterator +QPDFObjectHandle::QPDFArrayItems::end() { return iterator(oh, false); } diff --git a/manual/qpdf-manual.xml b/manual/qpdf-manual.xml index 001e3455..204bb72d 100644 --- a/manual/qpdf-manual.xml +++ b/manual/qpdf-manual.xml @@ -5190,11 +5190,10 @@ print "\n"; - Add QPDFDictItems and - QPDFArrayItems wrappers around - QPDFObjectHandle, allowing C++-style - iteration, including range-for iteration, over dictionary - and array QPDFObjectHandles. See comments in + Add QPDFObjectHandle::ditems() and + QPDFObjectHandle::aitems() that enable + C++-style iteration, including range-for iteration, over + dictionary and array QPDFObjectHandles. See comments in include/qpdf/QPDFObjectHandle.hh and examples/pdf-name-number-tree.cc for details. diff --git a/qpdf/qpdf.cc b/qpdf/qpdf.cc index 725a1742..bedb5ead 100644 --- a/qpdf/qpdf.cc +++ b/qpdf/qpdf.cc @@ -4104,7 +4104,7 @@ static void do_list_attachments(QPDF& pdf, Options& o) << std::endl; } std::cout << " all data streams:" << std::endl; - for (auto i2: QPDFDictItems(efoh->getEmbeddedFileStreams())) + for (auto i2: efoh->getEmbeddedFileStreams().ditems()) { std::cout << " " << i2.first << " -> " << i2.second.getObjGen() diff --git a/qpdf/test_driver.cc b/qpdf/test_driver.cc index 356d9312..19f20abd 100644 --- a/qpdf/test_driver.cc +++ b/qpdf/test_driver.cc @@ -352,7 +352,7 @@ void runtest(int n, char const* filename1, char const* arg2) std::cout << "/QTest is an array with " << qtest.getArrayNItems() << " items" << std::endl; int i = 0; - for (auto& iter: QPDFArrayItems(qtest)) + for (auto& iter: qtest.aitems()) { QTC::TC("qpdf", "main QTest array indirect", iter.isIndirect() ? 1 : 0); @@ -366,7 +366,7 @@ void runtest(int n, char const* filename1, char const* arg2) { QTC::TC("qpdf", "main QTest dictionary"); std::cout << "/QTest is a dictionary" << std::endl; - for (auto& iter: QPDFDictItems(qtest)) + for (auto& iter: qtest.ditems()) { QTC::TC("qpdf", "main QTest dictionary indirect", iter.second.isIndirect() ? 1 : 0); @@ -1545,7 +1545,7 @@ void runtest(int n, char const* filename1, char const* arg2) assert(array.isArray()); { // Exercise iterators directly - QPDFArrayItems ai(array); + auto ai = array.aitems(); auto i = ai.begin(); assert(i->getName() == "/Item0"); auto& i_value = *i; @@ -1565,7 +1565,7 @@ void runtest(int n, char const* filename1, char const* arg2) assert(dictionary.isDictionary()); { // Exercise iterators directly - QPDFDictItems di(dictionary); + auto di = dictionary.ditems(); auto i = di.begin(); assert(i->first == "/Key1"); auto& i_value = *i;