Coverage Report

Created: 2026-04-29 06:21

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