TrinityCore
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 "Define.h"
22#include "ByteConverter.h"
23#include <array>
24#include <string>
25#include <vector>
26#include <cstring>
27
28class MessageBuffer;
29
30// Root of ByteBuffer exception hierarchy
31class TC_SHARED_API ByteBufferException : public std::exception
32{
33public:
34 explicit ByteBufferException() = default;
35 explicit ByteBufferException(std::string&& message) noexcept : msg_(std::move(message)) { }
36
37 char const* what() const noexcept override { return msg_.c_str(); }
38
39protected:
40 std::string msg_;
41};
42
44{
45public:
46 ByteBufferPositionException(size_t pos, size_t size, size_t valueSize);
47};
48
50{
51public:
52 ByteBufferInvalidValueException(char const* type, std::string_view value);
53};
54
56{
57 public:
58 constexpr static size_t DEFAULT_SIZE = 0x1000;
59 constexpr static uint8 InitialBitPos = 8;
60
61 // constructor
62 ByteBuffer() : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0)
63 {
64 _storage.reserve(DEFAULT_SIZE);
65 }
66
67 // reserve/resize tag
68 struct Reserve { };
69 struct Resize { };
70
71 ByteBuffer(size_t size, Reserve) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0)
72 {
73 _storage.reserve(size);
74 }
75
76 ByteBuffer(size_t size, Resize) : _rpos(0), _wpos(size), _bitpos(InitialBitPos), _curbitval(0)
77 {
78 _storage.resize(size);
79 }
80
81 ByteBuffer(ByteBuffer&& buf) noexcept : _rpos(buf._rpos), _wpos(buf._wpos),
82 _bitpos(buf._bitpos), _curbitval(buf._curbitval), _storage(buf.Move()) { }
83
84 ByteBuffer(ByteBuffer const& right) = default;
85
86 ByteBuffer(MessageBuffer&& buffer);
87
88 std::vector<uint8>&& Move() noexcept
89 {
90 _rpos = 0;
91 _wpos = 0;
92 _bitpos = InitialBitPos;
93 _curbitval = 0;
94 return std::move(_storage);
95 }
96
98 {
99 if (this != &right)
100 {
101 _rpos = right._rpos;
102 _wpos = right._wpos;
103 _bitpos = right._bitpos;
104 _curbitval = right._curbitval;
105 _storage = right._storage;
106 }
107
108 return *this;
109 }
110
111 ByteBuffer& operator=(ByteBuffer&& right) noexcept
112 {
113 if (this != &right)
114 {
115 _rpos = right._rpos;
116 _wpos = right._wpos;
117 _bitpos = right._bitpos;
118 _curbitval = right._curbitval;
119 _storage = right.Move();
120 }
121
122 return *this;
123 }
124
125 virtual ~ByteBuffer() = default;
126
127 void clear()
128 {
129 _rpos = 0;
130 _wpos = 0;
131 _bitpos = InitialBitPos;
132 _curbitval = 0;
133 _storage.clear();
134 }
135
136 template <typename T>
137 void append(T value)
138 {
139 static_assert(std::is_trivially_copyable_v<T>, "append(T) must be used with trivially copyable types");
140 EndianConvert(value);
141 append(reinterpret_cast<uint8 const*>(&value), sizeof(value));
142 }
143
145 {
146 return _bitpos != 8;
147 }
148
150 {
151 if (_bitpos == 8)
152 return;
153
154 _bitpos = 8;
155
156 append(&_curbitval, sizeof(uint8));
157 _curbitval = 0;
158 }
159
161 {
162 if (_bitpos > 7)
163 return;
164
165 _bitpos = 8;
166 _curbitval = 0;
167 }
168
169 bool WriteBit(bool bit)
170 {
171 --_bitpos;
172 if (bit)
173 _curbitval |= (1 << (_bitpos));
174
175 if (_bitpos == 0)
176 {
177 _bitpos = 8;
178 append(&_curbitval, sizeof(_curbitval));
179 _curbitval = 0;
180 }
181
182 return bit;
183 }
184
185 bool ReadBit()
186 {
187 ++_bitpos;
188 if (_bitpos > 7)
189 {
190 _curbitval = read<uint8>();
191 _bitpos = 0;
192 }
193
194 return ((_curbitval >> (7 - _bitpos)) & 1) != 0;
195 }
196
197 void WriteBits(uint64 value, int32 bits)
198 {
199 // remove bits that don't fit
200 value &= (UI64LIT(1) << bits) - 1;
201
202 if (bits > int32(_bitpos))
203 {
204 // first write to fill bit buffer
205 _curbitval |= value >> (bits - _bitpos);
206 bits -= _bitpos;
207 _bitpos = 8; // required "unneccessary" write to avoid double flushing
208 append(&_curbitval, sizeof(_curbitval));
209
210 // then append as many full bytes as possible
211 while (bits >= 8)
212 {
213 bits -= 8;
214 append<uint8>(value >> bits);
215 }
216
217 // store remaining bits in the bit buffer
218 _bitpos = 8 - bits;
219 _curbitval = (value & ((UI64LIT(1) << bits) - 1)) << _bitpos;
220 }
221 else
222 {
223 // entire value fits in the bit buffer
224 _bitpos -= bits;
225 _curbitval |= value << _bitpos;
226
227 if (_bitpos == 0)
228 {
229 _bitpos = 8;
230 append(&_curbitval, sizeof(_curbitval));
231 _curbitval = 0;
232 }
233 }
234 }
235
237 {
238 uint32 value = 0;
239 for (int32 i = bits - 1; i >= 0; --i)
240 value |= uint32(ReadBit()) << i;
241
242 return value;
243 }
244
245 template <typename T>
246 void put(std::size_t pos, T value)
247 {
248 static_assert(std::is_trivially_copyable_v<T>, "put(size_t, T) must be used with trivially copyable types");
249 EndianConvert(value);
250 put(pos, reinterpret_cast<uint8 const*>(&value), sizeof(value));
251 }
252
265 void PutBits(std::size_t pos, std::size_t value, uint32 bitCount);
266
268 {
269 append<uint8>(value);
270 return *this;
271 }
272
274 {
275 append<uint16>(value);
276 return *this;
277 }
278
280 {
281 append<uint32>(value);
282 return *this;
283 }
284
286 {
287 append<uint64>(value);
288 return *this;
289 }
290
291 // signed as in 2e complement
293 {
294 append<int8>(value);
295 return *this;
296 }
297
299 {
300 append<int16>(value);
301 return *this;
302 }
303
305 {
306 append<int32>(value);
307 return *this;
308 }
309
311 {
312 append<int64>(value);
313 return *this;
314 }
315
316 // floating points
317 ByteBuffer& operator<<(float value)
318 {
319 append<float>(value);
320 return *this;
321 }
322
323 ByteBuffer& operator<<(double value)
324 {
325 append<double>(value);
326 return *this;
327 }
328
329 ByteBuffer& operator<<(std::string_view value)
330 {
331 if (size_t len = value.length())
332 append(reinterpret_cast<uint8 const*>(value.data()), len);
333 append(static_cast<uint8>(0));
334 return *this;
335 }
336
337 ByteBuffer& operator<<(std::string const& str)
338 {
339 return operator<<(std::string_view(str));
340 }
341
342 ByteBuffer& operator<<(char const* str)
343 {
344 return operator<<(std::string_view(str ? str : ""));
345 }
346
347 ByteBuffer& operator>>(bool& value)
348 {
349 value = read<char>() > 0;
350 return *this;
351 }
352
354 {
355 read(&value, 1);
356 return *this;
357 }
358
360 {
361 read(&value, 1);
362 return *this;
363 }
364
366 {
367 read(&value, 1);
368 return *this;
369 }
370
372 {
373 read(&value, 1);
374 return *this;
375 }
376
377 //signed as in 2e complement
379 {
380 read(&value, 1);
381 return *this;
382 }
383
385 {
386 read(&value, 1);
387 return *this;
388 }
389
391 {
392 read(&value, 1);
393 return *this;
394 }
395
397 {
398 read(&value, 1);
399 return *this;
400 }
401
402 ByteBuffer& operator>>(float& value);
403 ByteBuffer& operator>>(double& value);
404
405 ByteBuffer& operator>>(std::string& value)
406 {
407 value = ReadCString(true);
408 return *this;
409 }
410
411 uint8& operator[](size_t const pos)
412 {
413 if (pos >= size())
414 throw ByteBufferPositionException(pos, 1, size());
415 return _storage[pos];
416 }
417
418 uint8 const& operator[](size_t const pos) const
419 {
420 if (pos >= size())
421 throw ByteBufferPositionException(pos, 1, size());
422 return _storage[pos];
423 }
424
425 size_t rpos() const { return _rpos; }
426
427 size_t rpos(size_t rpos_)
428 {
429 _rpos = rpos_;
430 return _rpos;
431 }
432
433 void rfinish()
434 {
435 _rpos = wpos();
436 }
437
438 size_t wpos() const { return _wpos; }
439
440 size_t wpos(size_t wpos_)
441 {
442 _wpos = wpos_;
443 return _wpos;
444 }
445
447 size_t bitwpos() const { return _wpos * 8 + 8 - _bitpos; }
448
449 size_t bitwpos(size_t newPos)
450 {
451 _wpos = newPos / 8;
452 _bitpos = 8 - (newPos % 8);
453 return _wpos * 8 + 8 - _bitpos;
454 }
455
456 template <typename T>
457 void read_skip() { read_skip(sizeof(T)); }
458
459 void read_skip(size_t skip)
460 {
461 if (_rpos + skip > size())
462 throw ByteBufferPositionException(_rpos, skip, size());
463
464 ResetBitPos();
465 _rpos += skip;
466 }
467
468 template <typename T>
470 {
471 ResetBitPos();
472 T r = read<T>(_rpos);
473 _rpos += sizeof(T);
474 return r;
475 }
476
477 template <typename T>
478 T read(size_t pos) const
479 {
480 if (pos + sizeof(T) > size())
481 throw ByteBufferPositionException(pos, sizeof(T), size());
482 T val;
483 std::memcpy(&val, &_storage[pos], sizeof(T));
484 EndianConvert(val);
485 return val;
486 }
487
488 template <typename T>
489 void read(T* dest, size_t count)
490 {
491 static_assert(std::is_trivially_copyable_v<T>, "read(T*, size_t) must be used with trivially copyable types");
492 read(reinterpret_cast<uint8*>(dest), count * sizeof(T));
493#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
494 for (size_t i = 0; i < count; ++i)
495 EndianConvert(dest[i]);
496#endif
497 }
498
499 void read(uint8* dest, size_t len)
500 {
501 if (_rpos + len > size())
502 throw ByteBufferPositionException(_rpos, len, size());
503
504 ResetBitPos();
505 std::memcpy(dest, &_storage[_rpos], len);
506 _rpos += len;
507 }
508
509 template <size_t Size>
510 void read(std::array<uint8, Size>& arr)
511 {
512 read(arr.data(), Size);
513 }
514
516 {
517 guid = 0;
518 ReadPackedUInt64(read<uint8>(), guid);
519 }
520
521 void ReadPackedUInt64(uint8 mask, uint64& value)
522 {
523 for (uint32 i = 0; i < 8; ++i)
524 if (mask & (uint8(1) << i))
525 value |= (uint64(read<uint8>()) << (i * 8));
526 }
527
530 void WriteString(std::string const& str)
531 {
532 if (size_t len = str.length())
533 append(str.c_str(), len);
534 }
535
536 void WriteString(std::string_view str)
537 {
538 if (size_t len = str.length())
539 append(str.data(), len);
540 }
541
542 void WriteString(char const* str, size_t len)
543 {
544 if (len)
545 append(str, len);
546 }
547
548 std::string_view ReadCString(bool requireValidUtf8 = true);
549
550 std::string_view ReadString(uint32 length, bool requireValidUtf8 = true);
551
553 {
554 if (_storage.empty())
555 throw ByteBufferException();
556 return _storage.data();
557 }
558
559 uint8 const* contents() const
560 {
561 if (_storage.empty())
562 throw ByteBufferException();
563 return _storage.data();
564 }
565
566 size_t size() const { return _storage.size(); }
567 bool empty() const { return _storage.empty(); }
568
569 void resize(size_t newsize)
570 {
571 _storage.resize(newsize, 0);
572 _rpos = 0;
573 _wpos = size();
574 }
575
576 void reserve(size_t ressize)
577 {
578 if (ressize > size())
579 _storage.reserve(ressize);
580 }
581
583 {
584 _storage.shrink_to_fit();
585 }
586
587 template <typename T>
588 void append(T const* src, size_t cnt)
589 {
590#if TRINITY_ENDIAN == TRINITY_LITTLEENDIAN
591 append(reinterpret_cast<uint8 const*>(src), cnt * sizeof(T));
592#else
593 for (size_t i = 0; i < cnt; ++i)
594 append<T>(src[i]);
595#endif
596 }
597
598 void append(uint8 const* src, size_t cnt);
599
600 void append(ByteBuffer const& buffer)
601 {
602 if (!buffer.empty())
603 append(buffer.contents(), buffer.size());
604 }
605
606 template <size_t Size>
607 void append(std::array<uint8, Size> const& arr)
608 {
609 append(arr.data(), Size);
610 }
611
612 // can be used in SMSG_MONSTER_MOVE opcode
613 void appendPackXYZ(float x, float y, float z)
614 {
615 uint32 packed = 0;
616 packed |= ((int)(x / 0.25f) & 0x7FF);
617 packed |= ((int)(y / 0.25f) & 0x7FF) << 11;
618 packed |= ((int)(z / 0.25f) & 0x3FF) << 22;
619 *this << packed;
620 }
621
623 {
624 uint8 mask = 0;
625 size_t pos = wpos();
626 *this << uint8(mask);
627
628 uint8 packed[8];
629 if (size_t packedSize = PackUInt64(guid, &mask, packed))
630 append(packed, packedSize);
631
632 put<uint8>(pos, mask);
633 }
634
635 static size_t PackUInt64(uint64 value, uint8* mask, uint8* result)
636 {
637 size_t resultSize = 0;
638 *mask = 0;
639 memset(result, 0, 8);
640
641 for (uint8 i = 0; value != 0; ++i)
642 {
643 if (value & 0xFF)
644 {
645 *mask |= uint8(1 << i);
646 result[resultSize++] = uint8(value & 0xFF);
647 }
648
649 value >>= 8;
650 }
651
652 return resultSize;
653 }
654
655 void put(size_t pos, uint8 const* src, size_t cnt);
656
657 void print_storage() const;
658
659 void textlike() const;
660
661 void hexlike() const;
662
663 protected:
664 size_t _rpos, _wpos;
667 std::vector<uint8> _storage;
668};
669
671template <> inline std::string ByteBuffer::read<std::string>()
672{
673 return std::string(ReadCString());
674}
675
676template <>
677inline void ByteBuffer::read_skip<char*>()
678{
679 (void)ReadCString();
680}
681
682template <>
683inline void ByteBuffer::read_skip<char const*>()
684{
685 read_skip<char*>();
686}
687
688template <>
689inline void ByteBuffer::read_skip<std::string>()
690{
691 read_skip<char*>();
692}
693
694#endif
void EndianConvert(T &val)
Definition: ByteConverter.h:48
uint8_t uint8
Definition: Define.h:144
#define TC_SHARED_API
Definition: Define.h:117
int64_t int64
Definition: Define.h:137
int16_t int16
Definition: Define.h:139
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
ByteBuffer & operator<<(ByteBuffer &buf, ObjectGuid const &guid)
Definition: ObjectGuid.cpp:962
ByteBuffer & operator>>(ByteBuffer &buf, ObjectGuid &guid)
Definition: ObjectGuid.cpp:983
std::string msg_
Definition: ByteBuffer.h:40
ByteBufferException(std::string &&message) noexcept
Definition: ByteBuffer.h:35
char const * what() const noexcept override
Definition: ByteBuffer.h:37
ByteBufferException()=default
void append(std::array< uint8, Size > const &arr)
Definition: ByteBuffer.h:607
uint32 ReadBits(int32 bits)
Definition: ByteBuffer.h:236
size_t _wpos
Definition: ByteBuffer.h:664
void read(std::array< uint8, Size > &arr)
Definition: ByteBuffer.h:510
ByteBuffer & operator<<(uint32 value)
Definition: ByteBuffer.h:279
ByteBuffer & operator>>(int64 &value)
Definition: ByteBuffer.h:396
void read_skip()
Definition: ByteBuffer.h:457
ByteBuffer & operator<<(double value)
Definition: ByteBuffer.h:323
ByteBuffer & operator<<(std::string const &str)
Definition: ByteBuffer.h:337
void appendPackXYZ(float x, float y, float z)
Definition: ByteBuffer.h:613
ByteBuffer & operator>>(uint32 &value)
Definition: ByteBuffer.h:365
size_t rpos() const
Definition: ByteBuffer.h:425
ByteBuffer & operator<<(uint8 value)
Definition: ByteBuffer.h:267
size_t bitwpos() const
Returns position of last written bit.
Definition: ByteBuffer.h:447
std::vector< uint8 > _storage
Definition: ByteBuffer.h:667
ByteBuffer & operator<<(int32 value)
Definition: ByteBuffer.h:304
void reserve(size_t ressize)
Definition: ByteBuffer.h:576
uint8 const * contents() const
Definition: ByteBuffer.h:559
void WriteString(std::string const &str)
Definition: ByteBuffer.h:530
ByteBuffer & operator=(ByteBuffer const &right)
Definition: ByteBuffer.h:97
void WriteString(char const *str, size_t len)
Definition: ByteBuffer.h:542
void ReadPackedUInt64(uint8 mask, uint64 &value)
Definition: ByteBuffer.h:521
ByteBuffer & operator<<(int64 value)
Definition: ByteBuffer.h:310
uint8 _bitpos
Definition: ByteBuffer.h:665
ByteBuffer & operator<<(std::string_view value)
Definition: ByteBuffer.h:329
T read(size_t pos) const
Definition: ByteBuffer.h:478
void resize(size_t newsize)
Definition: ByteBuffer.h:569
std::vector< uint8 > && Move() noexcept
Definition: ByteBuffer.h:88
static size_t PackUInt64(uint64 value, uint8 *mask, uint8 *result)
Definition: ByteBuffer.h:635
ByteBuffer & operator>>(int16 &value)
Definition: ByteBuffer.h:384
void read_skip(size_t skip)
Definition: ByteBuffer.h:459
void shrink_to_fit()
Definition: ByteBuffer.h:582
ByteBuffer & operator>>(uint8 &value)
Definition: ByteBuffer.h:353
void append(T const *src, size_t cnt)
Definition: ByteBuffer.h:588
void append(T value)
Definition: ByteBuffer.h:137
ByteBuffer & operator<<(float value)
Definition: ByteBuffer.h:317
ByteBuffer & operator>>(int8 &value)
Definition: ByteBuffer.h:378
std::string_view ReadCString(bool requireValidUtf8=true)
Definition: ByteBuffer.cpp:58
ByteBuffer & operator>>(uint16 &value)
Definition: ByteBuffer.h:359
void rfinish()
Definition: ByteBuffer.h:433
void ResetBitPos()
Definition: ByteBuffer.h:160
uint8 & operator[](size_t const pos)
Definition: ByteBuffer.h:411
uint8 const & operator[](size_t const pos) const
Definition: ByteBuffer.h:418
void WriteString(std::string_view str)
Definition: ByteBuffer.h:536
ByteBuffer & operator<<(uint16 value)
Definition: ByteBuffer.h:273
size_t wpos() const
Definition: ByteBuffer.h:438
void append(ByteBuffer const &buffer)
Definition: ByteBuffer.h:600
uint8 _curbitval
Definition: ByteBuffer.h:666
ByteBuffer & operator>>(std::string &value)
Definition: ByteBuffer.h:405
bool WriteBit(bool bit)
Definition: ByteBuffer.h:169
ByteBuffer & operator=(ByteBuffer &&right) noexcept
Definition: ByteBuffer.h:111
size_t rpos(size_t rpos_)
Definition: ByteBuffer.h:427
ByteBuffer(size_t size, Resize)
Definition: ByteBuffer.h:76
void ReadPackedUInt64(uint64 &guid)
Definition: ByteBuffer.h:515
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:246
ByteBuffer(ByteBuffer &&buf) noexcept
Definition: ByteBuffer.h:81
ByteBuffer & operator>>(int32 &value)
Definition: ByteBuffer.h:390
void clear()
Definition: ByteBuffer.h:127
ByteBuffer & operator<<(uint64 value)
Definition: ByteBuffer.h:285
ByteBuffer & operator<<(int16 value)
Definition: ByteBuffer.h:298
size_t size() const
Definition: ByteBuffer.h:566
void read(T *dest, size_t count)
Definition: ByteBuffer.h:489
bool empty() const
Definition: ByteBuffer.h:567
void AppendPackedUInt64(uint64 guid)
Definition: ByteBuffer.h:622
ByteBuffer(ByteBuffer const &right)=default
void FlushBits()
Definition: ByteBuffer.h:149
size_t _rpos
Definition: ByteBuffer.h:664
size_t bitwpos(size_t newPos)
Definition: ByteBuffer.h:449
size_t wpos(size_t wpos_)
Definition: ByteBuffer.h:440
ByteBuffer & operator<<(int8 value)
Definition: ByteBuffer.h:292
bool HasUnfinishedBitPack() const
Definition: ByteBuffer.h:144
ByteBuffer & operator>>(bool &value)
Definition: ByteBuffer.h:347
ByteBuffer(size_t size, Reserve)
Definition: ByteBuffer.h:71
uint8 * contents()
Definition: ByteBuffer.h:552
ByteBuffer & operator>>(uint64 &value)
Definition: ByteBuffer.h:371
ByteBuffer & operator<<(char const *str)
Definition: ByteBuffer.h:342
bool ReadBit()
Definition: ByteBuffer.h:185
virtual ~ByteBuffer()=default
void read(uint8 *dest, size_t len)
Definition: ByteBuffer.h:499
void WriteBits(uint64 value, int32 bits)
Definition: ByteBuffer.h:197
constexpr std::size_t size()
Definition: UpdateField.h:769