Coverage Report

Created: 2025-07-18 07:00

/src/qpdf/libqpdf/qpdf/InputSource_private.hh
Line
Count
Source (jump to first uncovered line)
1
#ifndef QPDF_INPUTSOURCE_PRIVATE_HH
2
#define QPDF_INPUTSOURCE_PRIVATE_HH
3
4
#include <qpdf/BufferInputSource.hh>
5
#include <qpdf/InputSource.hh>
6
7
#include <limits>
8
#include <sstream>
9
#include <stdexcept>
10
11
namespace qpdf::is
12
{
13
    class OffsetBuffer final: public InputSource
14
    {
15
      public:
16
        OffsetBuffer(std::string const& description, Buffer* buf, qpdf_offset_t global_offset) :
17
40.4k
            proxied(description, buf),
18
40.4k
            global_offset(global_offset)
19
40.4k
        {
20
40.4k
            if (global_offset < 0) {
21
55
                throw std::logic_error("is::OffsetBuffer constructed with negative offset");
22
55
            }
23
40.3k
            last_offset = global_offset;
24
40.3k
        }
25
26
40.3k
        ~OffsetBuffer() final = default;
27
28
        qpdf_offset_t
29
        findAndSkipNextEOL() final
30
0
        {
31
0
            return proxied.findAndSkipNextEOL() + global_offset;
32
0
        }
33
34
        std::string const&
35
        getName() const final
36
0
        {
37
0
            return proxied.getName();
38
0
        }
39
40
        qpdf_offset_t
41
        tell() final
42
6.93M
        {
43
6.93M
            return proxied.tell() + global_offset;
44
6.93M
        }
45
46
        void
47
        seek(qpdf_offset_t offset, int whence) final
48
6.88M
        {
49
6.88M
            if (whence == SEEK_SET) {
50
6.88M
                proxied.seek(offset - global_offset, whence);
51
6.88M
            } else {
52
0
                proxied.seek(offset, whence);
53
0
            }
54
6.88M
        }
55
56
        void
57
        rewind() final
58
0
        {
59
0
            seek(0, SEEK_SET);
60
0
        }
61
62
        size_t
63
        read(char* buffer, size_t length) final
64
108k
        {
65
108k
            size_t result = proxied.read(buffer, length);
66
108k
            setLastOffset(proxied.getLastOffset() + global_offset);
67
108k
            return result;
68
108k
        }
69
70
        void
71
        unreadCh(char ch) final
72
0
        {
73
0
            proxied.unreadCh(ch);
74
0
        }
75
76
      private:
77
        BufferInputSource proxied;
78
        qpdf_offset_t global_offset;
79
    };
80
81
} // namespace qpdf::is
82
83
inline size_t
84
InputSource::read(std::string& str, size_t count, qpdf_offset_t at)
85
57.0k
{
86
57.0k
    if (at >= 0) {
87
45.1k
        seek(at, SEEK_SET);
88
45.1k
    }
89
57.0k
    str.resize(count);
90
57.0k
    str.resize(read(str.data(), count));
91
57.0k
    return str.size();
92
57.0k
}
93
94
inline std::string
95
InputSource::read(size_t count, qpdf_offset_t at)
96
45.1k
{
97
45.1k
    std::string result(count, '\0');
98
45.1k
    (void)read(result, count, at);
99
45.1k
    return result;
100
45.1k
}
101
102
inline void
103
InputSource::loadBuffer()
104
14.6M
{
105
14.6M
    buf_idx = 0;
106
14.6M
    buf_len = qpdf_offset_t(read(buffer, buf_size));
107
    // NB read sets last_offset
108
14.6M
    buf_start = last_offset;
109
14.6M
}
110
111
inline qpdf_offset_t
112
InputSource::fastTell()
113
123M
{
114
123M
    if (buf_len == 0) {
115
116k
        loadBuffer();
116
123M
    } else {
117
123M
        auto curr = tell();
118
123M
        if (curr < buf_start || curr >= (buf_start + buf_len)) {
119
14.5M
            loadBuffer();
120
108M
        } else {
121
108M
            last_offset = curr;
122
108M
            buf_idx = curr - buf_start;
123
108M
        }
124
123M
    }
125
123M
    return last_offset;
126
123M
}
127
128
inline bool
129
InputSource::fastRead(char& ch)
130
1.92G
{
131
    // Before calling fastRead, fastTell must be called to prepare the buffer. Once reading is
132
    // complete, fastUnread must be called to set the correct file position.
133
1.92G
    if (buf_idx < buf_len) {
134
1.91G
        ch = buffer[buf_idx];
135
1.91G
        ++(buf_idx);
136
1.91G
        ++(last_offset);
137
1.91G
        return true;
138
139
1.91G
    } else if (buf_len == 0) {
140
60.7k
        return false;
141
14.0M
    } else {
142
14.0M
        seek(buf_start + buf_len, SEEK_SET);
143
14.0M
        fastTell();
144
14.0M
        return fastRead(ch);
145
14.0M
    }
146
1.92G
}
147
148
inline void
149
InputSource::fastUnread(bool back)
150
109M
{
151
109M
    last_offset -= back ? 1 : 0;
152
109M
    seek(last_offset, SEEK_SET);
153
109M
}
154
155
#endif // QPDF_INPUTSOURCE_PRIVATE_HH