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