Coverage Report

Created: 2026-01-10 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qpdf/libqpdf/qpdf/QPDFObject_private.hh
Line
Count
Source
1
#ifndef QPDFOBJECT_HH
2
#define QPDFOBJECT_HH
3
4
// NOTE: This file is called QPDFObject_private.hh instead of QPDFObject.hh because of
5
// include/qpdf/QPDFObject.hh. See comments there for an explanation.
6
7
#include <qpdf/Constants.h>
8
#include <qpdf/Types.h>
9
10
#include <qpdf/JSON.hh>
11
#include <qpdf/JSON_writer.hh>
12
#include <qpdf/QPDF.hh>
13
#include <qpdf/QPDFObjGen.hh>
14
15
#include <map>
16
#include <memory>
17
#include <string>
18
#include <string_view>
19
#include <variant>
20
#include <vector>
21
22
class Disconnect;
23
class QPDFObject;
24
class QPDFObjectHandle;
25
26
namespace qpdf
27
{
28
    class Array;
29
    class BaseDictionary;
30
    class Dictionary;
31
    class Integer;
32
    class Name;
33
    class Stream;
34
    class String;
35
36
    namespace impl
37
    {
38
        class Writer;
39
    }
40
} // namespace qpdf
41
42
class QPDF_Array final
43
{
44
  private:
45
    struct Sparse
46
    {
47
        size_t size{0};
48
        std::map<size_t, QPDFObjectHandle> elements;
49
    };
50
51
  public:
52
0
    QPDF_Array() = default;
53
    QPDF_Array(QPDF_Array const& other) :
54
0
        sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr)
55
0
    {
56
0
    }
57
58
13.0k
    QPDF_Array(QPDF_Array&&) = default;
59
430
    QPDF_Array& operator=(QPDF_Array&&) = default;
60
61
  private:
62
    friend class QPDFObject;
63
    friend class qpdf::BaseHandle;
64
    friend class qpdf::Array;
65
66
    QPDF_Array(std::vector<QPDFObjectHandle> const& items) :
67
11.9k
        elements(items)
68
11.9k
    {
69
11.9k
    }
70
    QPDF_Array(std::vector<QPDFObjectHandle>&& items, bool sparse);
71
72
    QPDF_Array(std::vector<QPDFObjectHandle>&& items) :
73
0
        elements(std::move(items))
74
0
    {
75
0
    }
76
77
    size_t
78
    size() const
79
0
    {
80
0
        return sp ? sp->size : elements.size();
81
0
    }
82
83
    std::unique_ptr<Sparse> sp;
84
    std::vector<QPDFObjectHandle> elements;
85
};
86
87
class QPDF_Bool final
88
{
89
    friend class QPDFObject;
90
    friend class qpdf::BaseHandle;
91
    friend class QPDFObjectHandle;
92
93
    explicit QPDF_Bool(bool val) :
94
1.21k
        val(val)
95
1.21k
    {
96
1.21k
    }
97
    bool val;
98
};
99
100
class QPDF_Destroyed final
101
{
102
};
103
104
class QPDF_Dictionary final
105
{
106
    friend class QPDFObject;
107
    friend class qpdf::BaseDictionary;
108
    friend class qpdf::BaseHandle;
109
110
    QPDF_Dictionary(std::map<std::string, QPDFObjectHandle> const& items) :
111
20.2k
        items(items)
112
20.2k
    {
113
20.2k
    }
114
    inline QPDF_Dictionary(std::map<std::string, QPDFObjectHandle>&& items);
115
116
    std::map<std::string, QPDFObjectHandle> items;
117
};
118
119
class QPDF_InlineImage final
120
{
121
    friend class QPDFObject;
122
    friend class qpdf::BaseHandle;
123
124
    explicit QPDF_InlineImage(std::string val) :
125
0
        val(std::move(val))
126
0
    {
127
0
    }
128
    std::string val;
129
};
130
131
class QPDF_Integer final
132
{
133
    friend class QPDFObject;
134
    friend class qpdf::BaseHandle;
135
    friend class qpdf::Integer;
136
    friend class QPDFObjectHandle;
137
138
    QPDF_Integer(long long val) :
139
1.07M
        val(val)
140
1.07M
    {
141
1.07M
    }
142
    long long val;
143
};
144
145
class QPDF_Name final
146
{
147
    friend class QPDFObject;
148
    friend class qpdf::BaseHandle;
149
    friend class qpdf::Name;
150
151
    explicit QPDF_Name(std::string name) :
152
26.4k
        name(std::move(name))
153
26.4k
    {
154
26.4k
    }
155
    std::string name;
156
};
157
158
class QPDF_Null final
159
{
160
    friend class QPDFObject;
161
    friend class qpdf::BaseHandle;
162
163
  public:
164
    static inline std::shared_ptr<QPDFObject> create(
165
        std::shared_ptr<QPDFObject> parent,
166
        std::string_view const& static_descr,
167
        std::string var_descr);
168
};
169
170
class QPDF_Operator final
171
{
172
    friend class QPDFObject;
173
    friend class qpdf::BaseHandle;
174
175
    QPDF_Operator(std::string val) :
176
0
        val(std::move(val))
177
0
    {
178
0
    }
179
180
    std::string val;
181
};
182
183
class QPDF_Real final
184
{
185
    friend class QPDFObject;
186
    friend class qpdf::BaseHandle;
187
188
    QPDF_Real(std::string val) :
189
5.40k
        val(std::move(val))
190
5.40k
    {
191
5.40k
    }
192
    inline QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes);
