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