Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibPDF/ObjectDerivatives.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2021-2022, Matthew Olsson <mattco@serenityos.org>
3
 * Copyright (c) 2021, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
4
 *
5
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#pragma once
9
10
#include <AK/DeprecatedFlyString.h>
11
#include <AK/HashMap.h>
12
#include <AK/RefCounted.h>
13
#include <AK/SourceLocation.h>
14
#include <LibPDF/Forward.h>
15
#include <LibPDF/Object.h>
16
#include <LibPDF/Value.h>
17
18
namespace PDF {
19
20
class StringObject final : public Object {
21
public:
22
    StringObject(ByteString string, bool is_binary)
23
0
        : m_string(move(string))
24
0
        , m_is_binary(is_binary)
25
0
    {
26
0
    }
27
28
0
    ~StringObject() override = default;
29
30
0
    [[nodiscard]] ALWAYS_INLINE ByteString const& string() const { return m_string; }
31
0
    [[nodiscard]] ALWAYS_INLINE bool is_binary() const { return m_is_binary; }
32
0
    void set_string(ByteString string) { m_string = move(string); }
33
34
0
    char const* type_name() const override { return "string"; }
35
    ByteString to_byte_string(int indent) const override;
36
37
protected:
38
0
    bool is_string() const override { return true; }
39
40
private:
41
    ByteString m_string;
42
    bool m_is_binary;
43
};
44
45
class NameObject final : public Object {
46
public:
47
    explicit NameObject(DeprecatedFlyString name)
48
65
        : m_name(move(name))
49
65
    {
50
65
    }
51
52
65
    ~NameObject() override = default;
53
54
62
    [[nodiscard]] ALWAYS_INLINE DeprecatedFlyString const& name() const { return m_name; }
55
56
0
    char const* type_name() const override { return "name"; }
57
    ByteString to_byte_string(int indent) const override;
58
59
protected:
60
0
    bool is_name() const override { return true; }
61
62
private:
63
    DeprecatedFlyString m_name;
64
};
65
66
class ArrayObject final : public Object {
67
public:
68
    explicit ArrayObject(Vector<Value> elements)
69
6
        : m_elements(move(elements))
70
6
    {
71
6
    }
72
73
6
    ~ArrayObject() override = default;
74
75
6
    [[nodiscard]] ALWAYS_INLINE size_t size() const { return m_elements.size(); }
76
0
    [[nodiscard]] ALWAYS_INLINE Vector<Value> elements() const { return m_elements; }
77
    [[nodiscard]] Vector<float> float_elements() const;
78
79
0
    ALWAYS_INLINE auto begin() const { return m_elements.begin(); }
80
0
    ALWAYS_INLINE auto end() const { return m_elements.end(); }
81
82
0
    ALWAYS_INLINE Value const& operator[](size_t index) const { return at(index); }
83
12
    ALWAYS_INLINE Value const& at(size_t index) const { return m_elements[index]; }
84
85
    PDFErrorOr<NonnullRefPtr<Object>> get_object_at(Document* document, size_t index) const;
86
0
    NonnullRefPtr<Object> get_object_at(size_t index) const { return at(index).get<NonnullRefPtr<Object>>(); }
87
88
#define DEFINE_INDEXER(class_name, snake_name)                                                  \
89
    PDFErrorOr<NonnullRefPtr<class_name>> get_##snake_name##_at(Document*, size_t index) const; \
90
    NonnullRefPtr<class_name> get_##snake_name##_at(size_t index) const;
91
    ENUMERATE_OBJECT_TYPES(DEFINE_INDEXER)
92
#undef DEFINE_INDEXER
93
94
    char const* type_name() const override
95
0
    {
96
0
        return "array";
97
0
    }
98
    ByteString to_byte_string(int indent) const override;
99
100
protected:
101
6
    bool is_array() const override { return true; }
102
103
private:
104
    Vector<Value> m_elements;
105
};
106
107
class DictObject final : public Object {
108
public:
109
    explicit DictObject(HashMap<DeprecatedFlyString, Value> map)
110
11
        : m_map(move(map))
111
11
    {
112
11
    }
113
114
11
    ~DictObject() override = default;
115
116
0
    [[nodiscard]] ALWAYS_INLINE HashMap<DeprecatedFlyString, Value> const& map() const { return m_map; }
117
118
    template<typename... Args>
119
60
    bool contains(Args&&... keys) const { return (m_map.contains(keys) && ...); }
Unexecuted instantiation: bool PDF::DictObject::contains<AK::DeprecatedFlyString const&>(AK::DeprecatedFlyString const&) const
bool PDF::DictObject::contains<AK::DeprecatedFlyString&>(AK::DeprecatedFlyString&) const
Line
Count
Source
119
9
    bool contains(Args&&... keys) const { return (m_map.contains(keys) && ...); }
bool PDF::DictObject::contains<AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&>(AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&, AK::DeprecatedFlyString&) const
Line
Count
Source
119
60
    bool contains(Args&&... keys) const { return (m_map.contains(keys) && ...); }
Unexecuted instantiation: bool PDF::DictObject::contains<AK::ByteString&>(AK::ByteString&) const
120
121
    template<typename... Args>
122
0
    bool contains_any_of(Args&&... keys) const { return (m_map.contains(keys) || ...); }
123
124
42
    ALWAYS_INLINE Optional<Value> get(DeprecatedFlyString const& key) const { return m_map.get(key).copy(); }
125
126
    Value get_value(DeprecatedFlyString const& key) const
127
36
    {
128
36
        auto value = get(key);
129
36
        VERIFY(value.has_value());
130
36
        return value.value();
131
36
    }
132
133
    PDFErrorOr<NonnullRefPtr<Object>> get_object(Document*, DeprecatedFlyString const& key) const;
134
135
#define DEFINE_GETTER(class_name, snake_name)                                                                \
136
    PDFErrorOr<NonnullRefPtr<class_name>> get_##snake_name(Document*, DeprecatedFlyString const& key) const; \
137
    NonnullRefPtr<class_name> get_##snake_name(DeprecatedFlyString const& key) const;
138
    ENUMERATE_OBJECT_TYPES(DEFINE_GETTER)
139
#undef DEFINE_GETTER
140
141
    char const* type_name() const override
142
0
    {
143
0
        return "dict";
144
0
    }
145
    ByteString to_byte_string(int indent) const override;
146
147
protected:
148
18
    bool is_dict() const override { return true; }
149
150
private:
151
    HashMap<DeprecatedFlyString, Value> m_map;
152
};
153
154
class StreamObject : public Object {
155
public:
156
    explicit StreamObject(NonnullRefPtr<DictObject> const& dict, ByteBuffer const& bytes)
157
0
        : m_dict(dict)
158
0
        , m_buffer(bytes)
159
0
    {
160
0
    }
161
162
0
    virtual ~StreamObject() override = default;
163
164
0
    [[nodiscard]] ALWAYS_INLINE NonnullRefPtr<DictObject> dict() const { return m_dict; }
165
0
    [[nodiscard]] ReadonlyBytes bytes() const { return m_buffer.bytes(); }
166
0
    [[nodiscard]] ByteBuffer& buffer() { return m_buffer; }
167
168
0
    char const* type_name() const override { return "stream"; }
169
    ByteString to_byte_string(int indent) const override;
170
171
private:
172
0
    bool is_stream() const override { return true; }
173
174
    NonnullRefPtr<DictObject> m_dict;
175
    ByteBuffer m_buffer;
176
};
177
178
class IndirectValue final : public Object {
179
public:
180
    IndirectValue(u32 index, u32 generation_index, Value const& value)
181
9
        : m_index(index)
182
9
        , m_value(value)
183
9
    {
184
9
        set_generation_index(generation_index);
185
9
    }
186
187
9
    ~IndirectValue() override = default;
188
189
0
    [[nodiscard]] ALWAYS_INLINE u32 index() const { return m_index; }
190
9
    [[nodiscard]] ALWAYS_INLINE Value const& value() const { return m_value; }
191
192
0
    char const* type_name() const override { return "indirect_object"; }
193
    ByteString to_byte_string(int indent) const override;
194
195
protected:
196
0
    bool is_indirect_value() const override { return true; }
197
198
private:
199
    u32 m_index;
200
    Value m_value;
201
};
202
203
template<IsValueType T>
204
UnwrappedValueType<T> cast_to(Value const& value)
205
6
{
206
    if constexpr (IsSame<T, bool>)
207
        return value.get<bool>();
208
    else if constexpr (IsSame<T, int>)
209
6
        return value.get<int>();
210
    else if constexpr (IsSame<T, float>)
211
        return value.get<float>();
212
    else if constexpr (IsSame<T, Object>)
213
0
        return value.get<NonnullRefPtr<Object>>();
214
    else if constexpr (IsObject<T>)
215
0
        return value.get<NonnullRefPtr<Object>>()->cast<T>();
216
6
    VERIFY_NOT_REACHED();
217
6
}
_ZN3PDF7cast_toITkNS_11IsValueTypeEiEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS1_13NonnullRefPtrIS4_EES4_E4TypeERKNS_5ValueE
Line
Count
Source
205
6
{
206
    if constexpr (IsSame<T, bool>)
207
        return value.get<bool>();
208
    else if constexpr (IsSame<T, int>)
209
6
        return value.get<int>();
210
    else if constexpr (IsSame<T, float>)
211
        return value.get<float>();
212
    else if constexpr (IsSame<T, Object>)
213
        return value.get<NonnullRefPtr<Object>>();
214
    else if constexpr (IsObject<T>)
215
        return value.get<NonnullRefPtr<Object>>()->cast<T>();
216
6
    VERIFY_NOT_REACHED();
217
6
}
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_10DictObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_6ObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_12StringObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_10NameObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_11ArrayObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_12StreamObjectEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
Unexecuted instantiation: _ZN3PDF7cast_toITkNS_11IsValueTypeENS_13IndirectValueEEEN2AK6Detail13__ConditionalIX8IsObjectIT_EENS2_13NonnullRefPtrIS5_EES5_E4TypeERKNS_5ValueE
218
219
}