193
    // Store reals as strings to avoid roundoff errors.
194
    std::string val;
195
};
196
197
class QPDF_Reference
198
{
199
    // This is a minimal implementation to support QPDF::replaceObject. Once we support parsing of
200
    // objects that are an indirect reference we will need to support multiple levels of
201
    // indirection, including the possibility of circular references.
202
    friend class QPDFObject;
203
    friend class qpdf::BaseHandle;
204
205
    QPDF_Reference(std::shared_ptr<QPDFObject> obj) :
206
18.8k
        obj(std::move(obj))
207
18.8k
    {
208
18.8k
    }
209
210
    std::shared_ptr<QPDFObject> obj;
211
};
212
213
class QPDF_Reserved final
214
{
215
};
216
217
class QPDF_Stream final
218
{
219
    class Members
220
    {
221
        friend class QPDF_Stream;
222
        friend class QPDFObject;
223
        friend class qpdf::Stream;
224
        friend class qpdf::BaseHandle;
225
226
      public:
227
        Members(QPDFObjectHandle stream_dict, size_t length) :
228
3.65k
            stream_dict(std::move(stream_dict)),
229
3.65k
            length(length)
230
3.65k
        {
231
3.65k
        }
232
233
      private:
234
        bool filter_on_write{true};
235
        QPDFObjectHandle stream_dict;
236
        size_t length{0};
237
        std::shared_ptr<Buffer> stream_data;
238
        std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider;
239
        std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters;
240
        std::string expand_filter_name(std::string const& name) const;
241
        std::function<std::shared_ptr<QPDFStreamFilter>()>
242
        filter_factory(std::string const& name) const;
243
    };
244
245
    friend class QPDFObject;
246
    friend class qpdf::BaseHandle;
247
    friend class qpdf::Stream;
248
249
    QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) :
250
3.65k
        m(std::make_unique<Members>(stream_dict, length))
251
3.65k
    {
252
3.65k
        if (!stream_dict.isDictionary()) {
253
0
            throw std::logic_error(
254
0
                "stream object instantiated with non-dictionary object for dictionary");
255
0
        }
256
3.65k
    }
257
258
    std::unique_ptr<Members> m;
