Coverage Report

Created: 2026-06-09 06:59

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
3.75k
    dh(dh)
9
3.75k
{
10
3.75k
}
11
12
QPDFOutlineObjectHelper::QPDFOutlineObjectHelper(
13
    QPDFObjectHandle a_oh, QPDFOutlineDocumentHelper& dh, int depth) :
14
3.75k
    QPDFObjectHelper(a_oh),
15
3.75k
    m(new Members(dh))
16
3.75k
{
17
3.75k
    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
3.75k
    if (QPDFOutlineDocumentHelper::Accessor::checkSeen(m->dh, a_oh.getObjGen())) {
23
1.39k
        a_oh.warn("Loop detected loop in /Outlines tree");
24
1.39k
        return;
25
1.39k
    }
26
27
2.35k
    QPDFObjGen::set children;
28
2.35k
    QPDFObjectHandle cur = a_oh.getKey("/First");
29
4.98k
    while (!cur.null() && cur.isIndirect()) {
30
2.77k
        if (!children.add(cur)) {
31
139
            cur.warn("Loop detected loop in /Outlines tree");
32
139
            break;
33
139
        }
34
2.63k
        QPDFOutlineObjectHelper new_ooh(cur, dh, 1 + depth);
35
2.63k
        new_ooh.m->parent = std::make_shared<QPDFOutlineObjectHelper>(*this);
36
2.63k
        m->kids.emplace_back(new_ooh);
37
2.63k
        cur = cur.getKey("/Next");
38
2.63k
    }
39
2.35k
}
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
3.51k
{
50
3.51k
    return m->kids;
51
3.51k
}
52
53
QPDFObjectHandle
54
QPDFOutlineObjectHelper::getDest()
55
3.80k
{
56
3.80k
    auto dest = get("/Dest");
57
3.80k
    if (dest.null()) {
58
2.68k
        auto const& A = get("/A");
59
2.68k
        if (Name(A["/S"]) == "/GoTo") {
60
828
            dest = A["/D"];
61
828
        }
62
2.68k
    }
63
3.80k
    if (dest.null()) {
64
1.87k
        return QPDFObjectHandle::newNull();
65
1.87k
    }
66
1.92k
    if (dest.isName() || dest.isString()) {
67
1.24k
        return m->dh.resolveNamedDest(dest);
68
1.24k
    }
69
680
    return dest;
70
1.92k
}
71
72
QPDFObjectHandle
73
QPDFOutlineObjectHelper::getDestPage()
74
3.80k
{
75
3.80k
    QPDFObjectHandle dest = getDest();
76
3.80k
    if (!dest.empty() && dest.isArray()) {
77
772
        return dest.getArrayItem(0);
78
772
    }
79
3.02k
    return QPDFObjectHandle::newNull();
80
3.80k
}
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
}