TrinityCore
ByteBuffer.cpp
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#include "ByteBuffer.h"
19#include "Errors.h"
20#include "MessageBuffer.h"
21#include "Log.h"
22#include "Util.h"
23#include <utf8.h>
24#include <algorithm>
25#include <sstream>
26#include <cmath>
27
28ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0), _storage(buffer.Move())
29{
30}
31
33 : ByteBufferException(Trinity::StringFormat("Attempted to get value with size: {} in ByteBuffer (pos: {} size: {})", valueSize, pos, size))
34{
35}
36
38 : ByteBufferException(Trinity::StringFormat("Invalid {} value ({}) found in ByteBuffer", type, value))
39{
40}
41
43{
44 read(&value, 1);
45 if (!std::isfinite(value))
46 throw ByteBufferInvalidValueException("float", "infinity");
47 return *this;
48}
49
51{
52 read(&value, 1);
53 if (!std::isfinite(value))
54 throw ByteBufferInvalidValueException("double", "infinity");
55 return *this;
56}
57
58std::string_view ByteBuffer::ReadCString(bool requireValidUtf8 /*= true*/)
59{
60 if (_rpos >= size())
62
64
65 char const* begin = reinterpret_cast<char const*>(_storage.data()) + _rpos;
66 char const* end = reinterpret_cast<char const*>(_storage.data()) + size();
67 char const* stringEnd = std::ranges::find(begin, end, '\0');
68 if (stringEnd == end)
70
71 std::string_view value(begin, stringEnd);
72 _rpos += value.length() + 1;
73 if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
74 throw ByteBufferInvalidValueException("string", value);
75 return value;
76}
77
78std::string_view ByteBuffer::ReadString(uint32 length, bool requireValidUtf8 /*= true*/)
79{
80 if (_rpos + length > size())
81 throw ByteBufferPositionException(_rpos, length, size());
82
84 if (!length)
85 return {};
86
87 std::string_view value(reinterpret_cast<char const*>(&_storage[_rpos]), length);
88 _rpos += length;
89 if (requireValidUtf8 && !utf8::is_valid(value.begin(), value.end()))
90 throw ByteBufferInvalidValueException("string", value);
91 return value;
92}
93
94void ByteBuffer::append(uint8 const* src, size_t cnt)
95{
96 ASSERT(src, "Attempted to put a NULL-pointer in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", _wpos, size());
97 ASSERT(cnt, "Attempted to put a zero-sized value in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", _wpos, size());
98 ASSERT((size() + cnt) < 100000000);
99
100 FlushBits();
101
102 size_t const newSize = _wpos + cnt;
103 if (_storage.capacity() < newSize) // custom memory allocation rules
104 {
105 if (newSize < 100)
106 _storage.reserve(300);
107 else if (newSize < 750)
108 _storage.reserve(2500);
109 else if (newSize < 6000)
110 _storage.reserve(10000);
111 else
112 _storage.reserve(400000);
113 }
114
115 if (_storage.size() < newSize)
116 _storage.resize(newSize);
117 std::memcpy(&_storage[_wpos], src, cnt);
118 _wpos = newSize;
119}
120
121void ByteBuffer::put(size_t pos, uint8 const* src, size_t cnt)
122{
123 ASSERT(pos + cnt <= size(), "Attempted to put value with size: " SZFMTD " in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", cnt, pos, size());
124 ASSERT(src, "Attempted to put a NULL-pointer in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", pos, size());
125 ASSERT(cnt, "Attempted to put a zero-sized value in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", pos, size());
126
127 std::memcpy(&_storage[pos], src, cnt);
128}
129
130void ByteBuffer::PutBits(std::size_t pos, std::size_t value, uint32 bitCount)
131{
132 ASSERT(pos + bitCount <= size() * 8, "Attempted to put %u bits in ByteBuffer (bitpos: " SZFMTD " size: " SZFMTD ")", bitCount, pos, size());
133 ASSERT(bitCount, "Attempted to put a zero bits in ByteBuffer");
134
135 for (uint32 i = 0; i < bitCount; ++i)
136 {
137 std::size_t wp = (pos + i) / 8;
138 std::size_t bit = (pos + i) % 8;
139 if ((value >> (bitCount - i - 1)) & 1)
140 _storage[wp] |= 1 << (7 - bit);
141 else
142 _storage[wp] &= ~(1 << (7 - bit));
143 }
144}
145
147{
148 if (!sLog->ShouldLog("network", LOG_LEVEL_TRACE)) // optimize disabled trace output
149 return;
150
151 std::ostringstream o;
152 o << "STORAGE_SIZE: " << size();
153 for (uint32 i = 0; i < size(); ++i)
154 o << read<uint8>(i) << " - ";
155 o << ' ';
156
157 TC_LOG_TRACE("network", "{}", o.str());
158}
159
161{
162 if (!sLog->ShouldLog("network", LOG_LEVEL_TRACE)) // optimize disabled trace output
163 return;
164
165 std::ostringstream o;
166 o << "STORAGE_SIZE: " << size();
167 for (uint32 i = 0; i < size(); ++i)
168 {
169 char buf[2];
170 snprintf(buf, 2, "%c", read<uint8>(i));
171 o << buf;
172 }
173 o << ' ';
174 TC_LOG_TRACE("network", "{}", o.str());
175}
176
178{
179 if (!sLog->ShouldLog("network", LOG_LEVEL_TRACE)) // optimize disabled trace output
180 return;
181
182 uint32 j = 1, k = 1;
183
184 std::ostringstream o;
185 o << "STORAGE_SIZE: " << size();
186
187 for (uint32 i = 0; i < size(); ++i)
188 {
189 char buf[4];
190 snprintf(buf, 4, "%02X", read<uint8>(i));
191 if ((i == (j * 8)) && ((i != (k * 16))))
192 {
193 o << "| ";
194 ++j;
195 }
196 else if (i == (k * 16))
197 {
198 o << '\n';
199 ++k;
200 ++j;
201 }
202
203 o << buf;
204 }
205 o << ' ';
206 TC_LOG_TRACE("network", "{}", o.str());
207}
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
#define SZFMTD
Definition: Define.h:132
#define ASSERT
Definition: Errors.h:68
@ LOG_LEVEL_TRACE
Definition: LogCommon.h:27
#define sLog
Definition: Log.h:154
#define TC_LOG_TRACE(filterType__, message__,...)
Definition: Log.h:176
ByteBufferInvalidValueException(char const *type, std::string_view value)
Definition: ByteBuffer.cpp:37
ByteBufferPositionException(size_t pos, size_t size, size_t valueSize)
Definition: ByteBuffer.cpp:32
size_t _wpos
Definition: ByteBuffer.h:664
std::vector< uint8 > _storage
Definition: ByteBuffer.h:667
void PutBits(std::size_t pos, std::size_t value, uint32 bitCount)
Definition: ByteBuffer.cpp:130
void hexlike() const
Definition: ByteBuffer.cpp:177
void print_storage() const
Definition: ByteBuffer.cpp:146
void append(T value)
Definition: ByteBuffer.h:137
std::string_view ReadCString(bool requireValidUtf8=true)
Definition: ByteBuffer.cpp:58
void ResetBitPos()
Definition: ByteBuffer.h:160
void textlike() const
Definition: ByteBuffer.cpp:160
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
Definition: ByteBuffer.cpp:78
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:246
size_t size() const
Definition: ByteBuffer.h:566
void FlushBits()
Definition: ByteBuffer.h:149
size_t _rpos
Definition: ByteBuffer.h:664
ByteBuffer & operator>>(bool &value)
Definition: ByteBuffer.h:347
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
constexpr std::size_t size()
Definition: UpdateField.h:769