259
};
260
261
// QPDF_Strings may included embedded null characters.
262
class QPDF_String final
263
{
264
    friend class QPDFObject;
265
    friend class qpdf::BaseHandle;
266
    friend class qpdf::String;
267
    friend class qpdf::impl::Writer;
268
269
  public:
270
    std::string unparse(bool force_binary = false);
271
    void writeJSON(int json_version, JSON::Writer& p);
272
273
  private:
274
    QPDF_String(std::string const& val) :
275
2.31k
        val(val)
276
2.31k
    {
277
2.31k
    }
278
    QPDF_String(std::string&& val) :
279
4.83k
        val(std::move(val))
280
4.83k
    {
281
4.83k
    }
282
    bool useHexString() const;
283
284
    std::string val;
285
};
286
287
class QPDF_Unresolved final
288
{
289
};
290
291
class QPDFObject
292
{
293
  public:
294
    template <typename T>
295
    QPDFObject(T&& value) :
296
1.18M
        value(std::forward<T>(value))
297
1.18M
    {
298
1.18M
    }
QPDFObject::QPDFObject<QPDF_Null>(QPDF_Null&&)
Line
Count
Source
296
31.3k
        value(std::forward<T>(value))
297
31.3k
    {
298
31.3k
    }
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_Reserved>(QPDF_Reserved&&)
QPDFObject::QPDFObject<QPDF_Dictionary>(QPDF_Dictionary&&)
Line
Count
Source
296
26.8k
        value(std::forward<T>(value))
297
26.8k
    {
298
26.8k
    }
QPDFObject::QPDFObject<QPDF_Bool>(QPDF_Bool&&)
Line
Count
Source
296
1.21k
        value(std::forward<T>(value))
297
1.21k
    {
298
1.21k
    }
QPDFObject::QPDFObject<QPDF_Integer>(QPDF_Integer&&)
Line
Count
Source
296
1.07M
        value(std::forward<T>(value))
297
1.07M
    {
298
1.07M
    }
QPDFObject::QPDFObject<QPDF_Real>(QPDF_Real&&)
Line
Count
Source
296
5.40k
        value(std::forward<T>(value))
297
5.40k
    {
298
5.40k
    }
QPDFObject::QPDFObject<QPDF_String>(QPDF_String&&)
Line
Count
Source
296
7.15k
        value(std::forward<T>(value))
297
7.15k
    {
298
7.15k
    }
QPDFObject::QPDFObject<QPDF_Name>(QPDF_Name&&)
Line
Count
Source
296
26.4k
        value(std::forward<T>(value))
297
26.4k
    {
298
26.4k
    }
QPDFObject::QPDFObject<QPDF_Array>(QPDF_Array&&)
Line
Count
Source
296
11.9k
        value(std::forward<T>(value))
297
11.9k
    {
298
11.9k
    }
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_Operator>(QPDF_Operator&&)
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_InlineImage>(QPDF_InlineImage&&)
299
300
    template <typename T>
301
    QPDFObject(QPDF* qpdf, QPDFObjGen og, T&& value) :
302
14.3k
        value(std::forward<T>(value)),
303
14.3k
        qpdf(qpdf),
304
14.3k
        og(og)
305
14.3k
    {
306
14.3k
    }
QPDFObject::QPDFObject<QPDF_Stream>(QPDF*, QPDFObjGen, QPDF_Stream&&)
Line
Count
Source
302
3.65k
        value(std::forward<T>(value)),
303
3.65k
        qpdf(qpdf),
304
3.65k
        og(og)
305
3.65k
    {
306
3.65k
    }
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_Unresolved>(QPDF*, QPDFObjGen, QPDF_Unresolved&&)
QPDFObject::QPDFObject<QPDF_Null>(QPDF*, QPDFObjGen, QPDF_Null&&)
Line
Count
Source
302
10.7k
        value(std::forward<T>(value)),
303
10.7k
        qpdf(qpdf),
304
10.7k
        og(og)
305
10.7k
    {
306
10.7k
    }
307
308
    template <typename T, typename... Args>
309
    inline static std::shared_ptr<QPDFObject> create(Args&&... args);
310
311
    template <typename T, typename... Args>
312
    inline static std::shared_ptr<QPDFObject>
313
    create(QPDF* qpdf, QPDFObjGen og, Args&&... args)
314
14.3k
    {
315
14.3k
        return std::make_shared<QPDFObject>(
316
14.3k
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
317
14.3k
    }
std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Stream, QPDFObjectHandle, unsigned long&>(QPDF*, QPDFObjGen, QPDFObjectHandle&&, unsigned long&)
Line
Count
Source
314
3.65k
    {
315
3.65k
        return std::make_shared<QPDFObject>(
316
3.65k
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
317
3.65k
    }
Unexecuted instantiation: std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Unresolved>(QPDF*, QPDFObjGen)
std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Null>(QPDF*, QPDFObjGen)
Line
Count
Source
314
10.7k
    {
315
10.7k
        return std::make_shared<QPDFObject>(
316
10.7k
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
317
10.7k
    }
318
319
    std::string getStringValue() const;
320
321
    // Return a unique type code for the resolved object
322
    inline qpdf_object_type_e getResolvedTypeCode() const;
323
324
    // Return a unique type code for the object
325
    qpdf_object_type_e
326
    getTypeCode() const
327
20.2k
    {
328
20.2k
        return static_cast<qpdf_object_type_e>(value.index());
329
20.2k
    }
330
    void
331
    assign_null()
332
0
    {
333
0
        value = QPDF_Null();
334
0
        qpdf = nullptr;
335
0
        og = QPDFObjGen();
336
0
        object_description = nullptr;
337
0
        parsed_offset = -1;
338
0
    }
339
    void
340
    move_to(std::shared_ptr<QPDFObject>& o, bool destroy)
341
18.8k
    {
342
18.8k
        o->value = std::move(value);
343
18.8k
        o->qpdf = qpdf;
344
18.8k
        o->og = og;
345
18.8k
        o->object_description = object_description;
346
18.8k
        o->parsed_offset = parsed_offset;
347
18.8k
        if (!destroy) {
348
18.8k
            value = QPDF_Reference(o);
349
18.8k
        }
350
18.8k
    }
351
    void
352
    swapWith(std::shared_ptr<QPDFObject> o)
353
0
    {
354
0
        std::swap(value, o->value);
355
0
        std::swap(qpdf, o->qpdf);
356
0
        std::swap(object_description, o->object_description);
357
0
        std::swap(parsed_offset, o->parsed_offset);
358
0
    }
359
360
    void
361
    setObjGen(QPDF* a_qpdf, QPDFObjGen a_og)
362
18.8k
    {
363
18.8k
        qpdf = a_qpdf;
364
18.8k
        og = a_og;
365
18.8k
    }
366
367
    bool
368
    isUnresolved() const
369
0
    {
370
0
        return getTypeCode() == ::ot_unresolved;
371
0
    }
372
373
    struct JSON_Descr
374
    {
375
        JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) :
376
17.8k
            input(input),
377
17.8k
            object(object)
378
17.8k
        {
379
17.8k
        }
380
381
        std::shared_ptr<std::string> input;
382
        std::string object;
383
    };
384
385
    struct ChildDescr
386
    {
387
        ChildDescr(
388
            std::shared_ptr<QPDFObject> parent,
389
            std::string_view const& static_descr,
390
            std::string var_descr) :
391
0
            parent(parent),
392
0
            static_descr(static_descr),
393
0
            var_descr(var_descr)
394
0
        {
395
0
        }
396
397
        std::weak_ptr<QPDFObject> parent;
398
        std::string_view const& static_descr;
399
        std::string var_descr;
400
    };
401
402
    struct ObjStreamDescr
403
    {
404
        ObjStreamDescr(int stream_id, int obj_id) :
405
0
            stream_id(stream_id),
406
0
            obj_id(obj_id) {};
407
408
        int stream_id;
409
        int obj_id;
410
    };
411
412
    using Description = std::variant<std::string, JSON_Descr, ChildDescr, ObjStreamDescr>;
413
414
    void
415
    setDescription(
416
        QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset = -1)
417
1.21M
    {
418
1.21M
        qpdf = qpdf_p;
419
1.21M
        object_description = description;
420
1.21M
        setParsedOffset(offset);
421
1.21M
    }
422
    void
423
    setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og)
424
0
    {
425
0
        qpdf = a_qpdf;
426
0
        og = a_og;
427
0
    }
428
    void
429
    setChildDescription(
430
        QPDF* a_qpdf,
431
        std::shared_ptr<QPDFObject> parent,
432
        std::string_view const& static_descr,
433
        std::string var_descr)
434
0
    {
435
0
        object_description =
436
0
            std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr));
437
0
        qpdf = a_qpdf;
438
0
    }
