/src/qpdf/libqpdf/QPDFOutlineObjectHelper.cc
Line | Count | Source |
1 | | #include <qpdf/QPDFOutlineObjectHelper.hh> |
2 | | |
3 | | #include <qpdf/QPDFObjectHandle_private.hh> |
4 | | #include <qpdf/QPDFOutlineDocumentHelper.hh> |
5 | | #include <qpdf/QTC.hh> |
6 | | |
7 | | QPDFOutlineObjectHelper::Members::Members(QPDFOutlineDocumentHelper& dh) : |
8 | 25.1k | dh(dh) |
9 | 25.1k | { |
10 | 25.1k | } |
11 | | |
12 | | QPDFOutlineObjectHelper::QPDFOutlineObjectHelper( |
13 | | QPDFObjectHandle a_oh, QPDFOutlineDocumentHelper& dh, int depth) : |
14 | 25.1k | QPDFObjectHelper(a_oh), |
15 | 25.1k | m(new Members(dh)) |
16 | 25.1k | { |
17 | 25.1k | if (depth > 50) { |
18 | | // Not exercised in test suite, but was tested manually by temporarily changing max depth |
19 | | // to 1. |
20 | 0 | return; |
21 | 0 | } |
22 | 25.1k | if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) { |
23 | 12.2k | a_oh.warn("Loop detected loop in /Outlines tree"); |
24 | 12.2k | return; |
25 | 12.2k | } |
26 | | |
27 | 12.8k | QPDFObjGen::set children; |
28 | 12.8k | QPDFObjectHandle cur = a_oh.getKey("/First"); |
29 | 31.0k | while (!cur.null() && cur.isIndirect()) { |
30 | 19.3k | if (!children.add(cur)) { |
31 | 1.10k | cur.warn("Loop detected loop in /Outlines tree"); |
32 | 1.10k | break; |
33 | 1.10k | } |
34 | 18.2k | QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth); |
35 | 18.2k | new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this); |
36 | 18.2k | m->kids.emplace_back(new_ooh); |
37 | 18.2k | cur = cur.getKey("/Next"); |
38 | 18.2k | } |
39 | 12.8k | } |
40 | | |
41 | | std::shared_ptr<QPDFOutlineObjectHelper> |
42 | | QPDFOutlineObjectHelper::getParent() |
43 | 0 | { |
44 | 0 | return m->parent; |
45 | 0 | } |
46 | | |
47 | | std::vector<QPDFOutlineObjectHelper> |
48 | | QPDFOutlineObjectHelper::getKids() |
49 | 22.7k | { |
50 | 22.7k | return m->kids; |
51 | 22.7k | } |
52 | | |
53 | | QPDFObjectHandle |
54 | | QPDFOutlineObjectHelper::getDest() |
55 | 24.1k | { |
56 | 24.1k | auto dest = get("/Dest"); |
57 | 24.1k | if (dest.null()) { |
58 | 19.9k | auto const& A = get("/A"); |
59 | 19.9k | if (Name(A["/S"]) == "/GoTo") { |
60 | 8.33k | dest = A["/D"]; |
61 | 8.33k | } |
62 | 19.9k | } |
63 | 24.1k | if (dest.null()) { |
64 | 11.7k | return QPDFObjectHandle::newNull(); |
65 | 11.7k | } |
66 | 12.3k | if (dest.isName() || dest.isString()) { |
67 | 9.16k | return m->dh.resolveNamedDest(dest); |
68 | 9.16k | } |
69 | 3.20k | return dest; |
70 | 12.3k | } |
71 | | |
72 | | QPDFObjectHandle |
73 | | QPDFOutlineObjectHelper::getDestPage() |
74 | 24.1k | { |
75 | 24.1k | QPDFObjectHandle dest = getDest(); |
76 | 24.1k | if (!dest.empty() && dest.isArray()) { |
77 | 3.30k | return dest.getArrayItem(0); |
78 | 3.30k | } |
79 | 20.8k | return QPDFObjectHandle::newNull(); |
80 | 24.1k | } |
81 | | |
82 | | int |
83 | | QPDFOutlineObjectHelper::getCount() |
84 | 0 | { |
85 | 0 | int count = 0; |
86 | 0 | if (oh().hasKey("/Count")) { |
87 | 0 | count = oh().getKey("/Count").getIntValueAsInt(); |
88 | 0 | } |
89 | 0 | return count; |
90 | 0 | } |
91 | | |
92 | | std::string |
93 | | QPDFOutlineObjectHelper::getTitle() |
94 | 0 | { |
95 | 0 | std::string result; |
96 | 0 | if (oh().hasKey("/Title")) { |
97 | 0 | result = oh().getKey("/Title").getUTF8Value(); |
98 | 0 | } |
99 | 0 | return result; |
100 | 0 | } |