libfilezilla
Loading...
Searching...
No Matches
buffer.hpp
Go to the documentation of this file.
1#ifndef LIBFILEZILLA_BUFFER_HEADER
2#define LIBFILEZILLA_BUFFER_HEADER
3
4#include "libfilezilla.hpp"
5
6#include <vector>
7#include <type_traits>
8
12
13namespace fz {
14
16enum class buffer_wipe_policy {
17 normal,
18 wipe_on_release
19};
20
26class FZ_PUBLIC_SYMBOL buffer_access_interface
27{
28public:
29 virtual ~buffer_access_interface();
30
35 virtual unsigned char const* get() const = 0;
36 virtual unsigned char* get() = 0;
37 virtual unsigned char* get(size_t write_size) = 0;
38 virtual void add(size_t added) = 0;
40
46 virtual void consume(size_t consumed) = 0;
47 virtual size_t size() const = 0;
48 virtual void clear() = 0;
49 virtual void append(unsigned char const* data, size_t len) = 0;
50 virtual size_t capacity() const = 0;
51 virtual void resize(size_t size) = 0;
53
54protected:
55 buffer_access_interface() = default;
56 // Concrete buffers may copy their state, but callers cannot assign via this base.
57 buffer_access_interface(buffer_access_interface const&) = default;
58 buffer_access_interface& operator=(buffer_access_interface const&) = default;
59};
60
62class FZ_PUBLIC_SYMBOL buffer_interface : public buffer_access_interface
63{
64public:
65 ~buffer_interface() override;
66
71 virtual void reserve(size_t capacity) = 0;
72 virtual void clear_and_free() = 0;
74
75protected:
76 buffer_interface() = default;
77 buffer_interface(buffer_interface const&) = default;
78 buffer_interface& operator=(buffer_interface const&) = default;
79};
80
92template<buffer_wipe_policy Policy>
93class basic_buffer
94{
95public:
96 using value_type = unsigned char;
97
98 basic_buffer() noexcept = default;
99
101 explicit basic_buffer(size_t capacity);
102
103 explicit basic_buffer(std::string_view const& data);
104
105 basic_buffer(basic_buffer const& buf);
106 basic_buffer(basic_buffer && buf) noexcept;
107
108 basic_buffer& operator=(basic_buffer const& buf);
109 basic_buffer& operator=(basic_buffer && buf) noexcept;
110
111 basic_buffer& operator=(std::string_view const& v);
112
113 ~basic_buffer();
114
116 unsigned char const* get() const { return pos_; }
117 unsigned char* get() { return pos_; }
118
120 unsigned char* data() { return pos_; }
121 unsigned char const* data() const { return pos_; }
122
141 unsigned char* get(size_t write_size);
142
144 void add(size_t added);
145
152 template<typename T, std::enable_if_t<std::is_signed_v<T>, int> = 0>
153 void add(T added) {
154 if (added > 0) {
155 add(static_cast<size_t>(added));
156 }
157 }
158
163 void consume(size_t consumed);
164
165 size_t size() const { return size_; }
166
170 void clear();
171
172 void clear_and_free();
173
178 void append(unsigned char const* data, size_t len);
179 void append(std::string_view const& str);
180 void append(std::basic_string_view<uint8_t> const& data);
181 void append(std::vector<uint8_t> const& data);
182 void append(basic_buffer const& b);
183 void append(unsigned char v);
184 void append(size_t len, unsigned char c);
185
186 void push_back(unsigned char v) {
187 return append(v);
188 }
189
190 basic_buffer& operator+=(unsigned char v) {
191 append(v);
192 return *this;
193 }
194 basic_buffer& operator+=(std::string_view const& str) {
195 append(str);
196 return *this;
197 }
198 basic_buffer& operator+=(std::vector<uint8_t> const& data) {
199 append(data);
200 return *this;
201 }
202 basic_buffer& operator+=(basic_buffer const& b) {
203 append(b);
204 return *this;
205 }
206
207 bool empty() const { return size_ == 0; }
208 explicit operator bool() const {
209 return size_ != 0;
210 }
211
212 size_t capacity() const { return capacity_; }
213 void reserve(size_t capacity);
214
215 void resize(size_t size);
216
218 unsigned char operator[](size_t i) const { return pos_[i]; }
219 unsigned char & operator[](size_t i) { return pos_[i]; }
220
221 bool operator==(basic_buffer const& rhs) const {
222 return *this == rhs.to_view();
223 }
224
225 bool operator==(std::string_view const& rhs) const;
226
227 bool operator!=(basic_buffer const& rhs) const {
228 return !(*this == rhs);
229 }
230 bool operator!=(std::string_view const& rhs) const {
231 return !(*this == rhs);
232 }
233
234 std::string_view to_view() const;
235
236 void wipe();
237 void wipe_unused();
238
239private:
240
241 // Invariants:
242 // size_ <= capacity_
243 // data_ <= pos_
244 // pos_ <= data_ + capacity_
245 // pos_ + size_ <= data_ + capacity_
246 unsigned char* data_{};
247 unsigned char* pos_{};
248 size_t size_{};
249 size_t capacity_{};
250};
251
252#if BUILDING_LIBFILEZILLA
253extern template class FZ_PUBLIC_SYMBOL basic_buffer<buffer_wipe_policy::normal>;
254extern template class FZ_PUBLIC_SYMBOL basic_buffer<buffer_wipe_policy::wipe_on_release>;
255#endif
256
257namespace buffer_detail {
258
259// The storage engine is non-polymorphic, keeping calls between its operations
260// direct. This layer supplies virtual dispatch for external callers and shares
261// the forwarding API across storage policies.
262//
263// Forwarders stay in the header so concrete calls can inline them. Virtual
264// destructors are defined in buffer.cpp to anchor vtables outside client code.
265template<buffer_wipe_policy Policy>
266class owning_buffer : public buffer_interface
267{
268public:
269 using value_type = unsigned char;
270
271 owning_buffer() noexcept = default;
272 explicit owning_buffer(size_t capacity) : storage_(capacity) {}
273 explicit owning_buffer(std::string_view const& data) : storage_(data) {}
274 owning_buffer(owning_buffer const&) = default;
275 owning_buffer(owning_buffer&&) noexcept = default;
276 owning_buffer& operator=(owning_buffer const&) = default;
277 owning_buffer& operator=(owning_buffer&&) noexcept = default;
278
279 owning_buffer& operator=(std::string_view const& data) {
280 storage_ = data;
281 return *this;
282 }
283
284 unsigned char const* get() const override { return storage_.get(); }
285 unsigned char* get() override { return storage_.get(); }
286 unsigned char* get(size_t size) override { return storage_.get(size); }
287 unsigned char* data() { return storage_.data(); }
288 unsigned char const* data() const { return storage_.data(); }
289 void add(size_t size) override { storage_.add(size); }
290
291 template<typename T, std::enable_if_t<std::is_signed_v<T>, int> = 0>
292 void add(T size) { storage_.add(size); }
293
294 void consume(size_t size) override { storage_.consume(size); }
295 size_t size() const override { return storage_.size(); }
296 bool empty() const { return storage_.empty(); }
297 explicit operator bool() const { return bool(storage_); }
298 size_t capacity() const override { return storage_.capacity(); }
299 void reserve(size_t capacity) override { storage_.reserve(capacity); }
300 void resize(size_t size) override { storage_.resize(size); }
301 void clear() override { storage_.clear(); }
302 void clear_and_free() override { storage_.clear_and_free(); }
303 void append(unsigned char const* data, size_t size) override { storage_.append(data, size); }
304 void append(std::string_view const& data) { storage_.append(data); }
305 void append(std::basic_string_view<uint8_t> const& data) { storage_.append(data); }
306 void append(std::vector<uint8_t> const& data) { storage_.append(data); }
307 void append(owning_buffer const& data) { storage_.append(data.storage_); }
308 void append(unsigned char value) { storage_.append(value); }
309 void append(size_t size, unsigned char value) { storage_.append(size, value); }
310 void push_back(unsigned char value) { storage_.push_back(value); }
311
312 owning_buffer& operator+=(unsigned char value) {
313 storage_ += value;
314 return *this;
315 }
316
317 owning_buffer& operator+=(std::string_view const& data) {
318 storage_ += data;
319 return *this;
320 }
321
322 owning_buffer& operator+=(std::vector<uint8_t> const& data) {
323 storage_ += data;
324 return *this;
325 }
326
327 owning_buffer& operator+=(owning_buffer const& data) {
328 storage_ += data.storage_;
329 return *this;
330 }
331
332 unsigned char operator[](size_t i) const { return storage_[i]; }
333 unsigned char& operator[](size_t i) { return storage_[i]; }
334 bool operator==(owning_buffer const& rhs) const { return storage_ == rhs.storage_; }
335 bool operator==(std::string_view const& rhs) const { return storage_ == rhs; }
336 bool operator!=(owning_buffer const& rhs) const { return storage_ != rhs.storage_; }
337 bool operator!=(std::string_view const& rhs) const { return storage_ != rhs; }
338 std::string_view to_view() const { return storage_.to_view(); }
339 void wipe() { storage_.wipe(); }
340 void wipe_unused() { storage_.wipe_unused(); }
341
342protected:
343 ~owning_buffer() override;
344
345private:
346 basic_buffer<Policy> storage_;
347};
348
349}
350
351// Consumers instantiate header-defined forwarders when they cannot inline them.
352#if BUILDING_LIBFILEZILLA
353extern template class FZ_PUBLIC_SYMBOL buffer_detail::owning_buffer<buffer_wipe_policy::normal>;
354extern template class FZ_PUBLIC_SYMBOL buffer_detail::owning_buffer<buffer_wipe_policy::wipe_on_release>;
355#endif
356
357// An out-of-line destructor suppresses implicit moves. Keep them explicit so
358// moving either concrete buffer still transfers ownership instead of copying.
359class FZ_PUBLIC_SYMBOL buffer final : public buffer_detail::owning_buffer<buffer_wipe_policy::normal>
360{
361public:
362 using owning_buffer::owning_buffer;
363 using owning_buffer::operator=;
364 buffer() noexcept = default;
365 buffer(buffer const&) = default;
366 buffer(buffer&&) noexcept = default;
367 buffer& operator=(buffer const&) = default;
368 buffer& operator=(buffer&&) noexcept = default;
369 ~buffer() override;
370};
371
374class FZ_PUBLIC_SYMBOL secure_buffer final : public buffer_detail::owning_buffer<buffer_wipe_policy::wipe_on_release>
375{
376public:
377 using owning_buffer::owning_buffer;
378 using owning_buffer::operator=;
379 secure_buffer() noexcept = default;
380 secure_buffer(secure_buffer const&) = default;
381 secure_buffer(secure_buffer&&) noexcept = default;
382 secure_buffer& operator=(secure_buffer const&) = default;
383 secure_buffer& operator=(secure_buffer&&) noexcept = default;
384 ~secure_buffer() override;
385};
386
387inline void wipe(buffer & b) {
388 b.wipe();
389}
390
391inline void wipe_unused(buffer & b) {
392 b.wipe_unused();
393}
394
395inline void wipe(secure_buffer & b) {
396 b.wipe();
397}
398
399inline void wipe_unused(secure_buffer & b) {
400 b.wipe_unused();
401}
402
403}
404
405#endif
The buffer class is a simple buffer where data can be appended at the end and consumed at the front....
Definition buffer.hpp:94
void add(T added)
Overload of add for signed types, only adds if value is positive.
Definition buffer.hpp:153
unsigned char * data()
Same as get().
Definition buffer.hpp:120
void consume(size_t consumed)
Removes consumed bytes from the beginning of the buffer.
unsigned char * get(size_t write_size)
Returns a writable buffer guaranteed to be large enough for write_size bytes, call add when done.
basic_buffer(size_t capacity)
Initially reserves the passed capacity.
unsigned char const * get() const
Undefined if buffer is empty.
Definition buffer.hpp:116
void append(unsigned char const *data, size_t len)
Appends the passed data to the buffer.
unsigned char operator[](size_t i) const
Gets element at offset i. Does not do bounds checking.
Definition buffer.hpp:218
void add(size_t added)
Increase size by the passed amount. Call this after having obtained a writable buffer with get(size_t...
Definition buffer.hpp:267
Definition buffer.hpp:360
Definition buffer.hpp:375
Sets some global macros and further includes string.hpp.
The namespace used by libfilezilla.
Definition apply.hpp:17