TrinityCore
Loading...
Searching...
No Matches
ByteBuffer.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITYCORE_BYTE_BUFFER_H
19#define TRINITYCORE_BYTE_BUFFER_H
20
21#include "ByteConverter.h"
22#include "Concepts.h"
23#include "Define.h"
24#include <array>
25#include <string>
26#include <vector>
27#include <cstring>
28
29// Root of ByteBuffer exception hierarchy
30class TC_SHARED_API ByteBufferException : public std::exception
31{
32public:
33 explicit ByteBufferException() = default;
34 explicit ByteBufferException(std::string&& message) noexcept : msg_(std::move(message)) { }
35
36 char const* what() const noexcept override { return msg_.c_str(); }
37
38protected:
39 std::string msg_;
40};
41
43{
44public:
45 ByteBufferPositionException(size_t pos, size_t size, size_t valueSize);
46};
47
49{
50public:
51 ByteBufferInvalidValueException(char const* type, std::string_view value);
52};
53
54template <typename T>
55concept ByteBufferNumeric = std::same_as<T, int8> || std::same_as<T, uint8>
56 || std::same_as<T, int16> || std::same_as<T, uint16>
57 || std::same_as<T, int32> || std::same_as<T, uint32>
58 || std::same_as<T, int64> || std::same_as<T, uint64>
59 || std::same_as<T, float> || std::same_as<T, double>
60 || std::same_as<T, char> || std::is_enum_v<T>;
61
63{
64 public:
65 constexpr static size_t DEFAULT_SIZE = 0x1000;
66 constexpr static uint8 InitialBitPos = 8;
67
68 // reserve/resize tag
69 struct Reserve { };
70 struct Resize { };
71
72 // constructor
73 explicit ByteBuffer() : ByteBuffer(DEFAULT_SIZE, Reserve{}) { }
74
75 explicit ByteBuffer(size_t size, Reserve) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0)
76 {
77 _storage.reserve(size);
78 }
79
80 explicit ByteBuffer(size_t size, Resize) : _rpos(0), _wpos(size), _bitpos(InitialBitPos), _curbitval(0)
81 {
82 _storage.resize(size);
83 }
84
85 ByteBuffer(ByteBuffer const& right) = default;
86
87 ByteBuffer(ByteBuffer&& buf) noexcept : _rpos(buf._rpos), _wpos(buf._wpos),
88 _bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(std::move(buf).Release()) { }
89
90 explicit ByteBuffer(std::vector<uint8>&& buffer) noexcept : _rpos(0), _wpos(buffer.size()),
91 _bitpos(InitialBitPos), _curbitval(0), _storage(std::move(buffer)) { }
92
93 std::vector<uint8>&& Release() && noexcept
94 {
95 _rpos = 0;
96 _wpos = 0;
97 _bitpos = InitialBitPos;
98 _curbitval = 0;
99 return std::move(_storage);
100 }
101
102 ByteBuffer& operator=(ByteBuffer const& right) = default;
103
104 ByteBuffer& operator=(ByteBuffer&& right) noexcept
105 {
106 if (this != &right)
107 {
108 _rpos = right._rpos;
109 _wpos = right._wpos;
110 _bitpos = right._bitpos;
111 _curbitval = right._curbitval;
112 _storage = std::move(right).Release();
113 }
114
115 return *this;
116 }
117
118 virtual ~ByteBuffer() = default;
119
120 void clear()
121 {
122 _rpos = 0;
123 _wpos = 0;
124 _bitpos = InitialBitPos;
125 _curbitval = 0;
126 _storage.clear();
127 }
128
129 template <ByteBufferNumeric T>
130 void append(T value)
131 {
132 EndianConvert(value);
133 append(reinterpret_cast<uint8 const*>(&value), sizeof(value));
134 }
135
137 {
138 return _bitpos != 8;
139 }
140
142 {
143 if (_bitpos == 8)
144 return;
145
146 _bitpos = 8;
147
148 append(&_curbitval, sizeof(uint8));
149 _curbitval = 0;
150 }
151
153 {
154 _bitpos = 8;
155 _curbitval = 0;
156 }
157
158 bool WriteBit(bool bit)
159 {
160 --_bitpos;
161 if (bit)
162 _curbitval |= (1 << (_bitpos));
163
164 if (_bitpos == 0)
165 {
166 _bitpos = 8;
167 append(&_curbitval, sizeof(_curbitval));
168 _curbitval = 0;
169 }
170
171 return bit;
172 }
173
174 bool ReadBit()
175 {
176 if (_bitpos >= 8)
177 {
178 read(&_curbitval, 1);
179 _bitpos = 0;
180 }
181
182 return ((_curbitval >> (8 - ++_bitpos)) & 1) != 0;
183 }
184
185 void WriteBits(uint64 value, int32 bits)
186 {
187 // remove bits that don't fit
188 value &= (UI64LIT(1) << bits) - 1;
189
190 if (bits > int32(_bitpos))
191 {
192 // first write to fill bit buffer
193 _curbitval |= value >> (bits - _bitpos);
194 bits -= _bitpos;
195 _bitpos = 8; // required "unneccessary" write to avoid double flushing
196 append(&_curbitval, sizeof(_curbitval));
197
198 // then append as many full bytes as possible
199 while (bits >= 8)
200 {
201 bits -= 8;
202 append<uint8>(value >> bits);
203 }
204
205 // store remaining bits in the bit buffer
206 _bitpos = 8 - bits;
207 _curbitval = (value & ((UI64LIT(1) << bits) - 1)) << _bitpos;
208 }
209 else
210 {
211 // entire value fits in the bit buffer
212 _bitpos -= bits;
213 _curbitval |= value << _bitpos;
214
215 if (_bitpos == 0)
216 {
217 _bitpos = 8;
218 append(&_curbitval, sizeof(_curbitval));
219 _curbitval = 0;
220 }
221 }
222 }
223
225 {
226 uint32 value = 0;
227 if (bits > 8 - int32(_bitpos))
228 {
229 // first retrieve whatever is left in the bit buffer
230 int32 bitsInBuffer = 8 - _bitpos;
231 value = (_curbitval & ((UI64LIT(1) << bitsInBuffer) - 1)) << (bits - bitsInBuffer);
232 bits -= bitsInBuffer;
233
234 // then read as many full bytes as possible
235 while (bits >= 8)
236 {
237 bits -= 8;
238 value |= read<uint8>() << bits;
239 }
240
241 // and finally any remaining bits
242 if (bits)
243 {
244 read(&_curbitval, 1);
245 value |= (_curbitval >> (8 - bits)) & ((UI64LIT(1) << bits) - 1);
246 _bitpos = bits;
247 }
248 }
249 else
250 {
251 // entire value is in the bit buffer
252 value = (_curbitval >> (8 - _bitpos - bits)) & ((UI64LIT(1) << bits) - 1);
253 _bitpos += bits;
254 }
255
256 return value;
257 }
258
259 template <ByteBufferNumeric T>
260 void put(std::size_t pos, T value)
261 {
262 EndianConvert(value);
263 put(pos, reinterpret_cast<uint8 const*>(&value), sizeof(value));
264 }
265
278 void PutBits(std::size_t pos, std::size_t value, uint32 bitCount);
279
280 ByteBuffer& operator<<(bool) = delete; // prevent implicit conversions to int32
281
283 {
284 append<char>(value);
285 return *this;
286 }
287
289 {
290 append<uint8>(value);
291 return *this;
292 }
293
295 {
296 append<uint16>(value);
297 return *this;
298 }
299
301 {
302 append<uint32>(value);
303 return *this;
304 }
305
307 {
308 append<uint64>(value);
309 return *this;
310 }
311
312 // signed as in 2e complement
314 {
315 append<int8>(value);
316 return *this;
317 }
318
320 {
321 append<int16>(value);
322 return *this;
323 }
324
326 {
327 append<int32>(value);
328 return *this;
329 }
330
332 {
333 append<int64>(value);
334 return *this;
335 }
336
337 // floating points
338 ByteBuffer& operator<<(float value)
339 {
340 append<float>(value);
341 return *this;
342 }
343
344 ByteBuffer& operator<<(double value)
345 {
346 append<double>(value);
347 return *this;
348 }
349
350 ByteBuffer& operator<<(std::string_view value)
351 {
352 if (size_t len = value.length())
353 append(reinterpret_cast<uint8 const*>(value.data()), len);
354 append(static_cast<uint8>(0));
355 return *this;
356 }
357
358 ByteBuffer& operator<<(std::string const& str)
359 {
360 return operator<<(std::string_view(str));
361 }
362
363 ByteBuffer& operator<<(char const* str)
364 {
365 return operator<<(std::string_view(str ? str : ""));
366 }
367
368 ByteBuffer& operator>>(bool&) = delete;
369
370 ByteBuffer& operator>>(char& value)
371 {
372 read(&value, 1);
373 return *this;
374 }
375
377 {
378 read(&value, 1);
379 return *this;
380 }
381
383 {
384 read(&value, 1);
385 return *this;
386 }
387
389 {
390 read(&value, 1);
391 return *this;
392 }
393
395 {
396 read(&value, 1);
397 return *this;
398 }
399
400 //signed as in 2e complement
402 {
403 read(&value, 1);
404 return *this;
405 }
406
408 {
409 read(&value, 1);
410 return *this;
411 }
412
414 {
415 read(&value, 1);
416 return *this;
417 }
418
420 {
421 read(&value, 1);
422 return *this;
423 }
424
425 ByteBuffer& operator>>(float& value);
426 ByteBuffer& operator>>(double& value);
427
428 ByteBuffer& operator>>(std::string& value)
429 {
430 value = ReadCString(true);
431 return *this;
432 }
433
434 uint8& operator[](size_t const pos)
435 {
436 if (pos >= _storage.size())
437 OnInvalidPosition(pos, 1);
438 return _storage[pos];
439 }
440
441 uint8 const& operator[](size_t const pos) const
442 {
443 if (pos >= _storage.size())
444 OnInvalidPosition(pos, 1);
445 return _storage[pos];
446 }
447
448 size_t rpos() const { return _rpos; }
449
450 size_t rpos(size_t rpos_)
451 {
452 _rpos = rpos_;
453 return _rpos;
454 }
455
456 void rfinish()
457 {
458 _rpos = wpos();
459 }
460
461 size_t wpos() const { return _wpos; }
462
463 size_t wpos(size_t wpos_)
464 {
465 _wpos = wpos_;
466 return _wpos;
467 }
468
470 size_t bitwpos() const { return _wpos * 8 + 8 - _bitpos; }
471
472 size_t bitwpos(size_t newPos)
473 {
474 _wpos = newPos / 8;
475 _bitpos = 8 - (newPos % 8);
476 return _wpos * 8 + 8 - _bitpos;
477 }
478
479 template <ByteBufferNumeric T>
480 void read_skip() { read_skip(sizeof(T)); }
481
482 void read_skip(size_t skip)
483 {
484 if (_rpos + skip > _storage.size())
485 OnInvalidPosition(_rpos, skip);
486
487 ResetBitPos();
488 _rpos += skip;
489 }
490
491 template <ByteBufferNumeric T>
493 {
494 ResetBitPos();
495 T r = read<T>(_rpos);
496 _rpos += sizeof(T);
497 return r;
498 }
499
500 template <ByteBufferNumeric T>
501 T read(size_t pos) const
502 {
503 if (pos + sizeof(T) > _storage.size())
504 OnInvalidPosition(pos, sizeof(T));
505
506 T val;
507 std::memcpy(&val, &_storage[pos], sizeof(T));
508 EndianConvert(val);
509 return val;
510 }
511
512 template <ByteBufferNumeric T>
513 void read(T* dest, size_t count)
514 {
515 static_assert(std::is_trivially_copyable_v<T>, "read(T*, size_t) must be used with trivially copyable types");
516 read(reinterpret_cast<uint8*>(dest), count * sizeof(T));
517#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
518 for (size_t i = 0; i < count; ++i)
519 EndianConvert(dest[i]);
520#endif
521 }
522
523 void read(uint8* dest, size_t len)
524 {
525 if (_rpos + len > _storage.size())
526 OnInvalidPosition(_rpos, len);
527
528 ResetBitPos();
529 std::memcpy(dest, &_storage[_rpos], len);
530 _rpos += len;
531 }
532
533 template <ByteBufferNumeric T, size_t Size>
534 void read(std::array<T, Size>& arr)
535 {
536 read(arr.data(), Size);
537 }
538
541 void WriteString(std::string const& str)
542 {
543 if (size_t len = str.length())
544 append(str.c_str(), len);
545 }
546
547 void WriteString(std::string_view str)
548 {
549 if (size_t len = str.length())
550 append(str.data(), len);
551 }
552
553 void WriteString(char const* str, size_t len)
554 {
555 if (len)
556 append(str, len);
557 }
558
559 void ReadSkipCString(bool requireValidUtf8 = true) { (void)ReadCString(requireValidUtf8); }
560
561 std::string_view ReadCString(bool requireValidUtf8 = true);
562
563 std::string_view ReadString(uint32 length, bool requireValidUtf8 = true);
564
565 uint8* data() { return _storage.data(); }
566 uint8 const* data() const { return _storage.data(); }
567
568 size_t size() const { return _storage.size(); }
569 bool empty() const { return _storage.empty(); }
570
571 void resize(size_t newsize)
572 {
573 _storage.resize(newsize, 0);
574 _rpos = 0;
575 _wpos = _storage.size();
576 }
577
578 void reserve(size_t ressize)
579 {
580 if (ressize > _storage.size())
581 _storage.reserve(ressize);
582 }
583
585 {
586 _storage.shrink_to_fit();
587 }
588
589 template <ByteBufferNumeric T>
590 void append(T const* src, size_t cnt)
591 {
592#if TRINITY_ENDIAN == TRINITY_LITTLEENDIAN
593 append(reinterpret_cast<uint8 const*>(src), cnt * sizeof(T));
594#else
595 for (size_t i = 0; i < cnt; ++i)
596 append<T>(src[i]);
597#endif
598 }
599
600 void append(uint8 const* src, size_t cnt);
601
602 void append(ByteBuffer const& buffer)
603 {
604 if (!buffer.empty())
605 append(buffer.data(), buffer.size());
606 }
607
608 template <ByteBufferNumeric T, std::size_t Size>
609 void append(std::array<T, Size> const& arr)
610 {
611 append(arr.data(), Size);
612 }
613
614 void put(size_t pos, uint8 const* src, size_t cnt);
615
616 void print_storage() const;
617
618 void textlike() const;
619
620 void hexlike() const;
621
622 [[noreturn]] void OnInvalidPosition(size_t pos, size_t valueSize) const;
623
624 protected:
625 size_t _rpos, _wpos;
628 std::vector<uint8> _storage;
629};
630
631extern template char ByteBuffer::read<char>();
632extern template uint8 ByteBuffer::read<uint8>();
633extern template uint16 ByteBuffer::read<uint16>();
634extern template uint32 ByteBuffer::read<uint32>();
635extern template uint64 ByteBuffer::read<uint64>();
636extern template int8 ByteBuffer::read<int8>();
637extern template int16 ByteBuffer::read<int16>();
638extern template int32 ByteBuffer::read<int32>();
639extern template int64 ByteBuffer::read<int64>();
640extern template float ByteBuffer::read<float>();
641extern template double ByteBuffer::read<double>();
642
643template <typename T>
644concept HasByteBufferShiftOperators = requires(ByteBuffer& data, T const& value) { { data << value } -> std::convertible_to<ByteBuffer&>; }
645 && requires(ByteBuffer& data, T& value) { { data >> value } -> std::convertible_to<ByteBuffer&>; };
646
647#endif
void EndianConvert(T &val)
uint8_t uint8
Definition Define.h:156
#define TC_SHARED_API
Definition Define.h:123
int64_t int64
Definition Define.h:149
int16_t int16
Definition Define.h:151
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
ByteBuffer & operator<<(ByteBuffer &buf, ObjectGuid const &guid)
ByteBuffer & operator>>(ByteBuffer &buf, ObjectGuid &guid)
std::string msg_
Definition ByteBuffer.h:39
ByteBufferException(std::string &&message) noexcept
Definition ByteBuffer.h:34
char const * what() const noexcept override
Definition ByteBuffer.h:36
ByteBufferException()=default
uint32 ReadBits(int32 bits)
Definition ByteBuffer.h:224
ByteBuffer & operator<<(uint32 value)
Definition ByteBuffer.h:300
ByteBuffer & operator>>(int64 &value)
Definition ByteBuffer.h:419
void read_skip()
Definition ByteBuffer.h:480
ByteBuffer & operator<<(double value)
Definition ByteBuffer.h:344
ByteBuffer & operator<<(std::string const &str)
Definition ByteBuffer.h:358
ByteBuffer & operator>>(uint32 &value)
Definition ByteBuffer.h:388
size_t rpos() const
Definition ByteBuffer.h:448
ByteBuffer & operator<<(uint8 value)
Definition ByteBuffer.h:288
size_t bitwpos() const
Returns position of last written bit.
Definition ByteBuffer.h:470
std::vector< uint8 > _storage
Definition ByteBuffer.h:628
ByteBuffer & operator<<(int32 value)
Definition ByteBuffer.h:325
void reserve(size_t ressize)
Definition ByteBuffer.h:578
void WriteString(std::string const &str)
Definition ByteBuffer.h:541
void WriteString(char const *str, size_t len)
Definition ByteBuffer.h:553
ByteBuffer & operator<<(int64 value)
Definition ByteBuffer.h:331
uint8 _bitpos
Definition ByteBuffer.h:626
ByteBuffer & operator<<(std::string_view value)
Definition ByteBuffer.h:350
T read(size_t pos) const
Definition ByteBuffer.h:501
void resize(size_t newsize)
Definition ByteBuffer.h:571
ByteBuffer & operator>>(int16 &value)
Definition ByteBuffer.h:407
void read_skip(size_t skip)
Definition ByteBuffer.h:482
void shrink_to_fit()
Definition ByteBuffer.h:584
ByteBuffer & operator>>(uint8 &value)
Definition ByteBuffer.h:376
void append(T const *src, size_t cnt)
Definition ByteBuffer.h:590
std::vector< uint8 > && Release() &&noexcept
Definition ByteBuffer.h:93
void append(T value)
Definition ByteBuffer.h:130
ByteBuffer & operator<<(float value)
Definition ByteBuffer.h:338
ByteBuffer & operator>>(int8 &value)
Definition ByteBuffer.h:401
ByteBuffer & operator>>(uint16 &value)
Definition ByteBuffer.h:382
void rfinish()
Definition ByteBuffer.h:456
void ResetBitPos()
Definition ByteBuffer.h:152
ByteBuffer(std::vector< uint8 > &&buffer) noexcept
Definition ByteBuffer.h:90
uint8 & operator[](size_t const pos)
Definition ByteBuffer.h:434
ByteBuffer & operator>>(bool &)=delete
uint8 const & operator[](size_t const pos) const
Definition ByteBuffer.h:441
void WriteString(std::string_view str)
Definition ByteBuffer.h:547
ByteBuffer & operator=(ByteBuffer const &right)=default
ByteBuffer & operator<<(uint16 value)
Definition ByteBuffer.h:294
size_t wpos() const
Definition ByteBuffer.h:461
void append(ByteBuffer const &buffer)
Definition ByteBuffer.h:602
void ReadSkipCString(bool requireValidUtf8=true)
Definition ByteBuffer.h:559
ByteBuffer & operator<<(bool)=delete
uint8 _curbitval
Definition ByteBuffer.h:627
ByteBuffer & operator>>(std::string &value)
Definition ByteBuffer.h:428
bool WriteBit(bool bit)
Definition ByteBuffer.h:158
ByteBuffer & operator=(ByteBuffer &&right) noexcept
Definition ByteBuffer.h:104
size_t rpos(size_t rpos_)
Definition ByteBuffer.h:450
void read(std::array< T, Size > &arr)
Definition ByteBuffer.h:534
ByteBuffer(size_t size, Resize)
Definition ByteBuffer.h:80
void put(std::size_t pos, T value)
Definition ByteBuffer.h:260
ByteBuffer(ByteBuffer &&buf) noexcept
Definition ByteBuffer.h:87
ByteBuffer & operator>>(int32 &value)
Definition ByteBuffer.h:413
void clear()
Definition ByteBuffer.h:120
ByteBuffer & operator<<(uint64 value)
Definition ByteBuffer.h:306
ByteBuffer & operator<<(int16 value)
Definition ByteBuffer.h:319
size_t size() const
Definition ByteBuffer.h:568
void read(T *dest, size_t count)
Definition ByteBuffer.h:513
bool empty() const
Definition ByteBuffer.h:569
void append(std::array< T, Size > const &arr)
Definition ByteBuffer.h:609
ByteBuffer(ByteBuffer const &right)=default
uint8 const * data() const
Definition ByteBuffer.h:566
void FlushBits()
Definition ByteBuffer.h:141
size_t _rpos
Definition ByteBuffer.h:625
size_t bitwpos(size_t newPos)
Definition ByteBuffer.h:472
size_t wpos(size_t wpos_)
Definition ByteBuffer.h:463
ByteBuffer & operator<<(int8 value)
Definition ByteBuffer.h:313
bool HasUnfinishedBitPack() const
Definition ByteBuffer.h:136
ByteBuffer & operator>>(char &value)
Definition ByteBuffer.h:370
ByteBuffer & operator<<(char value)
Definition ByteBuffer.h:282
ByteBuffer(size_t size, Reserve)
Definition ByteBuffer.h:75
ByteBuffer & operator>>(uint64 &value)
Definition ByteBuffer.h:394
ByteBuffer & operator<<(char const *str)
Definition ByteBuffer.h:363
uint8 * data()
Definition ByteBuffer.h:565
bool ReadBit()
Definition ByteBuffer.h:174
virtual ~ByteBuffer()=default
void read(uint8 *dest, size_t len)
Definition ByteBuffer.h:523
void WriteBits(uint64 value, int32 bits)
Definition ByteBuffer.h:185