QPDFOutlineDocumentHelper.cc
3.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <qpdf/QPDFOutlineDocumentHelper.hh>
#include <qpdf/QPDFObjectHandle_private.hh>
#include <qpdf/QPDF_private.hh>
#include <qpdf/QTC.hh>
class QPDFOutlineDocumentHelper::Members
{
public:
Members() = default;
Members(Members const&) = delete;
~Members() = default;
std::vector<QPDFOutlineObjectHelper> outlines;
QPDFObjGen::set seen;
QPDFObjectHandle dest_dict;
std::unique_ptr<QPDFNameTreeObjectHelper> names_dest;
std::map<QPDFObjGen, std::vector<QPDFOutlineObjectHelper>> by_page;
};
bool
QPDFOutlineDocumentHelper::Accessor::checkSeen(QPDFOutlineDocumentHelper& dh, QPDFObjGen og)
{
return !dh.m->seen.add(og);
}
QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) :
QPDFDocumentHelper(qpdf),
m(std::make_shared<Members>())
{
validate();
}
QPDFOutlineDocumentHelper&
QPDFOutlineDocumentHelper::get(QPDF& qpdf)
{
return qpdf.outlines();
}
void
QPDFOutlineDocumentHelper::validate(bool repair)
{
m->outlines.clear();
m->names_dest = nullptr;
QPDFObjectHandle root = qpdf.getRoot();
if (!root.hasKey("/Outlines")) {
return;
}
auto outlines = root.getKey("/Outlines");
if (!(outlines.isDictionary() && outlines.hasKey("/First"))) {
return;
}
QPDFObjectHandle cur = outlines.getKey("/First");
QPDFObjGen::set seen;
while (!cur.null() && seen.add(cur)) {
m->outlines.emplace_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
cur = cur.getKey("/Next");
}
}
bool
QPDFOutlineDocumentHelper::hasOutlines()
{
return !m->outlines.empty();
}
std::vector<QPDFOutlineObjectHelper>
QPDFOutlineDocumentHelper::getTopLevelOutlines()
{
return m->outlines;
}
void
QPDFOutlineDocumentHelper::initializeByPage()
{
std::list<QPDFOutlineObjectHelper> queue;
queue.insert(queue.end(), m->outlines.begin(), m->outlines.end());
while (!queue.empty()) {
QPDFOutlineObjectHelper oh = queue.front();
queue.pop_front();
m->by_page[oh.getDestPage().getObjGen()].push_back(oh);
std::vector<QPDFOutlineObjectHelper> kids = oh.getKids();
queue.insert(queue.end(), kids.begin(), kids.end());
}
}
std::vector<QPDFOutlineObjectHelper>
QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og)
{
if (m->by_page.empty()) {
initializeByPage();
}
if (m->by_page.contains(og)) {
return m->by_page[og];
}
return {};
}
QPDFObjectHandle
QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
{
QPDFObjectHandle result;
if (name.isName()) {
if (!m->dest_dict) {
m->dest_dict = qpdf.getRoot().getKey("/Dests");
}
result = m->dest_dict.getKeyIfDict(name.getName());
} else if (name.isString()) {
if (!m->names_dest) {
auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests");
if (dests.isDictionary()) {
m->names_dest = std::make_unique<QPDFNameTreeObjectHelper>(
dests,
qpdf,
[](QPDFObjectHandle const& o) -> bool {
return o.isArray() || o.isDictionary();
},
true);
m->names_dest->validate();
}
}
if (m->names_dest) {
if (m->names_dest->findObject(name.getUTF8Value(), result)) {
QTC::TC("qpdf", "QPDFOutlineDocumentHelper string named dest");
}
}
}
if (!result) {
return QPDFObjectHandle::newNull();
}
if (result.isDictionary()) {
return result.getKey("/D");
}
return result;
}