TrinityCore
Loading...
Searching...
No Matches
PacketOperators.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_PACKET_OPERATORS_H
19#define TRINITYCORE_PACKET_OPERATORS_H
20
21#include "ByteBuffer.h"
22#include "Optional.h"
23#include <memory>
24
25namespace WorldPackets
26{
27 namespace Strings
28 {
34 }
35
36 template<typename T>
37 concept AsWritable = std::is_default_constructible_v<T> && HasByteBufferShiftOperators<T>;
38
39 template<typename T, typename Underlying>
40 concept AsWritableFor = requires { static_cast<Underlying>(std::declval<T>()); }
41 && requires { static_cast<T>(Underlying()); };
42
43 template<AsWritable Underlying, AsWritableFor<Underlying> T>
44 struct AsWriter
45 {
46 T const& Value;
47
48 friend inline ByteBuffer& operator<<(ByteBuffer& data, AsWriter const& as)
49 {
50 data << static_cast<Underlying>(as.Value);
51 return data;
52 }
53 };
54
55 template<AsWritable Underlying, AsWritableFor<Underlying> T>
56 struct AsReaderWriter : AsWriter<Underlying, T>
57 {
58 friend inline ByteBuffer& operator>>(ByteBuffer& data, AsReaderWriter const& as)
59 {
60 Underlying temp;
61 data >> temp;
62 const_cast<T&>(as.Value) = static_cast<T>(temp);
63 return data;
64 }
65 };
66
67 template<AsWritable Underlying, AsWritableFor<Underlying> T>
68 inline AsWriter<Underlying, T> As(T const& value) { return { value }; }
69
70 template<AsWritable Underlying, AsWritableFor<Underlying> T>
71 inline AsReaderWriter<Underlying, T> As(T& value) { return { value }; }
72
73 template<typename T>
74 concept OptionalWritable = std::is_default_constructible_v<T>;
75
76 template<OptionalWritable T>
78 {
80
81 friend inline ByteBuffer& operator<<(ByteBuffer& data, OptionalInitWriter const& opt)
82 {
83 data.WriteBit(opt.Opt.has_value());
84 return data;
85 }
86 };
87
88 template<OptionalWritable T>
90 {
91 friend inline ByteBuffer& operator>>(ByteBuffer& data, OptionalInitReaderWriter const& opt)
92 {
93 if (data.ReadBit())
94 const_cast<Optional<T>&>(opt.Opt).emplace();
95 return data;
96 }
97 };
98
99 template<OptionalWritable T>
100 inline OptionalInitWriter<T> OptionalInit(Optional<T> const& value) { return { value }; }
101
102 template<OptionalWritable T>
103 inline OptionalInitReaderWriter<T> OptionalInit(Optional<T>& value) { return { value }; }
104
105 template<OptionalWritable T>
107 {
108 std::unique_ptr<T> const& Ptr;
109
110 friend inline ByteBuffer& operator<<(ByteBuffer& data, PtrInitWriter const& opt)
111 {
112 data.WriteBit(opt.Ptr != nullptr);
113 return data;
114 }
115 };
116
117 template<OptionalWritable T>
119 {
120 friend inline ByteBuffer& operator>>(ByteBuffer& data, PtrInitReaderWriter const& opt)
121 {
122 if (data.ReadBit())
123 const_cast<std::unique_ptr<T>&>(opt.Ptr) = std::make_unique<T>();
124 return data;
125 }
126 };
127
128 template<OptionalWritable T>
129 inline PtrInitWriter<T> OptionalInit(std::unique_ptr<T> const& value) { return { value }; }
130
131 template<OptionalWritable T>
132 inline PtrInitReaderWriter<T> OptionalInit(std::unique_ptr<T>& value) { return { value }; }
133
134 template<typename T>
136
137 template<uint32 BitCount, BitsWritable T>
139 {
140 T const& Value;
141
142 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsWriter const& bits)
143 {
144 if constexpr (BitCount != 1)
145 data.WriteBits(static_cast<uint32>(bits.Value), BitCount);
146 else
147 data.WriteBit(static_cast<uint32>(bits.Value) != 0);
148
149 return data;
150 }
151 };
152
153 template<uint32 BitCount, BitsWritable T>
154 struct BitsReaderWriter : BitsWriter<BitCount, T>
155 {
156 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsReaderWriter const& bits)
157 {
158 if constexpr (BitCount != 1)
159 const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBits(BitCount));
160 else
161 const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBit() ? 1 : 0);
162
163 return data;
164 }
165 };
166
167 template<uint32 BitCount, BitsWritable T>
168 inline BitsWriter<BitCount, T> Bits(T const& value) { return { value }; }
169
170 template<uint32 BitCount, BitsWritable T>
171 inline BitsReaderWriter<BitCount, T> Bits(T& value) { return { value }; }
172
173 template<typename T, typename SizeType>
174 concept ContainerWritable = requires(T const& container) { { container.size() } -> AsWritableFor<SizeType>; }
175 && !std::same_as<T, std::string_view>
176 && !std::same_as<T, std::string>;
177
178 template<typename T, typename SizeType>
180 && !std::is_const_v<T>
181 && requires(T & container) { container.resize(SizeType{}); };
182
183 template<AsWritable Underlying, ContainerWritable<Underlying> Container>
185 {
186 Container const& Value;
187
188 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
189 {
190 data << static_cast<Underlying>(size.Value.size());
191 return data;
192 }
193 };
194
195 template<AsWritable Underlying, ContainerReadable<Underlying> Container>
196 struct SizeReaderWriter : SizeWriter<Underlying, Container>
197 {
198 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
199 {
200 Underlying temp;
201 data >> temp;
202
203 if constexpr (std::is_same_v<Container, std::string> || std::is_same_v<Container, std::string_view>)
204 if (size_t rpos = data.rpos(); temp > data.size() - rpos)
205 data.OnInvalidPosition(rpos, temp);
206
207 if constexpr (std::is_same_v<std::remove_cvref_t<Container>, std::string_view>)
208 // create a temporary string_view pointing at random position in ByteBuffer to be able to retrieve the length later
209 const_cast<std::string_view&>(size.Value) = { reinterpret_cast<char const*>(data.data()), temp };
210 else
211 const_cast<Container&>(size.Value).resize(temp);
212
213 return data;
214 }
215 };
216
217 template<AsWritable Underlying, ContainerWritable<Underlying> Container>
218 inline SizeWriter<Underlying, Container> Size(Container const& value) { return { value }; }
219
220 template<AsWritable Underlying, ContainerReadable<Underlying> Container>
221 inline SizeReaderWriter<Underlying, Container> Size(Container& value) { return { value }; }
222
223 template<uint32 BitCount, ContainerWritable<uint32> Container>
225 {
226 Container const& Value;
227
228 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsSizeWriter const& size)
229 {
230 data.WriteBits(static_cast<uint32>(size.Value.size()), BitCount);
231 return data;
232 }
233 };
234
235 template<uint32 BitCount, ContainerReadable<uint32> Container>
236 struct BitsSizeReaderWriter : BitsSizeWriter<BitCount, Container>
237 {
238 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsSizeReaderWriter const& size)
239 {
240 const_cast<Container&>(size.Value).resize(data.ReadBits(BitCount));
241 return data;
242 }
243 };
244
245 template<uint32 BitCount, ContainerWritable<uint32> Container>
246 inline BitsSizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
247
248 template<uint32 BitCount, ContainerReadable<uint32> Container>
249 inline BitsSizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
250
251 template<typename T>
252 concept StringWritable = requires(T const& container) { { container.length() } -> AsWritableFor<uint32>; }
253 && requires(ByteBuffer& data, T const& string) { data.WriteString(static_cast<std::string_view>(string)); /*TODO: Kill String class and remove the cast*/ };
254
255 template<typename T>
257 && !std::is_const_v<T>
258 && (requires(T& container) { container.resize(uint32()); } || std::same_as<T, std::string_view>)
259 && requires(ByteBuffer& data, T& string) { string = data.ReadString(uint32(), bool()); };
260
261 namespace SizedString
262 {
263 template<uint32 BitCount, StringWritable Container>
265 {
266 Container const& Value;
267
268 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
269 {
270 data.WriteBits(static_cast<uint32>(size.Value.length()), BitCount);
271 return data;
272 }
273 };
274
275 template<uint32 BitCount, StringReadable Container>
276 struct SizeReaderWriter : SizeWriter<BitCount, Container>
277 {
278 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
279 {
280 uint32 length = data.ReadBits(BitCount);
281 if (size_t rpos = data.rpos(); length > data.size() - rpos)
282 data.OnInvalidPosition(rpos, length);
283
284 if constexpr (std::is_same_v<Container, std::string_view>)
285 // create a temporary string_view pointing at start of ByteBuffer to be able to retrieve the length later
286 const_cast<std::string_view&>(size.Value) = { reinterpret_cast<char const*>(data.data()), length };
287 else
288 const_cast<Container&>(size.Value).resize(length);
289
290 return data;
291 }
292 };
293
294 template<uint32 BitCount, StringWritable Container>
295 inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
296
297 template<uint32 BitCount, StringReadable Container>
298 inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
299
300 template<StringWritable Container>
302 {
303 Container const& Value;
304
305 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& string)
306 {
307 data.WriteString(string.Value);
308 return data;
309 }
310 };
311
312 template<StringReadable Container, Strings::Utf8Mode Mode>
313 struct DataReaderWriter : DataWriter<Container>
314 {
315 static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
316
317 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
318 {
319 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length(), IsUtf8());
320 return data;
321 }
322 };
323
324 template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
325 inline DataWriter<Container> Data(Container const& value) { return { value }; }
326
327 template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
328 inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
329 }
330
331 // SizedCString (sends size + string + null terminator but only if not empty)
332 namespace SizedCString
333 {
334 template<uint32 BitCount, StringWritable Container>
336 {
337 Container const& Value;
338
339 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
340 {
341 data.WriteBits(static_cast<uint32>(size.Value.length() + 1), BitCount);
342 return data;
343 }
344 };
345
346 template<uint32 BitCount, StringReadable Container>
347 struct SizeReaderWriter : SizeWriter<BitCount, Container>
348 {
349 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
350 {
351 if (uint32 bytesIncludingNullTerminator = data.ReadBits(BitCount); bytesIncludingNullTerminator > 1)
352 {
353 uint32 length = bytesIncludingNullTerminator - 1;
354 if (size_t rpos = data.rpos(); length > data.size() - rpos)
355 data.OnInvalidPosition(rpos, bytesIncludingNullTerminator);
356
357 if constexpr (std::is_same_v<Container, std::string_view>)
358 // create a temporary string_view pointing at start of ByteBuffer to be able to retrieve the length later
359 const_cast<std::string_view&>(size.Value) = { reinterpret_cast<char const*>(data.data()), length };
360 else
361 const_cast<Container&>(size.Value).resize(length);
362 }
363 return data;
364 }
365 };
366
367 template<uint32 BitCount, StringWritable Container>
368 inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
369
370 template<uint32 BitCount, StringReadable Container>
371 inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
372
373 template<StringWritable Container>
375 {
376 Container const& Value;
377
378 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& string)
379 {
380 if (!string.Value.empty())
381 {
382 data.WriteString(string.Value);
383 data << char('\0');
384 }
385 return data;
386 }
387 };
388
389 template<StringReadable Container, Strings::Utf8Mode Mode>
390 struct DataReaderWriter : DataWriter<Container>
391 {
392 static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
393
394 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
395 {
396 if (!string.Value.empty())
397 {
398 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length(), IsUtf8());
399 (void)data.read<char>(); // null terminator
400 }
401 return data;
402 }
403 };
404
405 template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
406 inline DataWriter<Container> Data(Container const& value) { return { value }; }
407
408 template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
409 inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
410 }
411}
412
413#endif // TRINITYCORE_PACKET_OPERATORS_H
uint8_t uint8
Definition Define.h:156
uint32_t uint32
Definition Define.h:154
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
uint32 ReadBits(int32 bits)
Definition ByteBuffer.h:224
size_t rpos() const
Definition ByteBuffer.h:448
void WriteString(std::string const &str)
Definition ByteBuffer.h:541
void OnInvalidPosition(size_t pos, size_t valueSize) const
bool WriteBit(bool bit)
Definition ByteBuffer.h:158
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
size_t size() const
Definition ByteBuffer.h:568
uint8 * data()
Definition ByteBuffer.h:565
bool ReadBit()
Definition ByteBuffer.h:174
void WriteBits(uint64 value, int32 bits)
Definition ByteBuffer.h:185
SizeWriter< BitCount, Container > BitsSize(Container const &value)
SizeWriter< BitCount, Container > BitsSize(Container const &value)
SizeWriter< Underlying, Container > Size(Container const &value)
OptionalInitWriter< T > OptionalInit(Optional< T > const &value)
AsWriter< Underlying, T > As(T const &value)
BitsWriter< BitCount, T > Bits(T const &value)
BitsSizeWriter< BitCount, Container > BitsSize(Container const &value)
friend ByteBuffer & operator>>(ByteBuffer &data, AsReaderWriter const &as)
friend ByteBuffer & operator<<(ByteBuffer &data, AsWriter const &as)
friend ByteBuffer & operator>>(ByteBuffer &data, BitsReaderWriter const &bits)
friend ByteBuffer & operator>>(ByteBuffer &data, BitsSizeReaderWriter const &size)
friend ByteBuffer & operator<<(ByteBuffer &data, BitsSizeWriter const &size)
friend ByteBuffer & operator<<(ByteBuffer &data, BitsWriter const &bits)
friend ByteBuffer & operator>>(ByteBuffer &data, OptionalInitReaderWriter const &opt)
friend ByteBuffer & operator<<(ByteBuffer &data, OptionalInitWriter const &opt)
friend ByteBuffer & operator>>(ByteBuffer &data, PtrInitReaderWriter const &opt)
friend ByteBuffer & operator<<(ByteBuffer &data, PtrInitWriter const &opt)
std::unique_ptr< T > const & Ptr
friend ByteBuffer & operator>>(ByteBuffer &data, SizeReaderWriter const &size)
friend ByteBuffer & operator<<(ByteBuffer &data, SizeWriter const &size)
friend ByteBuffer & operator>>(ByteBuffer &data, DataReaderWriter const &string)
friend ByteBuffer & operator<<(ByteBuffer &data, DataWriter const &string)
friend ByteBuffer & operator>>(ByteBuffer &data, SizeReaderWriter const &size)
friend ByteBuffer & operator<<(ByteBuffer &data, SizeWriter const &size)
friend ByteBuffer & operator>>(ByteBuffer &data, DataReaderWriter const &string)
friend ByteBuffer & operator<<(ByteBuffer &data, DataWriter const &string)
friend ByteBuffer & operator>>(ByteBuffer &data, SizeReaderWriter const &size)
friend ByteBuffer & operator<<(ByteBuffer &data, SizeWriter const &size)