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 const_cast<Container&>(size.Value).resize(temp);
204 return data;
205 }
206 };
207
208 template<AsWritable Underlying, ContainerWritable<Underlying> Container>
209 inline SizeWriter<Underlying, Container> Size(Container const& value) { return { value }; }
210
211 template<AsWritable Underlying, ContainerReadable<Underlying> Container>
212 inline SizeReaderWriter<Underlying, Container> Size(Container& value) { return { value }; }
213
214 template<uint32 BitCount, ContainerWritable<uint32> Container>
216 {
217 Container const& Value;
218
219 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsSizeWriter const& size)
220 {
221 data.WriteBits(static_cast<uint32>(size.Value.size()), BitCount);
222 return data;
223 }
224 };
225
226 template<uint32 BitCount, ContainerReadable<uint32> Container>
227 struct BitsSizeReaderWriter : BitsSizeWriter<BitCount, Container>
228 {
229 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsSizeReaderWriter const& size)
230 {
231 const_cast<Container&>(size.Value).resize(data.ReadBits(BitCount));
232 return data;
233 }
234 };
235
236 template<uint32 BitCount, ContainerWritable<uint32> Container>
237 inline BitsSizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
238
239 template<uint32 BitCount, ContainerReadable<uint32> Container>
240 inline BitsSizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
241
242 template<typename T>
243 concept StringWritable = requires(T const& container) { { container.length() } -> AsWritableFor<uint32>; }
244 && requires(ByteBuffer& data, T const& string) { data.WriteString(static_cast<std::string_view>(string)); /*TODO: Kill String class and remove the cast*/ };
245
246 template<typename T>
248 && !std::is_const_v<T>
249 && (requires(T& container) { container.resize(uint32()); } || std::same_as<T, std::string_view>)
250 && requires(ByteBuffer& data, T& string) { string = data.ReadString(uint32(), bool()); };
251
252 namespace SizedString
253 {
254 template<uint32 BitCount, StringWritable Container>
256 {
257 Container const& Value;
258
259 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
260 {
261 data.WriteBits(static_cast<uint32>(size.Value.length()), BitCount);
262 return data;
263 }
264 };
265
266 template<uint32 BitCount, StringReadable Container>
267 struct SizeReaderWriter : SizeWriter<BitCount, Container>
268 {
269 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
270 {
271 uint32 length = data.ReadBits(BitCount);
272 if (size_t rpos = data.rpos(); length > data.size() - rpos)
273 data.OnInvalidPosition(rpos, length);
274
275 if constexpr (std::is_same_v<Container, std::string_view>)
276 // create a temporary string_view pointing at start of ByteBuffer to be able to retrieve the length later
277 const_cast<std::string_view&>(size.Value) = { reinterpret_cast<char const*>(data.data()), length };
278 else
279 const_cast<Container&>(size.Value).resize(length);
280
281 return data;
282 }
283 };
284
285 template<uint32 BitCount, StringWritable Container>
286 inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
287
288 template<uint32 BitCount, StringReadable Container>
289 inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
290
291 template<StringWritable Container>
293 {
294 Container const& Value;
295
296 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& string)
297 {
298 data.WriteString(string.Value);
299 return data;
300 }
301 };
302
303 template<StringReadable Container, Strings::Utf8Mode Mode>
304 struct DataReaderWriter : DataWriter<Container>
305 {
306 static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
307
308 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
309 {
310 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length(), IsUtf8());
311 return data;
312 }
313 };
314
315 template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
316 inline DataWriter<Container> Data(Container const& value) { return { value }; }
317
318 template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
319 inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
320 }
321
322 // SizedCString (sends size + string + null terminator but only if not empty)
323 namespace SizedCString
324 {
325 template<uint32 BitCount, StringWritable Container>
327 {
328 Container const& Value;
329
330 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
331 {
332 data.WriteBits(static_cast<uint32>(size.Value.length() + 1), BitCount);
333 return data;
334 }
335 };
336
337 template<uint32 BitCount, StringReadable Container>
338 struct SizeReaderWriter : SizeWriter<BitCount, Container>
339 {
340 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
341 {
342 if (uint32 bytesIncludingNullTerminator = data.ReadBits(BitCount); bytesIncludingNullTerminator > 1)
343 {
344 uint32 length = bytesIncludingNullTerminator - 1;
345 if (size_t rpos = data.rpos(); length > data.size() - rpos)
346 data.OnInvalidPosition(rpos, bytesIncludingNullTerminator);
347
348 if constexpr (std::is_same_v<Container, std::string_view>)
349 // create a temporary string_view pointing at start of ByteBuffer to be able to retrieve the length later
350 const_cast<std::string_view&>(size.Value) = { reinterpret_cast<char const*>(data.data()), length };
351 else
352 const_cast<Container&>(size.Value).resize(length);
353 }
354 return data;
355 }
356 };
357
358 template<uint32 BitCount, StringWritable Container>
359 inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
360
361 template<uint32 BitCount, StringReadable Container>
362 inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
363
364 template<StringWritable Container>
366 {
367 Container const& Value;
368
369 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& string)
370 {
371 if (!string.Value.empty())
372 {
373 data.WriteString(string.Value);
374 data << char('\0');
375 }
376 return data;
377 }
378 };
379
380 template<StringReadable Container, Strings::Utf8Mode Mode>
381 struct DataReaderWriter : DataWriter<Container>
382 {
383 static constexpr bool IsUtf8() { return Mode == Strings::ValidUtf8; }
384
385 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
386 {
387 if (!string.Value.empty())
388 {
389 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length(), IsUtf8());
390 (void)data.read<char>(); // null terminator
391 }
392 return data;
393 }
394 };
395
396 template<Strings::Utf8Mode = Strings::ValidUtf8, StringWritable Container>
397 inline DataWriter<Container> Data(Container const& value) { return { value }; }
398
399 template<Strings::Utf8Mode Mode = Strings::ValidUtf8, StringReadable Container>
400 inline DataReaderWriter<Container, Mode> Data(Container& value) { return { value }; }
401 }
402
403 namespace Bytes
404 {
405 template<AsWritable Underlying>
407 {
408 std::span<uint8> const& Value;
409
410 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& size)
411 {
412 data << static_cast<Underlying>(size.Value.size());
413 return data;
414 }
415 };
416
417 template<AsWritable Underlying>
418 struct SizeReaderWriter : SizeWriter<Underlying>
419 {
420 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& size)
421 {
422 Underlying temp;
423 data >> temp;
424
425 if (size_t rpos = data.rpos(); temp > data.size() - rpos)
426 data.OnInvalidPosition(rpos, temp);
427
428 // create a temporary span pointing at random position in ByteBuffer to be able to retrieve the length later
429 const_cast<std::span<uint8>&>(size.Value) = { data.data(), temp };
430 return data;
431 }
432 };
433
434 template<AsWritable Underlying>
435 inline SizeWriter<Underlying> Size(std::span<uint8> const& value) { return { value }; }
436
437 template<AsWritable Underlying>
438 inline SizeReaderWriter<Underlying> Size(std::span<uint8>& value) { return { value }; }
439
440 template<uint32 BitCount>
442 {
443 std::span<uint8> const& Value;
444
445 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsSizeWriter const& size)
446 {
447 data.WriteBits(static_cast<uint32>(size.Value.size()), BitCount);
448 return data;
449 }
450 };
451
452 template<uint32 BitCount>
454 {
455 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsSizeReaderWriter const& size)
456 {
457 uint32 length = data.ReadBits(BitCount);
458 if (size_t rpos = data.rpos(); length > data.size() - rpos)
459 data.OnInvalidPosition(rpos, length);
460
461 // create a temporary span pointing at start of ByteBuffer to be able to retrieve the length later
462 const_cast<std::span<uint8>&>(size.Value) = { data.data(), length };
463 return data;
464 }
465 };
466
467 template<uint32 BitCount>
468 inline BitsSizeWriter<BitCount> BitsSize(std::span<uint8> const& value) { return { value }; }
469
470 template<uint32 BitCount>
471 inline BitsSizeReaderWriter<BitCount> BitsSize(std::span<uint8>& value) { return { value }; }
472
474 {
475 std::span<uint8> const& Value;
476
477 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& span)
478 {
479 if (!data.empty())
480 data.append(span.Value.data(), span.Value.size());
481 return data;
482 }
483 };
484
486 {
487 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
488 {
489 const_cast<std::span<uint8>&>(string.Value) = data.ReadBytes(string.Value.size());
490 return data;
491 }
492 };
493
494 inline DataWriter Data(std::span<uint8> const& value) { return { value }; }
495
496 inline DataReaderWriter Data(std::span<uint8>& value) { return { value }; }
497 }
498
499 template <typename T>
501 {
502 friend inline ByteBuffer& operator<<(ByteBuffer& data, IgnoredReaderWriter const& /*unused*/)
503 {
504 data << T();
505 return data;
506 }
507
508 friend inline ByteBuffer& operator>>(ByteBuffer& data, IgnoredReaderWriter const& /*unused*/)
509 {
510 if constexpr (ByteBufferNumeric<T>)
511 {
512 data.read_skip<T>();
513 }
514 else
515 {
516 T dummy;
517 data >> dummy;
518 }
519 return data;
520 }
521 };
522
523 template <typename T>
525}
526
527#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:225
void read_skip()
Definition ByteBuffer.h:481
size_t rpos() const
Definition ByteBuffer.h:449
void WriteString(std::string const &str)
Definition ByteBuffer.h:542
std::span< uint8 > ReadBytes(size_t length)
Definition ByteBuffer.h:566
void OnInvalidPosition(size_t pos, size_t valueSize) const
void append(T value)
Definition ByteBuffer.h:131
bool WriteBit(bool bit)
Definition ByteBuffer.h:159
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
size_t size() const
Definition ByteBuffer.h:580
bool empty() const
Definition ByteBuffer.h:581
uint8 * data()
Definition ByteBuffer.h:577
bool ReadBit()
Definition ByteBuffer.h:175
void WriteBits(uint64 value, int32 bits)
Definition ByteBuffer.h:186
SizeWriter< Underlying > Size(std::span< uint8 > const &value)
BitsSizeWriter< BitCount > BitsSize(std::span< uint8 > const &value)
SizeWriter< BitCount, Container > BitsSize(Container const &value)
SizeWriter< BitCount, Container > BitsSize(Container const &value)
constexpr IgnoredReaderWriter< T > Ignored
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, BitsSizeReaderWriter const &size)
std::span< uint8 > const & Value
friend ByteBuffer & operator<<(ByteBuffer &data, BitsSizeWriter const &size)
friend ByteBuffer & operator>>(ByteBuffer &data, DataReaderWriter const &string)
std::span< uint8 > const & Value
friend ByteBuffer & operator<<(ByteBuffer &data, DataWriter const &span)
friend ByteBuffer & operator>>(ByteBuffer &data, SizeReaderWriter const &size)
std::span< uint8 > const & Value
friend ByteBuffer & operator<<(ByteBuffer &data, SizeWriter const &size)
friend ByteBuffer & operator>>(ByteBuffer &data, IgnoredReaderWriter const &)
friend ByteBuffer & operator<<(ByteBuffer &data, IgnoredReaderWriter const &)
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)