Change from QPDF{Array,Dict}Items to aitems() and ditems()

This commit is contained in:
Jay Berkenbilt 2021-02-22 11:02:18 -05:00
parent a9ae8cadc6
commit 7b3cbacf5d
9 changed files with 99 additions and 62 deletions

View File

@ -137,16 +137,15 @@
2021-01-29 Jay Berkenbilt <ejb@ql.org> 2021-01-29 Jay Berkenbilt <ejb@ql.org>
* Add wrappers QPDFDictItems and QPDFArrayItems around * Add methods to QPDFObjectHandle that provide a C++ iterator API,
QPDFObjectHandle that provide a C++ iterator API, including C++11 including C++11 range-for iteration, over arrays and dictionaries.
range-for iteration, over arrays and dictionaries. With this, you With this, you can do
can do
for (auto i: QPDFDictItems(oh)) for (auto i: dict_oh.ditems())
{ {
// i.first is a string, i.second is a QPDFObjectHandle // 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 // i is a QPDFObjectHandle
} }

View File

@ -32,7 +32,7 @@ void dumpInfoDict(QPDF& pdf,
QPDFObjectHandle trailer = pdf.getTrailer(); QPDFObjectHandle trailer = pdf.getTrailer();
if (trailer.hasKey("/Info")) if (trailer.hasKey("/Info"))
{ {
for (auto& it: QPDFDictItems(trailer.getKey("/Info"))) for (auto& it: trailer.getKey("/Info").ditems())
{ {
std::string val; std::string val;
if (it.second.isString()) if (it.second.isString())

View File

@ -93,7 +93,7 @@ int main(int argc, char* argv[])
// look at it using dictionary and array iterators. // look at it using dictionary and array iterators.
std::cout << "Keys in name tree object:" << std::endl; std::cout << "Keys in name tree object:" << std::endl;
QPDFObjectHandle names; QPDFObjectHandle names;
for (auto const& i: QPDFDictItems(name_tree_oh)) for (auto const& i: name_tree_oh.ditems())
{ {
std::cout << i.first << std::endl; std::cout << i.first << std::endl;
if (i.first == "/Names") if (i.first == "/Names")
@ -103,7 +103,7 @@ int main(int argc, char* argv[])
} }
// Values in names array: // Values in names array:
std::cout << "Values in names:" << std::endl; std::cout << "Values in names:" << std::endl;
for (auto& i: QPDFArrayItems(names)) for (auto& i: names.aitems())
{ {
std::cout << " " << i.unparse() << std::endl; std::cout << " " << i.unparse() << std::endl;
} }

View File

@ -659,8 +659,19 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
std::string getInlineImageValue(); std::string getInlineImageValue();
// Methods for array objects; see also name and array objects. See // Methods for array objects; see also name and array objects.
// also QPDFArrayItems later in this file.
// 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 QPDF_DLL
int getArrayNItems(); int getArrayNItems();
QPDF_DLL QPDF_DLL
@ -684,8 +695,20 @@ class QPDFObjectHandle
QPDF_DLL QPDF_DLL
Matrix getArrayAsMatrix(); Matrix getArrayAsMatrix();
// Methods for dictionary objects. See also QPDFDictItems later in // Methods for dictionary objects.
// this file.
// 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 QPDF_DLL
bool hasKey(std::string const&); bool hasKey(std::string const&);
QPDF_DLL QPDF_DLL
@ -1288,7 +1311,7 @@ class QPDFObjectHandle
bool reserved; bool reserved;
}; };
class QPDFDictItems class QPDFObjectHandle::QPDFDictItems
{ {
// This class allows C++-style iteration, including range-for // This class allows C++-style iteration, including range-for
// iteration, around dictionaries. You can write // iteration, around dictionaries. You can write
@ -1379,7 +1402,7 @@ class QPDFDictItems
QPDFObjectHandle oh; QPDFObjectHandle oh;
}; };
class QPDFArrayItems class QPDFObjectHandle::QPDFArrayItems
{ {
// This class allows C++-style iteration, including range-for // This class allows C++-style iteration, including range-for
// iteration, around arrays. You can write // iteration, around arrays. You can write

View File

@ -439,7 +439,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
} }
}; };
for (auto annot: QPDFArrayItems(old_annots)) for (auto annot: old_annots.aitems())
{ {
if (annot.isStream()) if (annot.isStream())
{ {
@ -620,7 +620,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
}; };
if (apdict.isDictionary()) if (apdict.isDictionary())
{ {
for (auto& ap: QPDFDictItems(apdict)) for (auto& ap: apdict.ditems())
{ {
if (ap.second.isStream()) if (ap.second.isStream())
{ {
@ -629,7 +629,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
} }
else if (ap.second.isDictionary()) else if (ap.second.isDictionary())
{ {
for (auto& ap2: QPDFDictItems(ap.second)) for (auto& ap2: ap.second.ditems())
{ {
if (ap2.second.isStream()) if (ap2.second.isStream())
{ {

View File

@ -705,6 +705,12 @@ QPDFObjectHandle::getInlineImageValue()
// Array accessors // Array accessors
QPDFObjectHandle::QPDFArrayItems
QPDFObjectHandle::aitems()
{
return QPDFArrayItems(*this);
}
int int
QPDFObjectHandle::getArrayNItems() QPDFObjectHandle::getArrayNItems()
{ {
@ -931,6 +937,12 @@ QPDFObjectHandle::eraseItem(int at)
// Dictionary accessors // Dictionary accessors
QPDFObjectHandle::QPDFDictItems
QPDFObjectHandle::ditems()
{
return QPDFDictItems(*this);
}
bool bool
QPDFObjectHandle::hasKey(std::string const& key) 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) oh(oh)
{ {
} }
QPDFDictItems::iterator& QPDFObjectHandle::QPDFDictItems::iterator&
QPDFDictItems::iterator::operator++() QPDFObjectHandle::QPDFDictItems::iterator::operator++()
{ {
++this->m->iter; ++this->m->iter;
updateIValue(); updateIValue();
return *this; return *this;
} }
QPDFDictItems::iterator& QPDFObjectHandle::QPDFDictItems::iterator&
QPDFDictItems::iterator::operator--() QPDFObjectHandle::QPDFDictItems::iterator::operator--()
{ {
--this->m->iter; --this->m->iter;
updateIValue(); updateIValue();
return *this; return *this;
} }
QPDFDictItems::iterator::reference QPDFObjectHandle::QPDFDictItems::iterator::reference
QPDFDictItems::iterator:: operator*() QPDFObjectHandle::QPDFDictItems::iterator:: operator*()
{ {
updateIValue(); updateIValue();
return this->ivalue; return this->ivalue;
} }
QPDFDictItems::iterator::pointer QPDFObjectHandle::QPDFDictItems::iterator::pointer
QPDFDictItems::iterator::operator->() QPDFObjectHandle::QPDFDictItems::iterator::operator->()
{ {
updateIValue(); updateIValue();
return &this->ivalue; return &this->ivalue;
} }
bool 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) 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); 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)) m(new Members(oh, for_begin))
{ {
updateIValue(); updateIValue();
} }
void void
QPDFDictItems::iterator::updateIValue() QPDFObjectHandle::QPDFDictItems::iterator::updateIValue()
{ {
this->m->is_end = (this->m->iter == this->m->keys.end()); this->m->is_end = (this->m->iter == this->m->keys.end());
if (this->m->is_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) : QPDFObjectHandle& oh, bool for_begin) :
oh(oh) oh(oh)
{ {
@ -3290,25 +3304,25 @@ QPDFDictItems::iterator::Members::Members(
this->iter = for_begin ? this->keys.begin() : this->keys.end(); this->iter = for_begin ? this->keys.begin() : this->keys.end();
} }
QPDFDictItems::iterator QPDFObjectHandle::QPDFDictItems::iterator
QPDFDictItems::begin() QPDFObjectHandle::QPDFDictItems::begin()
{ {
return iterator(oh, true); return iterator(oh, true);
} }
QPDFDictItems::iterator QPDFObjectHandle::QPDFDictItems::iterator
QPDFDictItems::end() QPDFObjectHandle::QPDFDictItems::end()
{ {
return iterator(oh, false); return iterator(oh, false);
} }
QPDFArrayItems::QPDFArrayItems(QPDFObjectHandle const& oh) : QPDFObjectHandle::QPDFArrayItems::QPDFArrayItems(QPDFObjectHandle const& oh) :
oh(oh) oh(oh)
{ {
} }
QPDFArrayItems::iterator& QPDFObjectHandle::QPDFArrayItems::iterator&
QPDFArrayItems::iterator::operator++() QPDFObjectHandle::QPDFArrayItems::iterator::operator++()
{ {
if (! this->m->is_end) if (! this->m->is_end)
{ {
@ -3318,8 +3332,8 @@ QPDFArrayItems::iterator::operator++()
return *this; return *this;
} }
QPDFArrayItems::iterator& QPDFObjectHandle::QPDFArrayItems::iterator&
QPDFArrayItems::iterator::operator--() QPDFObjectHandle::QPDFArrayItems::iterator::operator--()
{ {
if (this->m->item_number > 0) if (this->m->item_number > 0)
{ {
@ -3329,34 +3343,36 @@ QPDFArrayItems::iterator::operator--()
return *this; return *this;
} }
QPDFArrayItems::iterator::reference QPDFObjectHandle::QPDFArrayItems::iterator::reference
QPDFArrayItems::iterator:: operator*() QPDFObjectHandle::QPDFArrayItems::iterator:: operator*()
{ {
updateIValue(); updateIValue();
return this->ivalue; return this->ivalue;
} }
QPDFArrayItems::iterator::pointer QPDFObjectHandle::QPDFArrayItems::iterator::pointer
QPDFArrayItems::iterator::operator->() QPDFObjectHandle::QPDFArrayItems::iterator::operator->()
{ {
updateIValue(); updateIValue();
return &this->ivalue; return &this->ivalue;
} }
bool 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); 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)) m(new Members(oh, for_begin))
{ {
updateIValue(); updateIValue();
} }
void void
QPDFArrayItems::iterator::updateIValue() QPDFObjectHandle::QPDFArrayItems::iterator::updateIValue()
{ {
this->m->is_end = (this->m->item_number >= this->m->oh.getArrayNItems()); this->m->is_end = (this->m->item_number >= this->m->oh.getArrayNItems());
if (this->m->is_end) 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) : QPDFObjectHandle& oh, bool for_begin) :
oh(oh) oh(oh)
{ {
this->item_number = for_begin ? 0 : oh.getArrayNItems(); this->item_number = for_begin ? 0 : oh.getArrayNItems();
} }
QPDFArrayItems::iterator QPDFObjectHandle::QPDFArrayItems::iterator
QPDFArrayItems::begin() QPDFObjectHandle::QPDFArrayItems::begin()
{ {
return iterator(oh, true); return iterator(oh, true);
} }
QPDFArrayItems::iterator QPDFObjectHandle::QPDFArrayItems::iterator
QPDFArrayItems::end() QPDFObjectHandle::QPDFArrayItems::end()
{ {
return iterator(oh, false); return iterator(oh, false);
} }

View File

@ -5190,11 +5190,10 @@ print "\n";
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
Add <classname>QPDFDictItems</classname> and Add <function>QPDFObjectHandle::ditems()</function> and
<classname>QPDFArrayItems</classname> wrappers around <function>QPDFObjectHandle::aitems()</function> that enable
<classname>QPDFObjectHandle</classname>, allowing C++-style C++-style iteration, including range-for iteration, over
iteration, including range-for iteration, over dictionary dictionary and array QPDFObjectHandles. See comments in
and array QPDFObjectHandles. See comments in
<filename>include/qpdf/QPDFObjectHandle.hh</filename> and <filename>include/qpdf/QPDFObjectHandle.hh</filename> and
<filename>examples/pdf-name-number-tree.cc</filename> for <filename>examples/pdf-name-number-tree.cc</filename> for
details. details.

View File

@ -4104,7 +4104,7 @@ static void do_list_attachments(QPDF& pdf, Options& o)
<< std::endl; << std::endl;
} }
std::cout << " all data streams:" << 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 << " -> " std::cout << " " << i2.first << " -> "
<< i2.second.getObjGen() << i2.second.getObjGen()

View File

@ -352,7 +352,7 @@ void runtest(int n, char const* filename1, char const* arg2)
std::cout << "/QTest is an array with " std::cout << "/QTest is an array with "
<< qtest.getArrayNItems() << " items" << std::endl; << qtest.getArrayNItems() << " items" << std::endl;
int i = 0; int i = 0;
for (auto& iter: QPDFArrayItems(qtest)) for (auto& iter: qtest.aitems())
{ {
QTC::TC("qpdf", "main QTest array indirect", QTC::TC("qpdf", "main QTest array indirect",
iter.isIndirect() ? 1 : 0); iter.isIndirect() ? 1 : 0);
@ -366,7 +366,7 @@ void runtest(int n, char const* filename1, char const* arg2)
{ {
QTC::TC("qpdf", "main QTest dictionary"); QTC::TC("qpdf", "main QTest dictionary");
std::cout << "/QTest is a dictionary" << std::endl; 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", QTC::TC("qpdf", "main QTest dictionary indirect",
iter.second.isIndirect() ? 1 : 0); iter.second.isIndirect() ? 1 : 0);
@ -1545,7 +1545,7 @@ void runtest(int n, char const* filename1, char const* arg2)
assert(array.isArray()); assert(array.isArray());
{ {
// Exercise iterators directly // Exercise iterators directly
QPDFArrayItems ai(array); auto ai = array.aitems();
auto i = ai.begin(); auto i = ai.begin();
assert(i->getName() == "/Item0"); assert(i->getName() == "/Item0");
auto& i_value = *i; auto& i_value = *i;
@ -1565,7 +1565,7 @@ void runtest(int n, char const* filename1, char const* arg2)
assert(dictionary.isDictionary()); assert(dictionary.isDictionary());
{ {
// Exercise iterators directly // Exercise iterators directly
QPDFDictItems di(dictionary); auto di = dictionary.ditems();
auto i = di.begin(); auto i = di.begin();
assert(i->first == "/Key1"); assert(i->first == "/Key1");
auto& i_value = *i; auto& i_value = *i;