439
    std::string getDescription();
440
    bool
441
    hasDescription()
442
1.72M
    {
443
1.72M
        return object_description || og.isIndirect();
444
1.72M
    }
445
    void
446
    setParsedOffset(qpdf_offset_t offset)
447
1.21M
    {
448
1.21M
        if (parsed_offset < 0) {
449
1.19M
            parsed_offset = offset;
450
1.19M
        }
451
1.21M
    }
452
    QPDF*
453
    getQPDF()
454
237k
    {
455
237k
        return qpdf;
456
237k
    }
457
    QPDFObjGen
458
    getObjGen()
459
71.0k
    {
460
71.0k
        return og;
461
71.0k
    }
462
463
  private:
464
    friend class QPDF_Stream;
465
    friend class qpdf::BaseHandle;
466
    friend class Disconnect;
467
468
    typedef std::variant<
469
        std::monostate,
470
        QPDF_Reserved,
471
        QPDF_Null,
472
        QPDF_Bool,
473
        QPDF_Integer,
474
        QPDF_Real,
475
        QPDF_String,
476
        QPDF_Name,
477
        QPDF_Array,
478
        QPDF_Dictionary,
479
        QPDF_Stream,
480
        QPDF_Operator,
481
        QPDF_InlineImage,
482
        QPDF_Unresolved,
483
        QPDF_Destroyed,
484
        QPDF_Reference>
485
        Value;
486
    Value value;
487
488
    QPDFObject(QPDFObject const&) = delete;
489
    QPDFObject& operator=(QPDFObject const&) = delete;
490
491
    std::shared_ptr<Description> object_description;
492
493
    QPDF* qpdf{nullptr};
494
    QPDFObjGen og{};
495
    qpdf_offset_t parsed_offset{-1};
496
};
497
498
#endif // QPDFOBJECT_HH