/src/qpdf/libqpdf/QPDFOutlineDocumentHelper.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include <qpdf/QPDFOutlineDocumentHelper.hh> |
2 | | |
3 | | #include <qpdf/QTC.hh> |
4 | | |
5 | | QPDFOutlineDocumentHelper::QPDFOutlineDocumentHelper(QPDF& qpdf) : |
6 | 7.08k | QPDFDocumentHelper(qpdf), |
7 | 7.08k | m(new Members()) |
8 | 7.08k | { |
9 | 7.08k | QPDFObjectHandle root = qpdf.getRoot(); |
10 | 7.08k | if (!root.hasKey("/Outlines")) { |
11 | 6.56k | return; |
12 | 6.56k | } |
13 | 518 | QPDFObjectHandle outlines = root.getKey("/Outlines"); |
14 | 518 | if (!(outlines.isDictionary() && outlines.hasKey("/First"))) { |
15 | 41 | return; |
16 | 41 | } |
17 | 477 | QPDFObjectHandle cur = outlines.getKey("/First"); |
18 | 477 | QPDFObjGen::set seen; |
19 | 1.28k | while (!cur.isNull() && seen.add(cur)) { |
20 | 812 | m->outlines.push_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1)); |
21 | 812 | cur = cur.getKey("/Next"); |
22 | 812 | } |
23 | 477 | } |
24 | | |
25 | | bool |
26 | | QPDFOutlineDocumentHelper::hasOutlines() |
27 | 0 | { |
28 | 0 | return !m->outlines.empty(); |
29 | 0 | } |
30 | | |
31 | | std::vector<QPDFOutlineObjectHelper> |
32 | | QPDFOutlineDocumentHelper::getTopLevelOutlines() |
33 | 0 | { |
34 | 0 | return m->outlines; |
35 | 0 | } |
36 | | |
37 | | void |
38 | | QPDFOutlineDocumentHelper::initializeByPage() |
39 | 15.1k | { |
40 | 15.1k | std::list<QPDFOutlineObjectHelper> queue; |
41 | 15.1k | queue.insert(queue.end(), m->outlines.begin(), m->outlines.end()); |
42 | | |
43 | 18.0k | while (!queue.empty()) { |
44 | 2.90k | QPDFOutlineObjectHelper oh = queue.front(); |
45 | 2.90k | queue.pop_front(); |
46 | 2.90k | m->by_page[oh.getDestPage().getObjGen()].push_back(oh); |
47 | 2.90k | std::vector<QPDFOutlineObjectHelper> kids = oh.getKids(); |
48 | 2.90k | queue.insert(queue.end(), kids.begin(), kids.end()); |
49 | 2.90k | } |
50 | 15.1k | } |
51 | | |
52 | | std::vector<QPDFOutlineObjectHelper> |
53 | | QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og) |
54 | 15.6k | { |
55 | 15.6k | if (m->by_page.empty()) { |
56 | 15.1k | initializeByPage(); |
57 | 15.1k | } |
58 | 15.6k | std::vector<QPDFOutlineObjectHelper> result; |
59 | 15.6k | if (m->by_page.contains(og)) { |
60 | 182 | result = m->by_page[og]; |
61 | 182 | } |
62 | 15.6k | return result; |
63 | 15.6k | } |
64 | | |
65 | | QPDFObjectHandle |
66 | | QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name) |
67 | 872 | { |
68 | 872 | QPDFObjectHandle result; |
69 | 872 | if (name.isName()) { |
70 | 135 | if (!m->dest_dict) { |
71 | 27 | m->dest_dict = qpdf.getRoot().getKey("/Dests"); |
72 | 27 | } |
73 | 135 | QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest"); |
74 | 135 | result = m->dest_dict.getKeyIfDict(name.getName()); |
75 | 737 | } else if (name.isString()) { |
76 | 737 | if (!m->names_dest) { |
77 | 385 | auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests"); |
78 | 385 | if (dests.isDictionary()) { |
79 | 218 | m->names_dest = std::make_shared<QPDFNameTreeObjectHelper>(dests, qpdf); |
80 | 218 | } |
81 | 385 | } |
82 | 737 | if (m->names_dest) { |
83 | 570 | if (m->names_dest->findObject(name.getUTF8Value(), result)) { |
84 | 250 | QTC::TC("qpdf", "QPDFOutlineDocumentHelper string named dest"); |
85 | 250 | } |
86 | 570 | } |
87 | 737 | } |
88 | 872 | if (!result) { |
89 | 366 | return QPDFObjectHandle::newNull(); |
90 | 366 | } |
91 | 506 | if (result.isDictionary()) { |
92 | 23 | QTC::TC("qpdf", "QPDFOutlineDocumentHelper named dest dictionary"); |
93 | 23 | return result.getKey("/D"); |
94 | 23 | } |
95 | 483 | return result; |
96 | 506 | } |