aboutsummaryrefslogtreecommitdiffstats
path: root/libqpdf
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2018-12-19 03:08:53 +0100
committerJay Berkenbilt <ejb@ql.org>2018-12-22 01:11:57 +0100
commitd5d179f4419dfbbbc3598b91071f6ca7cc44357c (patch)
treec2824094f0ac9aed1788014b6a2031e803a8a3bd /libqpdf
parent30a0c070e41212172f5516936594ec0f6e72ac70 (diff)
downloadqpdf-d5d179f4419dfbbbc3598b91071f6ca7cc44357c.tar.zst
Add document and object helpers for outlines (bookmarks)
Diffstat (limited to 'libqpdf')
-rw-r--r--libqpdf/QPDFOutlineDocumentHelper.cc137
-rw-r--r--libqpdf/QPDFOutlineObjectHelper.cc117
-rw-r--r--libqpdf/build.mk2
3 files changed, 256 insertions, 0 deletions
diff --git a/libqpdf/QPDFOutlineDocumentHelper.cc b/libqpdf/QPDFOutlineDocumentHelper.cc
new file mode 100644
index 00000000..411ccf34
--- /dev/null
+++ b/libqpdf/QPDFOutlineDocumentHelper.cc
@@ -0,0 +1,137 @@
+#include <qpdf/QPDFOutlineDocumentHelper.hh>
+#include <qpdf/QTC.hh>
+
+QPDFOutlineDocumentHelper::Members::~Members()
+{
+}
+
+QPDFOutlineDocumentHelper::Members::Members()
+{
+}
+
+QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) :
+ QPDFDocumentHelper(qpdf),
+ m(new Members())
+{
+ QPDFObjectHandle root = qpdf.getRoot();
+ if (! root.hasKey("/Outlines"))
+ {
+ return;
+ }
+ QPDFObjectHandle outlines = root.getKey("/Outlines");
+ if (! (outlines.isDictionary() && outlines.hasKey("/First")))
+ {
+ return;
+ }
+ QPDFObjectHandle cur = outlines.getKey("/First");
+ while (! cur.isNull())
+ {
+ this->m->outlines.push_back(
+ QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
+ cur = cur.getKey("/Next");
+ }
+}
+
+QPDFOutlineDocumentHelper::~QPDFOutlineDocumentHelper()
+{
+}
+
+bool
+QPDFOutlineDocumentHelper::hasOutlines()
+{
+ return ! this->m->outlines.empty();
+}
+
+std::list<QPDFOutlineObjectHelper>
+QPDFOutlineDocumentHelper::getTopLevelOutlines()
+{
+ return this->m->outlines;
+}
+
+void
+QPDFOutlineDocumentHelper::initializeByPage()
+{
+ std::list<QPDFOutlineObjectHelper> queue;
+ queue.insert(queue.end(), this->m->outlines.begin(), this->m->outlines.end());
+
+ while (! queue.empty())
+ {
+ QPDFOutlineObjectHelper oh = queue.front();
+ queue.pop_front();
+ this->m->by_page[oh.getDestPage().getObjGen()].push_back(oh);
+ std::list<QPDFOutlineObjectHelper> kids = oh.getKids();
+ queue.insert(queue.end(), kids.begin(), kids.end());
+ }
+}
+
+std::list<QPDFOutlineObjectHelper>
+QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen const& og)
+{
+ if (this->m->by_page.empty())
+ {
+ initializeByPage();
+ }
+ std::list<QPDFOutlineObjectHelper> result;
+ if (this->m->by_page.count(og))
+ {
+ result = this->m->by_page[og];
+ }
+ return result;
+}
+
+QPDFObjectHandle
+QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
+{
+ QPDFObjectHandle result;
+ if (name.isName())
+ {
+ if (! this->m->dest_dict.isInitialized())
+ {
+ this->m->dest_dict = this->qpdf.getRoot().getKey("/Dests");
+ }
+ if (this->m->dest_dict.isDictionary())
+ {
+ QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
+ result = this->m->dest_dict.getKey(name.getName());
+ }
+ }
+ else if (name.isString())
+ {
+ if (0 == this->m->names_dest.getPointer())
+ {
+ QPDFObjectHandle names = this->qpdf.getRoot().getKey("/Names");
+ if (names.isDictionary())
+ {
+ QPDFObjectHandle dests = names.getKey("/Dests");
+ if (dests.isDictionary())
+ {
+ this->m->names_dest =
+ new QPDFNameTreeObjectHelper(dests);
+ }
+ }
+ }
+ if (this->m->names_dest.getPointer())
+ {
+ if (this->m->names_dest->findObject(name.getUTF8Value(), result))
+ {
+ QTC::TC("qpdf", "QPDFOutlineDocumentHelper string named dest");
+ }
+ }
+ }
+ if (! result.isInitialized())
+ {
+ result = QPDFObjectHandle::newNull();
+ }
+ return result;
+}
+
+bool
+QPDFOutlineDocumentHelper::checkSeen(QPDFObjGen const& og)
+{
+ if (this->m->seen.count(og) > 0)
+ {
+ return true;
+ }
+ this->m->seen.insert(og);
+ return false;
+}
diff --git a/libqpdf/QPDFOutlineObjectHelper.cc b/libqpdf/QPDFOutlineObjectHelper.cc
new file mode 100644
index 00000000..e8eb11d0
--- /dev/null
+++ b/libqpdf/QPDFOutlineObjectHelper.cc
@@ -0,0 +1,117 @@
+#include <qpdf/QPDFOutlineObjectHelper.hh>
+#include <qpdf/QPDFOutlineDocumentHelper.hh>
+#include <qpdf/QTC.hh>
+
+QPDFOutlineObjectHelper::Members::~Members()
+{
+}
+
+QPDFOutlineObjectHelper::Members::Members(QPDFOutlineDocumentHelper& dh) :
+ dh(dh)
+{
+}
+
+QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
+ QPDFObjectHandle oh, QPDFOutlineDocumentHelper& dh, int depth) :
+ QPDFObjectHelper(oh),
+ m(new Members(dh))
+{
+ if (depth > 50)
+ {
+ // Not exercised in test suite, but was tested manually by
+ // temporarily changing max depth to 1.
+ return;
+ }
+ if (QPDFOutlineDocumentHelper::Accessor::checkSeen(
+ this->m->dh, this->oh.getObjGen()))
+ {
+ QTC::TC("qpdf", "QPDFOutlineObjectHelper loop");
+ return;
+ }
+
+ QPDFObjectHandle cur = oh.getKey("/First");
+ while (! cur.isNull())
+ {
+ QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth);
+ new_ooh.m->parent = new QPDFOutlineObjectHelper(*this);
+ this->m->kids.push_back(new_ooh);
+ cur = cur.getKey("/Next");
+ }
+}
+
+PointerHolder<QPDFOutlineObjectHelper>
+QPDFOutlineObjectHelper::getParent()
+{
+ return this->m->parent;
+}
+
+std::list<QPDFOutlineObjectHelper>
+QPDFOutlineObjectHelper::getKids()
+{
+ return this->m->kids;
+}
+
+QPDFObjectHandle
+QPDFOutlineObjectHelper::getDest()
+{
+ QPDFObjectHandle dest;
+ QPDFObjectHandle A;
+ if (this->oh.hasKey("/Dest"))
+ {
+ QTC::TC("qpdf", "QPDFOutlineObjectHelper direct dest");
+ dest = this->oh.getKey("/Dest");
+ }
+ else if ((A = this->oh.getKey("/A")).isDictionary() &&
+ A.getKey("/S").isName() &&
+ (A.getKey("/S").getName() == "/GoTo") &&
+ A.hasKey("/D"))
+ {
+ QTC::TC("qpdf", "QPDFOutlineObjectHelper action dest");
+ dest = A.getKey("/D");
+ }
+ if (! dest.isInitialized())
+ {
+ dest = QPDFObjectHandle::newNull();
+ }
+
+ if (dest.isName() || dest.isString())
+ {
+ QTC::TC("qpdf", "QPDFOutlineObjectHelper named dest");
+ dest = this->m->dh.resolveNamedDest(dest);
+ }
+
+ return dest;
+}
+
+QPDFObjectHandle
+QPDFOutlineObjectHelper::getDestPage()
+{
+ QPDFObjectHandle dest = getDest();
+ if ((dest.isArray()) && (dest.getArrayNItems() > 0))
+ {
+ return dest.getArrayItem(0);
+ }
+ return QPDFObjectHandle::newNull();
+}
+
+int
+QPDFOutlineObjectHelper::getCount()
+{
+ int count = 0;
+ if (this->oh.hasKey("/Count"))
+ {
+ count = this->oh.getKey("/Count").getIntValue();
+ }
+ return count;
+}
+
+std::string
+QPDFOutlineObjectHelper::getTitle()
+{
+ std::string result;
+ if (this->oh.hasKey("/Title"))
+ {
+ result = this->oh.getKey("/Title").getUTF8Value();
+ }
+ return result;
+}
diff --git a/libqpdf/build.mk b/libqpdf/build.mk
index 87252b5a..e063df0c 100644
--- a/libqpdf/build.mk
+++ b/libqpdf/build.mk
@@ -46,6 +46,8 @@ SRCS_libqpdf = \
libqpdf/QPDFObjGen.cc \
libqpdf/QPDFObject.cc \
libqpdf/QPDFObjectHandle.cc \
+ libqpdf/QPDFOutlineDocumentHelper.cc \
+ libqpdf/QPDFOutlineObjectHelper.cc \
libqpdf/QPDFPageDocumentHelper.cc \
libqpdf/QPDFPageLabelDocumentHelper.cc \
libqpdf/QPDFPageObjectHelper.cc \