Coverage Report

Created: 2026-04-12 06:58

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