Coverage Report

Created: 2025-08-28 06:38

/src/qpdf/include/qpdf/QPDFObjGen.hh
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2005-2021 Jay Berkenbilt
2
// Copyright (c) 2022-2025 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
100M
    QPDFObjGen() = default;
39
    QPDFObjGen(int obj, int gen) :
40
18.9M
        obj(obj),
41
18.9M
        gen(gen)
42
18.9M
    {
43
18.9M
    }
44
    bool
45
    operator<(QPDFObjGen const& rhs) const
46
909M
    {
47
909M
        return (obj < rhs.obj) || (obj == rhs.obj && gen < rhs.gen);
48
909M
    }
49
    bool
50
    operator==(QPDFObjGen const& rhs) const
51
3.82M
    {
52
3.82M
        return obj == rhs.obj && gen == rhs.gen;
53
3.82M
    }
54
    bool
55
    operator!=(QPDFObjGen const& rhs) const
56
1.58M
    {
57
1.58M
        return !(*this == rhs);
58
1.58M
    }
59
    int
60
    getObj() const
61
102M
    {
62
102M
        return obj;
63
102M
    }
64
    int
65
    getGen() const
66
2.52M
    {
67
2.52M
        return gen;
68
2.52M
    }
69
    bool
70
    isIndirect() const
71
40.9M
    {
72
40.9M
        return obj != 0;
73
40.9M
    }
74
    std::string
75
    unparse(char separator = ',') const
76
4.02M
    {
77
4.02M
        return std::to_string(obj) + separator + std::to_string(gen);
78
4.02M
    }
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
4.03M
        {
112
4.03M
            if (og.isIndirect()) {
113
3.31M
                if (count(og)) {
114
837k
                    return false;
115
837k
                }
116
2.47M
                emplace(og);
117
2.47M
            }
118
3.19M
            return true;
119
4.03M
        }
120
121
        void
122
        erase(QPDFObjGen og)
123
199k
        {
124
199k
            if (og.isIndirect()) {
125
23.7k
                std::set<QPDFObjGen>::erase(og);
126
23.7k
            }
127
199k
        }
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