Coverage Report

Created: 2026-04-29 06:21

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
1.03k
    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
1.40M
    QPDF_Array(QPDF_Array&&) = default;
59
1.77k
    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
179k
        elements(items)
68
179k
    {
69
179k
    }
70
    QPDF_Array(std::vector<QPDFObjectHandle>&& items, bool sparse);
71
72
    QPDF_Array(std::vector<QPDFObjectHandle>&& items) :
73
1.13M
        elements(std::move(items))
74
1.13M
    {
75
1.13M
    }
76
77
    size_t
78
    size() const
79
759k
    {
80
759k
        return sp ? sp->size : elements.size();
81
759k
    }
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
122k
        val(val)
95
122k
    {
96
122k
    }
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
727k
        items(items)
112
727k
    {
113
727k
    }
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 QPDFObjectHandle;
123
    friend class qpdf::BaseHandle;
124
125
    explicit QPDF_InlineImage(std::string val) :
126
0
        val(std::move(val))
127
0
    {
128
0
    }
129
    std::string val;
130
};
131
132
class QPDF_Integer final
133
{
134
    friend class QPDFObject;
135
    friend class qpdf::BaseHandle;
136
    friend class qpdf::Integer;
137
    friend class QPDFObjectHandle;
138
139
    QPDF_Integer(long long val) :
140
28.6M
        val(val)
141
28.6M
    {
142
28.6M
    }
143
    long long val;
144
};
145
146
class QPDF_Name final
147
{
148
    friend class QPDFObject;
149
    friend class QPDFObjectHandle;
150
    friend class qpdf::BaseHandle;
151
    friend class qpdf::Name;
152
153
    explicit QPDF_Name(std::string name) :
154
49.3M
        name(std::move(name))
155
49.3M
    {
156
49.3M
    }
157
    std::string name;
158
};
159
160
class QPDF_Null final
161
{
162
    friend class QPDFObject;
163
    friend class qpdf::BaseHandle;
164
165
  public:
166
    static inline std::shared_ptr<QPDFObject> create(
167
        std::shared_ptr<QPDFObject> parent,
168
        std::string_view const& static_descr,
169
        std::string var_descr);
170
};
171
172
class QPDF_Operator final
173
{
174
    friend class QPDFObject;
175
    friend class QPDFObjectHandle;
176
    friend class qpdf::BaseHandle;
177
178
    QPDF_Operator(std::string val) :
179
8.32M
        val(std::move(val))
180
8.32M
    {
181
8.32M
    }
182
183
    std::string val;
184
};
185
186
class QPDF_Real final
187
{
188
    friend class QPDFObject;
189
    friend class QPDFObjectHandle;
190
    friend class qpdf::BaseHandle;
191
192
    QPDF_Real(std::string val) :
193
1.17M
        val(std::move(val))
194
1.17M
    {
195
1.17M
    }
196
    inline QPDF_Real(double value, int decimal_places, bool trim_trailing_zeroes);
197
    // Store reals as strings to avoid roundoff errors.
198
    std::string val;
199
};
200
201
class QPDF_Reference
202
{
203
    // This is a minimal implementation to support QPDF::replaceObject. Once we support parsing of
204
    // objects that are an indirect reference we will need to support multiple levels of
205
    // indirection, including the possibility of circular references.
206
    friend class QPDFObject;
207
    friend class qpdf::BaseHandle;
208
209
    QPDF_Reference(std::shared_ptr<QPDFObject> obj) :
210
39.9k
        obj(std::move(obj))
211
39.9k
    {
212
39.9k
    }
213
214
    std::shared_ptr<QPDFObject> obj;
215
};
216
217
class QPDF_Reserved final
218
{
219
};
220
221
class QPDF_Stream final
222
{
223
    class Members
224
    {
225
        friend class QPDF_Stream;
226
        friend class QPDFObject;
227
        friend class qpdf::Stream;
228
        friend class qpdf::BaseHandle;
229
230
      public:
231
        Members(QPDFObjectHandle stream_dict, size_t length) :
232
427k
            stream_dict(std::move(stream_dict)),
233
427k
            length(length)
234
427k
        {
235
427k
        }
236
237
      private:
238
        bool filter_on_write{true};
239
        QPDFObjectHandle stream_dict;
240
        size_t length{0};
241
        std::shared_ptr<Buffer> stream_data;
242
        std::shared_ptr<QPDFObjectHandle::StreamDataProvider> stream_provider;
243
        std::vector<std::shared_ptr<QPDFObjectHandle::TokenFilter>> token_filters;
244
        std::string expand_filter_name(std::string const& name) const;
245
        std::function<std::shared_ptr<QPDFStreamFilter>()>
246
        filter_factory(std::string const& name) const;
247
    };
248
249
    friend class QPDFObject;
250
    friend class qpdf::BaseHandle;
251
    friend class qpdf::Stream;
252
253
    QPDF_Stream(QPDFObjectHandle stream_dict, size_t length) :
254
427k
        m(std::make_unique<Members>(stream_dict, length))
255
427k
    {
256
427k
        if (!stream_dict.isDictionary()) {
257
0
            throw std::logic_error(
258
0
                "stream object instantiated with non-dictionary object for dictionary");
259
0
        }
260
427k
    }
261
262
    std::unique_ptr<Members> m;
263
};
264
265
// QPDF_Strings may included embedded null characters.
266
class QPDF_String final
267
{
268
    friend class QPDFObject;
269
    friend class qpdf::BaseHandle;
270
    friend class qpdf::String;
271
    friend class qpdf::impl::Writer;
272
273
  public:
274
    std::string unparse(bool force_binary = false);
275
    void writeJSON(int json_version, JSON::Writer& p);
276
277
  private:
278
    QPDF_String(std::string const& val) :
279
2.69M
        val(val)
280
2.69M
    {
281
2.69M
    }
282
    QPDF_String(std::string&& val) :
283
102k
        val(std::move(val))
284
102k
    {
285
102k
    }
286
    bool useHexString() const;
287
288
    std::string val;
289
};
290
291
class QPDF_Unresolved final
292
{
293
};
294
295
class QPDFObject
296
{
297
  public:
298
    template <typename T>
299
    QPDFObject(T&& value) :
300
100M
        value(std::forward<T>(value))
301
100M
    {
302
100M
    }
QPDFObject::QPDFObject<QPDF_Null>(QPDF_Null&&)
Line
Count
Source
300
5.78M
        value(std::forward<T>(value))
301
5.78M
    {
302
5.78M
    }
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_Reserved>(QPDF_Reserved&&)
QPDFObject::QPDFObject<QPDF_Dictionary>(QPDF_Dictionary&&)
Line
Count
Source
300
2.78M
        value(std::forward<T>(value))
301
2.78M
    {
302
2.78M
    }
QPDFObject::QPDFObject<QPDF_Bool>(QPDF_Bool&&)
Line
Count
Source
300
122k
        value(std::forward<T>(value))
301
122k
    {
302
122k
    }
QPDFObject::QPDFObject<QPDF_Integer>(QPDF_Integer&&)
Line
Count
Source
300
28.6M
        value(std::forward<T>(value))
301
28.6M
    {
302
28.6M
    }
QPDFObject::QPDFObject<QPDF_Real>(QPDF_Real&&)
Line
Count
Source
300
1.49M
        value(std::forward<T>(value))
301
1.49M
    {
302
1.49M
    }
QPDFObject::QPDFObject<QPDF_String>(QPDF_String&&)
Line
Count
Source
300
2.40M
        value(std::forward<T>(value))
301
2.40M
    {
302
2.40M
    }
QPDFObject::QPDFObject<QPDF_Name>(QPDF_Name&&)
Line
Count
Source
300
49.3M
        value(std::forward<T>(value))
301
49.3M
    {
302
49.3M
    }
QPDFObject::QPDFObject<QPDF_Array>(QPDF_Array&&)
Line
Count
Source
300
1.38M
        value(std::forward<T>(value))
301
1.38M
    {
302
1.38M
    }
QPDFObject::QPDFObject<QPDF_Operator>(QPDF_Operator&&)
Line
Count
Source
300
8.32M
        value(std::forward<T>(value))
301
8.32M
    {
302
8.32M
    }
Unexecuted instantiation: QPDFObject::QPDFObject<QPDF_InlineImage>(QPDF_InlineImage&&)
303
304
    template <typename T>
305
    QPDFObject(QPDF* qpdf, QPDFObjGen og, T&& value) :
306
3.02M
        value(std::forward<T>(value)),
307
3.02M
        qpdf(qpdf),
308
3.02M
        og(og)
309
3.02M
    {
310
3.02M
    }
QPDFObject::QPDFObject<QPDF_Stream>(QPDF*, QPDFObjGen, QPDF_Stream&&)
Line
Count
Source
306
427k
        value(std::forward<T>(value)),
307
427k
        qpdf(qpdf),
308
427k
        og(og)
309
427k
    {
310
427k
    }
QPDFObject::QPDFObject<QPDF_Unresolved>(QPDF*, QPDFObjGen, QPDF_Unresolved&&)
Line
Count
Source
306
2.57M
        value(std::forward<T>(value)),
307
2.57M
        qpdf(qpdf),
308
2.57M
        og(og)
309
2.57M
    {
310
2.57M
    }
QPDFObject::QPDFObject<QPDF_Null>(QPDF*, QPDFObjGen, QPDF_Null&&)
Line
Count
Source
306
23.7k
        value(std::forward<T>(value)),
307
23.7k
        qpdf(qpdf),
308
23.7k
        og(og)
309
23.7k
    {
310
23.7k
    }
311
312
    template <typename T, typename... Args>
313
    inline static std::shared_ptr<QPDFObject> create(Args&&... args);
314
315
    template <typename T, typename... Args>
316
    inline static std::shared_ptr<QPDFObject>
317
    create(QPDF* qpdf, QPDFObjGen og, Args&&... args)
318
3.02M
    {
319
3.02M
        return std::make_shared<QPDFObject>(
320
3.02M
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
321
3.02M
    }
std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Stream, QPDFObjectHandle, unsigned long&>(QPDF*, QPDFObjGen, QPDFObjectHandle&&, unsigned long&)
Line
Count
Source
318
427k
    {
319
427k
        return std::make_shared<QPDFObject>(
320
427k
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
321
427k
    }
std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Unresolved>(QPDF*, QPDFObjGen)
Line
Count
Source
318
2.57M
    {
319
2.57M
        return std::make_shared<QPDFObject>(
320
2.57M
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
321
2.57M
    }
std::__1::shared_ptr<QPDFObject> QPDFObject::create<QPDF_Null>(QPDF*, QPDFObjGen)
Line
Count
Source
318
23.7k
    {
319
23.7k
        return std::make_shared<QPDFObject>(
320
23.7k
            qpdf, og, std::forward<T>(T(std::forward<Args>(args)...)));
321
23.7k
    }
322
323
    // Return a unique type code for the resolved object
324
    inline qpdf_object_type_e getResolvedTypeCode() const;
325
326
    // Return a unique type code for the object
327
    qpdf_object_type_e
328
    getTypeCode() const
329
9.31M
    {
330
9.31M
        return static_cast<qpdf_object_type_e>(value.index());
331
9.31M
    }
332
    void
333
    assign_null()
334
13.5k
    {
335
13.5k
        value = QPDF_Null();
336
13.5k
        qpdf = nullptr;
337
13.5k
        og = QPDFObjGen();
338
13.5k
        object_description = nullptr;
339
13.5k
        parsed_offset = -1;
340
13.5k
    }
341
    void
342
    move_to(std::shared_ptr<QPDFObject>& o, bool destroy)
343
2.47M
    {
344
2.47M
        o->value = std::move(value);
345
2.47M
        o->qpdf = qpdf;
346
2.47M
        o->og = og;
347
2.47M
        o->object_description = object_description;
348
2.47M
        o->parsed_offset = parsed_offset;
349
2.47M
        if (!destroy) {
350
39.9k
            value = QPDF_Reference(o);
351
39.9k
        }
352
2.47M
    }
353
    void
354
    swapWith(std::shared_ptr<QPDFObject> o)
355
0
    {
356
0
        std::swap(value, o->value);
357
0
        std::swap(qpdf, o->qpdf);
358
0
        std::swap(object_description, o->object_description);
359
0
        std::swap(parsed_offset, o->parsed_offset);
360
0
    }
361
362
    void
363
    setObjGen(QPDF* a_qpdf, QPDFObjGen a_og)
364
4.19M
    {
365
4.19M
        qpdf = a_qpdf;
366
4.19M
        og = a_og;
367
4.19M
    }
368
369
    bool
370
    isUnresolved() const
371
5.88M
    {
372
5.88M
        return getTypeCode() == ::ot_unresolved;
373
5.88M
    }
374
375
    struct JSON_Descr
376
    {
377
        JSON_Descr(std::shared_ptr<std::string> input, std::string const& object) :
378
38.4k
            input(input),
379
38.4k
            object(object)
380
38.4k
        {
381
38.4k
        }
382
383
        std::shared_ptr<std::string> input;
384
        std::string object;
385
    };
386
387
    struct ChildDescr
388
    {
389
        ChildDescr(
390
            std::shared_ptr<QPDFObject> parent,
391
            std::string_view const& static_descr,
392
            std::string var_descr) :
393
1.94M
            parent(parent),
394
1.94M
            static_descr(static_descr),
395
1.94M
            var_descr(var_descr)
396
1.94M
        {
397
1.94M
        }
398
399
        std::weak_ptr<QPDFObject> parent;
400
        std::string_view const& static_descr;
401
        std::string var_descr;
402
    };
403
404
    struct ObjStreamDescr
405
    {
406
        ObjStreamDescr(int stream_id, int obj_id) :
407
371k
            stream_id(stream_id),
408
371k
            obj_id(obj_id) {};
409
410
        int stream_id;
411
        int obj_id;
412
    };
413
414
    using Description = std::variant<std::string, JSON_Descr, ChildDescr, ObjStreamDescr>;
415
416
    void
417
    setDescription(
418
        QPDF* qpdf_p, std::shared_ptr<Description>& description, qpdf_offset_t offset = -1)
419
91.8M
    {
420
91.8M
        qpdf = qpdf_p;
421
91.8M
        object_description = description;
422
91.8M
        setParsedOffset(offset);
423
91.8M
    }
424
    void
425
    setDefaultDescription(QPDF* a_qpdf, QPDFObjGen const& a_og)
426
3.87M
    {
427
3.87M
        qpdf = a_qpdf;
428
3.87M
        og = a_og;
429
3.87M
    }
430
    void
431
    setChildDescription(
432
        QPDF* a_qpdf,
433
        std::shared_ptr<QPDFObject> parent,
434
        std::string_view const& static_descr,
435
        std::string var_descr)
436
1.94M
    {
437
1.94M
        object_description =
438
1.94M
            std::make_shared<Description>(ChildDescr(parent, static_descr, var_descr));
439
1.94M
        qpdf = a_qpdf;
440
1.94M
    }
441
    std::string getDescription();
442
    bool
443
    hasDescription()
444
4.43M
    {
445
4.43M
        return object_description || og.isIndirect();
446
4.43M
    }
447
    void
448
    setParsedOffset(qpdf_offset_t offset)
449
91.8M
    {
450
91.8M
        if (parsed_offset < 0) {
451
91.8M
            parsed_offset = offset;
452
91.8M
        }
453
91.8M
    }
454
    QPDF*
455
    getQPDF()
456
4.07M
    {
457
4.07M
        return qpdf;
458
4.07M
    }
459
    QPDFObjGen
460
    getObjGen()
461
58.8M
    {
462
58.8M
        return og;
463
58.8M
    }
464
465
  private:
466
    friend class QPDF_Stream;
467
    friend class qpdf::BaseHandle;
468
    friend class Disconnect;
469
470
    typedef std::variant<
471
        std::monostate,
472
        QPDF_Reserved,
473
        QPDF_Null,
474
        QPDF_Bool,
475
        QPDF_Integer,
476
        QPDF_Real,
477
        QPDF_String,
478
        QPDF_Name,
479
        QPDF_Array,
480
        QPDF_Dictionary,
481
        QPDF_Stream,
482
        QPDF_Operator,
483
        QPDF_InlineImage,
484
        QPDF_Unresolved,
485
        QPDF_Destroyed,
486
        QPDF_Reference>
487
        Value;
488
    Value value;
489
490
    QPDFObject(QPDFObject const&) = delete;
491
    QPDFObject& operator=(QPDFObject const&) = delete;
492
493
    std::shared_ptr<Description> object_description;
494
495
    QPDF* qpdf{nullptr};
496
    QPDFObjGen og{};
497
    qpdf_offset_t parsed_offset{-1};
498
};
499
500
#endif // QPDFOBJECT_HH