Coverage Report

Created: 2025-08-26 07:08

/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
6.96k
    QPDFDocumentHelper(qpdf),
7
6.96k
    m(new Members())
8
6.96k
{
9
6.96k
    QPDFObjectHandle root = qpdf.getRoot();
10
6.96k
    if (!root.hasKey("/Outlines")) {
11
6.23k
        return;
12
6.23k
    }
13
729
    QPDFObjectHandle outlines = root.getKey("/Outlines");
14
729
    if (!(outlines.isDictionary() && outlines.hasKey("/First"))) {
15
65
        return;
16
65
    }
17
664
    QPDFObjectHandle cur = outlines.getKey("/First");
18
664
    QPDFObjGen::set seen;
19
1.75k
    while (!cur.isNull() && seen.add(cur)) {
20
1.09k
        m->outlines.push_back(QPDFOutlineObjectHelper::Accessor::create(cur, *this, 1));
21
1.09k
        cur = cur.getKey("/Next");
22
1.09k
    }
23
664
}
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
9.04k
{
40
9.04k
    std::list<QPDFOutlineObjectHelper> queue;
41
9.04k
    queue.insert(queue.end(), m->outlines.begin(), m->outlines.end());
42
43
13.7k
    while (!queue.empty()) {
44
4.68k
        QPDFOutlineObjectHelper oh = queue.front();
45
4.68k
        queue.pop_front();
46
4.68k
        m->by_page[oh.getDestPage().getObjGen()].push_back(oh);
47
4.68k
        std::vector<QPDFOutlineObjectHelper> kids = oh.getKids();
48
4.68k
        queue.insert(queue.end(), kids.begin(), kids.end());
49
4.68k
    }
50
9.04k
}
51
52
std::vector<QPDFOutlineObjectHelper>
53
QPDFOutlineDocumentHelper::getOutlinesForPage(QPDFObjGen og)
54
9.42k
{
55
9.42k
    if (m->by_page.empty()) {
56
9.04k
        initializeByPage();
57
9.04k
    }
58
9.42k
    std::vector<QPDFOutlineObjectHelper> result;
59
9.42k
    if (m->by_page.contains(og)) {
60
192
        result = m->by_page[og];
61
192
    }
62
9.42k
    return result;
63
9.42k
}
64
65
QPDFObjectHandle
66
QPDFOutlineDocumentHelper::resolveNamedDest(QPDFObjectHandle name)
67
1.11k
{
68
1.11k
    QPDFObjectHandle result;
69
1.11k
    if (name.isName()) {
70
185
        if (!m->dest_dict) {
71
46
            m->dest_dict = qpdf.getRoot().getKey("/Dests");
72
46
        }
73
185
        QTC::TC("qpdf", "QPDFOutlineDocumentHelper name named dest");
74
185
        result = m->dest_dict.getKeyIfDict(name.getName());
75
934
    } else if (name.isString()) {
76
934
        if (!m->names_dest) {
77
629
            auto dests = qpdf.getRoot().getKey("/Names").getKeyIfDict("/Dests");
78
629
            if (dests.isDictionary()) {
79
353
                m->names_dest = std::make_shared<QPDFNameTreeObjectHelper>(dests, qpdf);
80
353
            }
81
629
        }
82
934
        if (m->names_dest) {
83
658
            if (m->names_dest->findObject(name.getUTF8Value(), result)) {
84
116
                QTC::TC("qpdf", "QPDFOutlineDocumentHelper string named dest");
85
116
            }
86
658
        }
87
934
    }
88
1.11k
    if (!result) {
89
601
        return QPDFObjectHandle::newNull();
90
601
    }
91
518
    if (result.isDictionary()) {
92
41
        QTC::TC("qpdf", "QPDFOutlineDocumentHelper named dest dictionary");
93
41
        return result.getKey("/D");
94
41
    }
95
477
    return result;
96
518
}