Coverage Report

Created: 2025-08-29 06:53

/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
}