Coverage Report

Created: 2026-01-10 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qpdf/include/qpdf/QPDFObjGen.hh
Line
Count
Source
1
// Copyright (c) 2005-2021 Jay Berkenbilt
2
// Copyright (c) 2022-2026 Jay Berkenbilt and Manfred Holger
3
//
4
// This file is part of qpdf.
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7
// in compliance with the License. You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software distributed under the License
12
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13
// or implied. See the License for the specific language governing permissions and limitations under
14
// the License.
15
//
16
// Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic
17
// License. At your option, you may continue to consider qpdf to be licensed under those terms.
18
// Please see the manual for additional information.
19
20
#ifndef QPDFOBJGEN_HH
21
#define QPDFOBJGEN_HH
22
23
#include <qpdf/DLL.h>
24
25
#include <iostream>
26
#include <set>
27
#include <string>
28
29
class QPDFObjectHandle;
30
class QPDFObjectHelper;
31
32
// This class represents an object ID and generation pair.  It is suitable to use as a key in a map
33
// or set.
34
35
class QPDFObjGen
36
{
37
  public:
38
2.31M
    QPDFObjGen() = default;
39
    QPDFObjGen(int obj, int gen) :
40
576k
        obj(obj),
41
576k
        gen(gen)
42
576k
    {
43
576k
    }
44
    bool
45
    operator<(QPDFObjGen const& rhs) const
46
2.44M
    {
47
2.44M
        return (obj < rhs.obj) || (obj == rhs.obj && gen < rhs.gen);
48
2.44M
    }
49
    bool
50
    operator==(QPDFObjGen const& rhs) const
51
9.53k
    {
52
9.53k
        return obj == rhs.obj && gen == rhs.gen;
53
9.53k
    }
54
    bool
55
    operator!=(QPDFObjGen const& rhs) const
56
0
    {
57
0
        return !(*this == rhs);
58
0
    }
59
    int
60
    getObj() const
61
53.8k
    {
62
53.8k
        return obj;
63
53.8k
    }
64
    int
65
    getGen() const
66
0
    {
67
0
        return gen;
68
0
    }
69
    bool
70
    isIndirect() const
71
3.09M
    {
72
3.09M
        return obj != 0;
73
3.09M
    }
74
    std::string
75
    unparse(char separator = ',') const
76
4.02k
    {
77
4.02k
        return std::to_string(obj) + separator + std::to_string(gen);
78
4.02k
    }
79
    friend std::ostream&
80
    operator<<(std::ostream& os, QPDFObjGen og)
81
0
    {
82
0
        os << og.obj << "," << og.gen;
83
0
        return os;
84
0
    }
85
86
    // Convenience class for loop detection when processing objects.
87
    //
88
    // The class adds 'add' methods to a std::set<QPDFObjGen> which allows to test whether an
89
    // QPDFObjGen is present in the set and to insert it in a single operation. The 'add' method is
90
    // overloaded to take a QPDFObjGen, QPDFObjectHandle or an QPDFObjectHelper as parameter.
91
    //
92
    // The erase method is modified to ignore requests to erase QPDFObjGen(0, 0).
93
    //
94
    // Usage example:
95
    //
96
    // void process_object(QPDFObjectHandle oh, QPDFObjGen::set& seen)
97
    // {
98
    //     if (seen.add(oh)) {
99
    //         // handle first encounter of oh
100
    //     } else {
101
    //         // handle loop / subsequent encounter of oh
102
    //     }
103
    // }
104
    class QPDF_DLL_CLASS set: public std::set<QPDFObjGen>
105
    {
106
      public:
107
        // Add 'og' to the set. Return false if 'og' is already present in the set. Attempts to
108
        // insert QPDFObjGen(0, 0) are ignored.
109
        bool
110
        add(QPDFObjGen og)
111
0
        {
112
0
            if (og.isIndirect()) {
113
0
                if (count(og)) {
114
0
                    return false;
115
0
                }
116
0
                emplace(og);
117
0
            }
118
0
            return true;
119
0
        }
120
121
        void
122
        erase(QPDFObjGen og)
123
0
        {
124
0
            if (og.isIndirect()) {
125
0
                std::set<QPDFObjGen>::erase(og);
126
0
            }
127
0
        }
128
    };
129
130
  private:
131
    // This class does not use the Members pattern to avoid a memory allocation for every one of
132
    // these. A lot of these get created and destroyed.
133
    int obj{0};
134
    int gen{0};
135
};
136
137
#endif // QPDFOBJGEN_HH