Coverage Report

Created: 2026-01-25 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
7.99k
    dh(dh)
9
7.99k
{
10
7.99k
}
11
12
QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
13
    QPDFObjectHandle a_oh, QPDFOutlineDocumentHelper& dh, int depth) :
14
7.99k
    QPDFObjectHelper(a_oh),
15
7.99k
    m(new Members(dh))
16
7.99k
{
17
7.99k
    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
7.99k
    if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) {
23
3.84k
        a_oh.warn("Loop detected loop in /Outlines tree");
24
3.84k
        return;
25
3.84k
    }
26
27
4.14k
    QPDFObjGen::set children;
28
4.14k
    QPDFObjectHandle cur = a_oh.getKey("/First");
29
9.84k
    while (!cur.null() && cur.isIndirect()) {
30
5.89k
        if (!children.add(cur)) {
31
199
            cur.warn("Loop detected loop in /Outlines tree");
32
199
            break;
33
199
        }
34
5.69k
        QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth);
35
5.69k
        new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this);
36
5.69k
        m->kids.emplace_back(new_ooh);
37
5.69k
        cur = cur.getKey("/Next");
38
5.69k
    }
39
4.14k
}
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
7.32k
{
50
7.32k
    return m->kids;
51
7.32k
}
52
53
QPDFObjectHandle
54
QPDFOutlineObjectHelper::getDest()
55
7.53k
{
56
7.53k
    auto dest = get("/Dest");
57
7.53k
    if (dest.null()) {
58
6.38k
        auto const& A = get("/A");
59
6.38k
        if (Name(A["/S"]) == "/GoTo") {
60
2.29k
            dest = A["/D"];
61
2.29k
        }
62
6.38k
    }
63
7.53k
    if (dest.null()) {
64
4.13k
        return QPDFObjectHandle::newNull();
65
4.13k
    }
66
3.39k
    if (dest.isName() || dest.isString()) {
67
2.93k
        return m->dh.resolveNamedDest(dest);
68
2.93k
    }
69
461
    return dest;
70
3.39k
}
71
72
QPDFObjectHandle
73
QPDFOutlineObjectHelper::getDestPage()
74
7.53k
{
75
7.53k
    QPDFObjectHandle dest = getDest();
76
7.53k
    if (!dest.empty() && dest.isArray()) {
77
433
        return dest.getArrayItem(0);
78
433
    }
79
7.10k
    return QPDFObjectHandle::newNull();
80
7.53k
}
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
}