TrinityCore
PacketUtilities.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 PacketUtilities_h__
19#define PacketUtilities_h__
20
21#include "ByteBuffer.h"
22#include "Duration.h"
23#include "Optional.h"
24#include "Tuples.h"
25#include <short_alloc/short_alloc.h>
26#include <memory>
27#include <string_view>
28#include <ctime>
29
30namespace WorldPackets
31{
33 {
34 public:
35 InvalidStringValueException(std::string_view value);
36
37 std::string const& GetInvalidValue() const { return _value; }
38
39 private:
40 std::string _value;
41 };
42
44 {
45 public:
46 InvalidUtf8ValueException(std::string_view value);
47 };
48
50 {
51 public:
52 InvalidHyperlinkException(std::string_view value);
53 };
54
56 {
57 public:
58 IllegalHyperlinkException(std::string_view value);
59 };
60
61 namespace Strings
62 {
63 struct RawBytes { static bool Validate(std::string_view /*value*/) { return true; } };
64 template<std::size_t MaxBytesWithoutNullTerminator>
65 struct ByteSize { static bool Validate(std::string_view value) { return value.size() <= MaxBytesWithoutNullTerminator; } };
66 struct Utf8 { static bool Validate(std::string_view value); };
67 struct Hyperlinks { static bool Validate(std::string_view value); };
68 struct NoHyperlinks { static bool Validate(std::string_view value); };
69 }
70
74 template<std::size_t MaxBytesWithoutNullTerminator, typename... Validators>
75 class String
76 {
77 using ValidatorList = std::conditional_t<!Trinity::has_type<Strings::RawBytes, std::tuple<Validators...>>::value,
78 std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Strings::Utf8, Validators...>,
79 std::tuple<Strings::ByteSize<MaxBytesWithoutNullTerminator>, Validators...>>;
80
81 public:
82 bool empty() const { return _storage.empty(); }
83 std::size_t length() const { return _storage.length(); }
84 char const* c_str() const { return _storage.c_str(); }
85
86 operator std::string_view() const { return _storage; }
87 operator std::string&() { return _storage; }
88 operator std::string const&() const { return _storage; }
89
90 std::string&& Move() { return std::move(_storage); }
91
92 friend ByteBuffer& operator>>(ByteBuffer& data, String& value)
93 {
94 value = data.ReadCString(false);
95 return data;
96 }
97
98 String& operator=(std::string const& value)
99 {
100 Validate(value);
101 _storage = value;
102 return *this;
103 }
104
105 String& operator=(std::string&& value)
106 {
107 Validate(value);
108 _storage = std::move(value);
109 return *this;
110 }
111
112 String& operator=(std::string_view value)
113 {
114 Validate(value);
115 _storage = std::move(value);
116 return *this;
117 }
118
119 String& operator=(char const* value)
120 {
121 return *this = std::string_view(value);
122 }
123
124 private:
125 static bool Validate(std::string_view value)
126 {
127 return ValidateNth(value, std::make_index_sequence<std::tuple_size_v<ValidatorList>>{});
128 }
129
130 template<std::size_t... indexes>
131 static bool ValidateNth(std::string_view value, std::index_sequence<indexes...>)
132 {
133 return (std::tuple_element_t<indexes, ValidatorList>::Validate(value) && ...);
134 }
135
136 std::string _storage;
137 };
138
140 {
141 public:
142 PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit);
143 };
144
148 template<typename T, std::size_t N>
149 class Array
150 {
151 public:
152 using allocator_type = short_alloc::short_alloc<T, (N * sizeof(T) + (alignof(std::max_align_t) - 1)) & ~(alignof(std::max_align_t) - 1)>;
153 using arena_type = typename allocator_type::arena_type;
154
155 using storage_type = std::vector<T, allocator_type>;
156
157 using max_capacity = std::integral_constant<std::size_t, N>;
158
159 using value_type = typename storage_type::value_type;
160 using size_type = typename storage_type::size_type;
161 using pointer = typename storage_type::pointer;
162 using const_pointer = typename storage_type::const_pointer;
163 using reference = typename storage_type::reference;
164 using const_reference = typename storage_type::const_reference;
165 using iterator = typename storage_type::iterator;
166 using const_iterator = typename storage_type::const_iterator;
167
169
170 Array(Array const& other) : Array()
171 {
172 for (T const& element : other)
173 _storage.push_back(element);
174 }
175
176 Array(Array&& other) noexcept = delete;
177
178 Array& operator=(Array const& other)
179 {
180 if (this == &other)
181 return *this;
182
183 _storage.clear();
184 for (T const& element : other)
185 _storage.push_back(element);
186
187 return *this;
188 }
189
190 Array& operator=(Array&& other) noexcept = delete;
191
192 iterator begin() { return _storage.begin(); }
193 const_iterator begin() const { return _storage.begin(); }
194
195 iterator end() { return _storage.end(); }
196 const_iterator end() const { return _storage.end(); }
197
198 pointer data() { return _storage.data(); }
199 const_pointer data() const { return _storage.data(); }
200
201 size_type size() const { return _storage.size(); }
202 bool empty() const { return _storage.empty(); }
203
206
207 void resize(size_type newSize)
208 {
209 if (newSize > max_capacity::value)
210 throw PacketArrayMaxCapacityException(newSize, max_capacity::value);
211
212 _storage.resize(newSize);
213 }
214
215 void push_back(value_type const& value)
216 {
217 if (_storage.size() >= max_capacity::value)
218 throw PacketArrayMaxCapacityException(_storage.size() + 1, max_capacity::value);
219
220 _storage.push_back(value);
221 }
222
223 void push_back(value_type&& value)
224 {
225 if (_storage.size() >= max_capacity::value)
226 throw PacketArrayMaxCapacityException(_storage.size() + 1, max_capacity::value);
227
228 _storage.push_back(std::forward<value_type>(value));
229 }
230
231 template<typename... Args>
232 T& emplace_back(Args&&... args)
233 {
234 _storage.emplace_back(std::forward<Args>(args)...);
235 return _storage.back();
236 }
237
239 {
240 return _storage.erase(first, last);
241 }
242
243 void clear()
244 {
245 _storage.clear();
246 }
247
248 private:
251 };
252
253 template<typename Underlying = int64>
255 {
256 public:
257 Timestamp() = default;
258 Timestamp(time_t value) : _value(value) { }
259 Timestamp(SystemTimePoint const& systemTime) : _value(std::chrono::system_clock::to_time_t(systemTime)) { }
260
261 Timestamp& operator=(time_t value)
262 {
263 _value = value;
264 return *this;
265 }
266
268 {
269 _value = std::chrono::system_clock::to_time_t(systemTime);
270 return *this;
271 }
272
273 operator time_t() const
274 {
275 return _value;
276 }
277
278 Underlying AsUnderlyingType() const
279 {
280 return static_cast<Underlying>(_value);
281 }
282
283 friend ByteBuffer& operator<<(ByteBuffer& data, Timestamp timestamp)
284 {
285 data << static_cast<Underlying>(timestamp._value);
286 return data;
287 }
288
289 friend ByteBuffer& operator>>(ByteBuffer& data, Timestamp& timestamp)
290 {
291 timestamp._value = static_cast<time_t>(data.read<Underlying>());
292 return data;
293 }
294
295 private:
296 time_t _value = time_t(0);
297 };
298
299 template<typename ChronoDuration, typename Underlying = int64>
301 {
302 public:
303 Duration() = default;
304 Duration(ChronoDuration value) : _value(value) { }
305
306 Duration& operator=(ChronoDuration value)
307 {
308 _value = value;
309 return *this;
310 }
311
312 operator ChronoDuration() const
313 {
314 return _value;
315 }
316
317 friend ByteBuffer& operator<<(ByteBuffer& data, Duration duration)
318 {
319 data << static_cast<Underlying>(duration._value.count());
320 return data;
321 }
322
323 friend ByteBuffer& operator>>(ByteBuffer& data, Duration& duration)
324 {
325 duration._value = ChronoDuration(data.read<Underlying>());
326 return data;
327 }
328
329 private:
330 ChronoDuration _value = ChronoDuration::zero();
331 };
332
333 template<typename Underlying, typename T>
334 struct AsWriter
335 {
336 T const& Value;
337
338 friend inline ByteBuffer& operator<<(ByteBuffer& data, AsWriter const& opt)
339 {
340 data << Underlying(opt.Value);
341 return data;
342 }
343 };
344
345 template<typename Underlying, typename T>
346 struct AsReaderWriter : AsWriter<Underlying, T>
347 {
348 friend inline ByteBuffer& operator>>(ByteBuffer& data, AsReaderWriter const& opt)
349 {
350 Underlying temp;
351 data >> temp;
352 const_cast<T&>(opt.Value) = static_cast<T>(temp);
353 return data;
354 }
355 };
356
357 template<typename Underlying, typename T>
358 inline AsWriter<Underlying, T> As(T const& value) { return { value }; }
359
360 template<typename Underlying, typename T>
361 inline AsReaderWriter<Underlying, T> As(T& value) { return { value }; }
362
363 template<typename T>
365 {
367
368 friend inline ByteBuffer& operator<<(ByteBuffer& data, OptionalInitWriter const& opt)
369 {
370 data.WriteBit(opt.Opt.has_value());
371 return data;
372 }
373 };
374
375 template<typename T>
377 {
379 {
380 if (data.ReadBit())
381 const_cast<Optional<T>&>(opt.Opt).emplace();
382 return data;
383 }
384 };
385
386 template<typename T>
387 inline OptionalInitWriter<T> OptionalInit(Optional<T> const& value) { return { value }; }
388
389 template<typename T>
390 inline OptionalInitReaderWriter<T> OptionalInit(Optional<T>& value) { return { value }; }
391
392 template<typename T>
394 {
395 std::unique_ptr<T> const& Ptr;
396
397 friend inline ByteBuffer& operator<<(ByteBuffer& data, PtrInitWriter const& opt)
398 {
399 data.WriteBit(opt.Ptr != nullptr);
400 return data;
401 }
402 };
403
404 template<typename T>
406 {
407 friend inline ByteBuffer& operator>>(ByteBuffer& data, PtrInitReaderWriter const& opt)
408 {
409 if (data.ReadBit())
410 const_cast<std::unique_ptr<T>&>(opt.Ptr) = std::make_unique<T>();
411 return data;
412 }
413 };
414
415 template<typename T>
416 inline PtrInitWriter<T> OptionalInit(std::unique_ptr<T> const& value) { return { value }; }
417
418 template<typename T>
419 inline PtrInitReaderWriter<T> OptionalInit(std::unique_ptr<T>& value) { return { value }; }
420
421 template<uint32 BitCount, typename T>
423 {
424 T const& Value;
425
426 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsWriter const& bits)
427 {
428 data.WriteBits(static_cast<uint32>(bits.Value), BitCount);
429 return data;
430 }
431 };
432
433 template<uint32 BitCount, typename T>
434 struct BitsReaderWriter : BitsWriter<BitCount, T>
435 {
436 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsReaderWriter const& bits)
437 {
438 const_cast<T&>(bits.Value) = static_cast<T>(data.ReadBits(BitCount));
439 return data;
440 }
441 };
442
443 template<uint32 BitCount, typename T>
444 inline BitsWriter<BitCount, T> Bits(T const& value) { return { value }; }
445
446 template<uint32 BitCount, typename T>
447 inline BitsReaderWriter<BitCount, T> Bits(T& value) { return { value }; }
448
449 template<uint32 BitCount, typename Container>
451 {
452 Container const& Value;
453
454 friend inline ByteBuffer& operator<<(ByteBuffer& data, BitsSizeWriter const& bits)
455 {
456 data.WriteBits(static_cast<uint32>(bits.Value.size()), BitCount);
457 return data;
458 }
459 };
460
461 template<uint32 BitCount, typename Container>
462 struct BitsSizeReaderWriter : BitsSizeWriter<BitCount, Container>
463 {
464 friend inline ByteBuffer& operator>>(ByteBuffer& data, BitsSizeReaderWriter const& bits)
465 {
466 const_cast<Container&>(bits.Value).resize(data.ReadBits(BitCount));
467 return data;
468 }
469 };
470
471 template<uint32 BitCount, typename Container>
472 inline BitsSizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
473
474 template<uint32 BitCount, typename Container>
475 inline BitsSizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
476
477 namespace SizedString
478 {
479 template<uint32 BitCount, typename Container>
480 inline BitsSizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
481
482 template<uint32 BitCount, typename Container>
483 inline BitsSizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
484
485 template<typename Container>
487 {
488 Container const& Value;
489
490 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizedStringWriter const& string)
491 {
492 data.WriteString(string.Value);
493 return data;
494 }
495 };
496
497 template<typename Container>
499 {
500 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizedStringReaderWriter const& string)
501 {
502 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length());
503 return data;
504 }
505 };
506
507 template<typename Container>
508 inline SizedStringWriter<Container> Data(Container const& value) { return { value }; }
509
510 template<typename Container>
511 inline SizedStringReaderWriter<Container> Data(Container& value) { return { value }; }
512 }
513
514 // SizedCString (sends size + string + null terminator but only if not empty)
515 namespace SizedCString
516 {
517 template<uint32 BitCount, typename Container>
519 {
520 Container const& Value;
521
522 friend inline ByteBuffer& operator<<(ByteBuffer& data, SizeWriter const& bits)
523 {
524 data.WriteBits(static_cast<uint32>(bits.Value.length() + 1), BitCount);
525 return data;
526 }
527 };
528
529 template<uint32 BitCount, typename Container>
530 struct SizeReaderWriter : SizeWriter<BitCount, Container>
531 {
532 friend inline ByteBuffer& operator>>(ByteBuffer& data, SizeReaderWriter const& bits)
533 {
534 if (uint32 bytesIncludingNullTerminator = data.ReadBits(BitCount); bytesIncludingNullTerminator > 1)
535 const_cast<Container&>(bits.Value).resize(bytesIncludingNullTerminator - 1);
536 return data;
537 }
538 };
539
540 template<uint32 BitCount, typename Container>
541 inline SizeWriter<BitCount, Container> BitsSize(Container const& value) { return { value }; }
542
543 template<uint32 BitCount, typename Container>
544 inline SizeReaderWriter<BitCount, Container> BitsSize(Container& value) { return { value }; }
545
546 template<typename Container>
548 {
549 Container const& Value;
550
551 friend inline ByteBuffer& operator<<(ByteBuffer& data, DataWriter const& string)
552 {
553 if (!string.Value.empty())
554 data << string.Value;
555 return data;
556 }
557 };
558
559 template<typename Container>
560 struct DataReaderWriter : DataWriter<Container>
561 {
562 friend inline ByteBuffer& operator>>(ByteBuffer& data, DataReaderWriter const& string)
563 {
564 const_cast<Container&>(string.Value) = data.ReadString(string.Value.length());
565 data.read_skip<char>(); // null terminator
566 return data;
567 }
568 };
569
570 template<typename Container>
571 inline DataWriter<Container> Data(Container const& value) { return { value }; }
572
573 template<typename Container>
574 inline DataReaderWriter<Container> Data(Container& value) { return { value }; }
575 };
576}
577
578#endif // PacketUtilities_h__
uint32_t uint32
Definition: Define.h:142
std::chrono::system_clock::time_point SystemTimePoint
Definition: Duration.h:37
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
uint32 ReadBits(int32 bits)
Definition: ByteBuffer.h:236
void read_skip()
Definition: ByteBuffer.h:457
void WriteString(std::string const &str)
Definition: ByteBuffer.h:530
std::string_view ReadCString(bool requireValidUtf8=true)
Definition: ByteBuffer.cpp:58
bool WriteBit(bool bit)
Definition: ByteBuffer.h:169
std::string_view ReadString(uint32 length, bool requireValidUtf8=true)
Definition: ByteBuffer.cpp:78
bool ReadBit()
Definition: ByteBuffer.h:185
void WriteBits(uint64 value, int32 bits)
Definition: ByteBuffer.h:197
typename storage_type::iterator iterator
short_alloc::short_alloc< T,(N *sizeof(T)+(alignof(std::max_align_t) - 1)) &~(alignof(std::max_align_t) - 1)> allocator_type
const_pointer data() const
iterator erase(const_iterator first, const_iterator last)
T & emplace_back(Args &&... args)
Array & operator=(Array &&other) noexcept=delete
std::vector< T, allocator_type > storage_type
typename storage_type::const_pointer const_pointer
typename storage_type::const_reference const_reference
void push_back(value_type const &value)
const_iterator end() const
typename storage_type::reference reference
typename storage_type::size_type size_type
Array & operator=(Array const &other)
typename storage_type::value_type value_type
const_reference operator[](size_type i) const
void push_back(value_type &&value)
Array(Array &&other) noexcept=delete
typename storage_type::const_iterator const_iterator
size_type size() const
typename storage_type::pointer pointer
std::integral_constant< std::size_t, N > max_capacity
typename allocator_type::arena_type arena_type
reference operator[](size_type i)
const_iterator begin() const
void resize(size_type newSize)
Array(Array const &other)
Duration & operator=(ChronoDuration value)
friend ByteBuffer & operator>>(ByteBuffer &data, Duration &duration)
Duration(ChronoDuration value)
friend ByteBuffer & operator<<(ByteBuffer &data, Duration duration)
IllegalHyperlinkException(std::string_view value)
InvalidHyperlinkException(std::string_view value)
InvalidStringValueException(std::string_view value)
std::string const & GetInvalidValue() const
InvalidUtf8ValueException(std::string_view value)
PacketArrayMaxCapacityException(std::size_t requestedSize, std::size_t sizeLimit)
char const * c_str() const
static bool Validate(std::string_view value)
std::conditional_t<!Trinity::has_type< Strings::RawBytes, std::tuple< Validators... > >::value, std::tuple< Strings::ByteSize< MaxBytesWithoutNullTerminator >, Strings::Utf8, Validators... >, std::tuple< Strings::ByteSize< MaxBytesWithoutNullTerminator >, Validators... > > ValidatorList
String & operator=(std::string const &value)
String & operator=(std::string_view value)
std::size_t length() const
String & operator=(std::string &&value)
static bool ValidateNth(std::string_view value, std::index_sequence< indexes... >)
friend ByteBuffer & operator>>(ByteBuffer &data, String &value)
std::string && Move()
String & operator=(char const *value)
Underlying AsUnderlyingType() const
Timestamp & operator=(time_t value)
friend ByteBuffer & operator<<(ByteBuffer &data, Timestamp timestamp)
Timestamp & operator=(SystemTimePoint const &systemTime)
friend ByteBuffer & operator>>(ByteBuffer &data, Timestamp &timestamp)
Timestamp(SystemTimePoint const &systemTime)
DataWriter< Container > Data(Container const &value)
SizeWriter< BitCount, Container > BitsSize(Container const &value)
SizedStringWriter< Container > Data(Container const &value)
BitsSizeWriter< BitCount, Container > BitsSize(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)
STL namespace.
friend ByteBuffer & operator>>(ByteBuffer &data, AsReaderWriter const &opt)
friend ByteBuffer & operator<<(ByteBuffer &data, AsWriter const &opt)
friend ByteBuffer & operator>>(ByteBuffer &data, BitsReaderWriter const &bits)
friend ByteBuffer & operator>>(ByteBuffer &data, BitsSizeReaderWriter const &bits)
friend ByteBuffer & operator<<(ByteBuffer &data, BitsSizeWriter const &bits)
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, DataReaderWriter const &string)
friend ByteBuffer & operator<<(ByteBuffer &data, DataWriter const &string)
friend ByteBuffer & operator>>(ByteBuffer &data, SizeReaderWriter const &bits)
friend ByteBuffer & operator<<(ByteBuffer &data, SizeWriter const &bits)
friend ByteBuffer & operator>>(ByteBuffer &data, SizedStringReaderWriter const &string)
friend ByteBuffer & operator<<(ByteBuffer &data, SizedStringWriter const &string)
static bool Validate(std::string_view value)
static bool Validate(std::string_view)
static bool Validate(std::string_view value)