Botcraft 1.21.4
Loading...
Searching...
No Matches
BinaryReadWrite.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <algorithm>
6#include <array>
7#include <cstring>
8#include <functional>
9#include <stdexcept>
10#include <string>
11#include <type_traits>
12
13namespace ProtocolCraft
14{
15 class NetworkType;
16
17 using ReadIterator = std::vector<unsigned char>::const_iterator;
18 using WriteContainer = std::vector<unsigned char>;
19
20 using UUID = std::array<unsigned char, 16>;
21
24
25 std::string ReadRawString(ReadIterator& iter, size_t& length, const size_t size);
26 void WriteRawString(const std::string& s, WriteContainer& container);
27
28 std::vector<unsigned char> ReadByteArray(ReadIterator& iter, size_t& length, const size_t desired_length);
29 void WriteByteArray(const std::vector<unsigned char>& my_array, WriteContainer& container);
30 void WriteByteArray(const unsigned char* data, const size_t length, WriteContainer& container);
31
32 namespace Internal
33 {
34 template <typename T>
35 T ChangeEndianness(const T& in)
36 {
37 T out;
38 std::reverse_copy(
39 reinterpret_cast<const unsigned char*>(&in),
40 reinterpret_cast<const unsigned char*>(&in) + sizeof(T),
41 reinterpret_cast<unsigned char*>(&out)
42 );
43 return out;
44 }
45 }
46
47 template<typename StorageType, typename SerializationType>
48 StorageType ReadData(ReadIterator& iter, size_t& length
49#ifdef PROTOCOLCRAFT_DETAILED_PARSING
50 ,
51 typename Internal::OffsetType<StorageType>::type* start_offset = nullptr,
52 typename Internal::OffsetType<StorageType>::type* end_offset = nullptr
53#endif
54 )
55 {
56 // bool, char, short, int, long, float, double ...
57 if constexpr (std::is_arithmetic_v<SerializationType>)
58 {
59 if (length < sizeof(SerializationType))
60 {
61 throw std::runtime_error("Not enough input in ReadData");
62 }
63#ifdef PROTOCOLCRAFT_DETAILED_PARSING
64 if (start_offset != nullptr)
65 {
66 *start_offset = length;
67 }
68#endif
69 SerializationType output;
70 std::memcpy(&output, &(*iter), sizeof(SerializationType));
71 length -= sizeof(SerializationType);
72 iter += sizeof(SerializationType);
73#ifdef PROTOCOLCRAFT_DETAILED_PARSING
74 if (end_offset != nullptr)
75 {
76 *end_offset = length;
77 }
78#endif
79 // Don't need to change endianess of single byte
80 if constexpr (sizeof(SerializationType) > 1)
81 {
82 // The compiler should(?) optimize that
83 // This check doesn't work if int and char
84 // have the same size, but I guess this is not
85 // the only thing that souldn't work in this case
86 constexpr int num = 1;
87 if (*(char*)&num == 1)
88 {
89 // Little endian --> change endianess
90 return static_cast<StorageType>(Internal::ChangeEndianness(output));
91 }
92 }
93
94 // Big endian or sizeof(1) --> endianess is good
95 return static_cast<StorageType>(output);
96 }
97 // VarType
98 else if constexpr (Internal::IsVarType<SerializationType>)
99 {
100#ifdef PROTOCOLCRAFT_DETAILED_PARSING
101 if (start_offset != nullptr)
102 {
103 *start_offset = length;
104 }
105#endif
106 size_t num_read = 0;
107 typename SerializationType::underlying_type result = 0;
108
109 unsigned char read;
110
111 do
112 {
113 if (num_read >= length)
114 {
115 throw std::runtime_error("Not enough input in ReadData<VarType>");
116 }
117 if (num_read * 7 > sizeof(typename SerializationType::underlying_type) * 8)
118 {
119 throw std::runtime_error("VarType is too big in ReadData<VarType>");
120 }
121
122 read = *(iter + num_read);
123
124 typename SerializationType::underlying_type value = static_cast<typename SerializationType::underlying_type>(read & 127);//0b01111111
125 result |= (value << (7 * num_read));
126
127 num_read++;
128 } while ((read & 128) != 0);//0b10000000
129
130 iter += num_read;
131 length -= num_read;
132#ifdef PROTOCOLCRAFT_DETAILED_PARSING
133 if (end_offset != nullptr)
134 {
135 *end_offset = length;
136 }
137#endif
138
139 return static_cast<StorageType>(result);
140 }
141 // std::string
142 else if constexpr (std::is_same_v<SerializationType, std::string> && std::is_same_v<StorageType, std::string>)
143 {
144#ifdef PROTOCOLCRAFT_DETAILED_PARSING
145 if (start_offset != nullptr)
146 {
147 *start_offset = length;
148 }
149#endif
150 const size_t size = ReadData<size_t, VarInt>(iter, length);
151 if (length < size)
152 {
153 throw std::runtime_error("Not enough input in ReadData<std::string>");
154 }
155
156 iter += size;
157 length -= size;
158#ifdef PROTOCOLCRAFT_DETAILED_PARSING
159 if (end_offset != nullptr)
160 {
161 *end_offset = length;
162 }
163#endif
164
165 return std::string(iter - size, iter);
166 }
167 // NetworkType
168 else if constexpr (std::is_base_of_v<NetworkType, SerializationType> && std::is_base_of_v<NetworkType, StorageType>)
169 {
170#ifdef PROTOCOLCRAFT_DETAILED_PARSING
171 if (start_offset != nullptr)
172 {
173 *start_offset = length;
174 }
175#endif
176 SerializationType output;
177 output.Read(iter, length);
178#ifdef PROTOCOLCRAFT_DETAILED_PARSING
179 if (end_offset != nullptr)
180 {
181 *end_offset = length;
182 }
183#endif
184 // static_cast required for example to convert between NBT::Value and NBT::UnnamedValue
185 return static_cast<StorageType>(output);
186 }
187 // std::vector // std::array
188 else if constexpr (
189 Internal::IsVector<SerializationType> ||
190 Internal::IsArray<SerializationType> ||
191 Internal::IsGenericVector<SerializationType>)
192 {
193 size_t N;
194 StorageType output{};
195#ifdef PROTOCOLCRAFT_DETAILED_PARSING
196 if (start_offset != nullptr)
197 {
198 start_offset->first = length;
199 }
200#endif
201 // std::vector
202 if constexpr (Internal::IsVector<SerializationType>)
203 {
204 static_assert(Internal::IsVector<StorageType>, "StorageType should be a std::vector");
205 N = ReadData<size_t, VarInt>(iter, length);
206 output.resize(N);
207#ifdef PROTOCOLCRAFT_DETAILED_PARSING
208 if (start_offset != nullptr)
209 {
210 start_offset->second.resize(N);
211 }
212 if (end_offset != nullptr)
213 {
214 end_offset->second.resize(N);
215 }
216#endif
217 }
218 // std::array
219 else if constexpr (Internal::IsArray<SerializationType>)
220 {
221 static_assert(Internal::IsArray<StorageType>, "StorageType should be a std::array");
222 N = std::size(output);
223 }
224 // Internal::Vector
225 else
226 {
227 // std::array but expressed with GenericVector
228 if constexpr (SerializationType::size > 0)
229 {
230 static_assert(Internal::IsArray<StorageType>, "StorageType should be a std::array");
231 N = SerializationType::size;
232 }
233 // Special case, "all remaining data"
234 else if constexpr (std::is_same_v<typename SerializationType::size_type, void>)
235 {
236 static_assert(std::is_same_v<StorageType, std::vector<unsigned char>>, "Only std::vector<unsigned char> is supported for \"all remaining data\"");
237 N = length;
238 output.resize(N);
239#ifdef PROTOCOLCRAFT_DETAILED_PARSING
240 if (start_offset != nullptr)
241 {
242 start_offset->second.resize(N);
243 }
244 if (end_offset != nullptr)
245 {
246 end_offset->second.resize(N);
247 }
248#endif
249 }
250 // Generic case for vector prefixed with size
251 else
252 {
253 static_assert(Internal::IsVector<StorageType>, "StorageType should be a std::vector");
254 N = ReadData<size_t, typename SerializationType::size_type>(iter, length);
255 output.resize(N);
256#ifdef PROTOCOLCRAFT_DETAILED_PARSING
257 if (start_offset != nullptr)
258 {
259 start_offset->second.resize(N);
260 }
261 if (end_offset != nullptr)
262 {
263 end_offset->second.resize(N);
264 }
265#endif
266 }
267 }
268
269 // If we need to read char/unsigned char, just memcpy it
270 if constexpr (sizeof(typename SerializationType::value_type) == 1 &&
271 !std::is_same_v<typename SerializationType::value_type, bool> &&
272 std::is_same_v<typename SerializationType::value_type, typename StorageType::value_type> &&
273 !std::is_base_of_v<NetworkType, typename SerializationType::value_type>)
274 {
275 if (length < N)
276 {
277 throw std::runtime_error("Not enough input to read vector data");
278 }
279#ifdef PROTOCOLCRAFT_DETAILED_PARSING
280 for (size_t i = 0; i < N; ++i)
281 {
282 if (start_offset != nullptr)
283 {
284 start_offset->second[i] = length - i;
285 }
286 if (end_offset != nullptr)
287 {
288 end_offset->second[i] = length - i + 1;
289 }
290 }
291#endif
292 std::memcpy(output.data(), &(*iter), N);
293 length -= N;
294 iter += N;
295 }
296 // else read the elements one by one
297 else
298 {
299 for (size_t i = 0; i < N; ++i)
300 {
301 output[i] = ReadData<typename StorageType::value_type, typename SerializationType::value_type>(iter, length
302#ifdef PROTOCOLCRAFT_DETAILED_PARSING
303 ,
304 start_offset != nullptr ? &start_offset->second[i] : nullptr,
305 end_offset != nullptr ? &end_offset->second[i] : nullptr
306#endif
307 );
308 }
309 }
310#ifdef PROTOCOLCRAFT_DETAILED_PARSING
311 if (end_offset != nullptr)
312 {
313 end_offset->first = length;
314 }
315#endif
316 return output;
317 }
318 // std::optional
319 else if constexpr (Internal::IsOptional<StorageType> && Internal::IsOptional<SerializationType>)
320 {
321 StorageType output;
322
323 const bool has_value = ReadData<bool, bool>(iter, length);
324 if (has_value)
325 {
326 output = ReadData<typename StorageType::value_type, typename SerializationType::value_type>(iter, length
327#ifdef PROTOCOLCRAFT_DETAILED_PARSING
328 ,
329 start_offset,
330 end_offset
331#endif
332 );
333 }
334
335 return output;
336 }
337 // std::pair
338 else if constexpr (Internal::IsPair<StorageType> && Internal::IsPair<SerializationType>)
339 {
340 StorageType output;
341
342#ifdef PROTOCOLCRAFT_DETAILED_PARSING
343 if (start_offset != nullptr)
344 {
345 start_offset->first = length;
346 }
347#endif
348 output.first = ReadData<typename StorageType::first_type, typename SerializationType::first_type>(iter, length
349#ifdef PROTOCOLCRAFT_DETAILED_PARSING
350 ,
351 start_offset != nullptr ? &start_offset->second.first : nullptr,
352 end_offset != nullptr ? &end_offset->second.first : nullptr
353#endif
354 );
355 output.second = ReadData<typename StorageType::second_type, typename SerializationType::second_type>(iter, length
356#ifdef PROTOCOLCRAFT_DETAILED_PARSING
357 ,
358 start_offset != nullptr ? &start_offset->second.second : nullptr,
359 end_offset != nullptr ? &end_offset->second.second : nullptr
360#endif
361 );
362
363#ifdef PROTOCOLCRAFT_DETAILED_PARSING
364 if (end_offset != nullptr)
365 {
366 end_offset->first = length;
367 }
368#endif
369 return output;
370 }
371 // std::map
372 else if constexpr (Internal::IsMap<StorageType> && Internal::IsMap<SerializationType>)
373 {
374#ifdef PROTOCOLCRAFT_DETAILED_PARSING
375 if (start_offset != nullptr)
376 {
377 start_offset->first = length;
378 }
379#endif
380 const int output_length = ReadData<int, VarInt>(iter, length);
381
382 StorageType output;
383 for (int i = 0; i < output_length; ++i)
384 {
385 const typename StorageType::key_type key = ReadData<typename StorageType::key_type, typename SerializationType::key_type>(iter, length);
386 const typename StorageType::mapped_type val = ReadData<typename StorageType::mapped_type, typename SerializationType::mapped_type>(iter, length
387#ifdef PROTOCOLCRAFT_DETAILED_PARSING
388 ,
389 start_offset != nullptr ? &start_offset->second[key] : nullptr,
390 end_offset != nullptr ? &end_offset->second[key] : nullptr
391#endif
392 );
393 output.insert(std::make_pair(key, val));
394 }
395
396#ifdef PROTOCOLCRAFT_DETAILED_PARSING
397 if (end_offset != nullptr)
398 {
399 end_offset->first = length;
400 }
401#endif
402 return output;
403 }
404 // std::bitset
405 else if constexpr (Internal::IsBitset<StorageType> && std::is_same_v<SerializationType, StorageType>)
406 {
407 StorageType output;
408 const size_t N = output.size();
409#ifdef PROTOCOLCRAFT_DETAILED_PARSING
410 if (start_offset != nullptr)
411 {
412 *start_offset = length;
413 }
414#endif
415 const std::vector<unsigned char> bytes = ReadByteArray(iter, length, N / 8 + (N % 8 != 0));
416 for (size_t i = 0; i < N; ++i)
417 {
418 output.set(i, (bytes[i / 8] >> (i % 8)) & 0x01);
419 }
420#ifdef PROTOCOLCRAFT_DETAILED_PARSING
421 if (end_offset != nullptr)
422 {
423 *end_offset = length;
424 }
425#endif
426
427 return output;
428 }
429 else
430 {
431 static_assert(Internal::dependant_false<SerializationType>, "Types not supported in ReadData");
432 }
433 }
434
435 template<typename T>
437#ifdef PROTOCOLCRAFT_DETAILED_PARSING
438 ,
439 typename Internal::OffsetType<typename Internal::SerializedType<T>::storage_type>::type* start_offset = nullptr,
440 typename Internal::OffsetType<typename Internal::SerializedType<T>::storage_type>::type* end_offset = nullptr
441#endif
442 )
443 {
444 return ReadData<typename Internal::SerializedType<T>::storage_type, typename Internal::SerializedType<T>::serialization_type>(iter, length
445#ifdef PROTOCOLCRAFT_DETAILED_PARSING
446 ,
447 start_offset,
448 end_offset
449#endif
450 );
451 }
452
453 template <typename StorageType, typename SerializationType>
454 void WriteData(typename std::conditional_t<std::is_arithmetic_v<StorageType> || std::is_enum_v<StorageType>, StorageType, const StorageType&> value, WriteContainer& container)
455 {
456 // bool, char, short, int, long, float, double ...
457 if constexpr (std::is_arithmetic_v<SerializationType>)
458 {
459 SerializationType val = static_cast<SerializationType>(value);
460
461 // Don't need to change endianess of single byte
462 if constexpr (sizeof(SerializationType) > 1)
463 {
464 // Little endian check
465 // It doesn't work if int and char
466 // have the same size, but I guess this is not
467 // the only thing that souldn't work in this case
468 constexpr int num = 1;
469 if (*(char*)&num == 1)
470 {
471 // Little endian
473 }
474 }
475
476 // Insert bytes in the container
477 container.insert(
478 container.end(),
479 reinterpret_cast<unsigned char*>(&val),
480 reinterpret_cast<unsigned char*>(&val) + sizeof(SerializationType)
481 );
482 }
483 // VarType
484 else if constexpr (Internal::IsVarType<SerializationType>)
485 {
486 std::make_unsigned_t<typename SerializationType::underlying_type> val = static_cast<std::make_unsigned_t<typename SerializationType::underlying_type>>(value);
487 do {
488 unsigned char temp = static_cast<unsigned char>(val & 127);//0b01111111
489 val >>= 7;
490 if (val != 0)
491 {
492 temp |= 128;//0b10000000
493 }
494 container.push_back(temp);
495 } while (val != 0);
496 }
497 // std::string
498 else if constexpr (std::is_same_v<SerializationType, std::string> && std::is_same_v<StorageType, std::string>)
499 {
500 WriteData<int, VarInt>(static_cast<int>(value.size()), container);
501 container.insert(container.end(), value.begin(), value.end());
502 }
503 // NetworkType
504 else if constexpr (std::is_base_of_v<NetworkType, SerializationType> && std::is_base_of_v<NetworkType, StorageType>)
505 {
506 // static_cast required for example to convert between NBT::Value and NBT::UnnamedValue
507 static_cast<SerializationType>(value).Write(container);
508 }
509 // std::vector // std::array
510 else if constexpr (
511 Internal::IsVector<SerializationType> ||
512 Internal::IsArray<SerializationType> ||
513 Internal::IsGenericVector<SerializationType>)
514 {
515 // std::vector
516 if constexpr (Internal::IsVector<SerializationType>)
517 {
518 static_assert(Internal::IsVector<StorageType>, "StorageType should be a std::vector");
519 WriteData<int, VarInt>(static_cast<int>(value.size()), container);
520 }
521 // std::array
522 else if constexpr (Internal::IsArray<SerializationType>)
523 {
524 static_assert(Internal::IsArray<StorageType>, "StorageType should be a std::array");
525 }
526 // Internal::Vector
527 else
528 {
529 // std::array but expressed with GenericVector
530 if constexpr (SerializationType::size > 0)
531 {
532 static_assert(Internal::IsArray<StorageType>, "StorageType should be a std::array");
533 }
534 // Special case, "all remaining data"
535 else if constexpr (std::is_same_v<typename SerializationType::size_type, void>)
536 {
537 static_assert(std::is_same_v<StorageType, std::vector<unsigned char>>, "Only std::vector<unsigned char> is supported for \"all remaining data\"");
538 }
539 // Generic case for vector prefixed with size
540 else
541 {
542 static_assert(Internal::IsVector<StorageType>, "StorageType should be a std::vector");
543 WriteData<int, typename SerializationType::size_type>(static_cast<int>(value.size()), container);
544 }
545 }
546
547 // If we need to write char/unsigned char, just copy the data
548 if constexpr (sizeof(typename SerializationType::value_type) == 1 &&
549 !std::is_same_v<typename SerializationType::value_type, bool> &&
550 std::is_same_v<typename StorageType::value_type, typename SerializationType::value_type> &&
551 !std::is_base_of_v<NetworkType, typename SerializationType::value_type>)
552 {
553 container.insert(container.end(), value.begin(), value.end());
554 }
555 else
556 {
557 for (const auto& e : value)
558 {
559 WriteData<typename StorageType::value_type, typename SerializationType::value_type>(e, container);
560 }
561 }
562 }
563 // std::optional
564 else if constexpr (Internal::IsOptional<StorageType> && Internal::IsOptional<SerializationType>)
565 {
566 WriteData<bool, bool>(value.has_value(), container);
567 if (value.has_value())
568 {
569 WriteData<typename StorageType::value_type, typename SerializationType::value_type>(value.value(), container);
570 }
571 }
572 // std::pair
573 else if constexpr (Internal::IsPair<StorageType> && Internal::IsPair<SerializationType>)
574 {
575 WriteData<typename StorageType::first_type, typename SerializationType::first_type>(value.first, container);
576 WriteData<typename StorageType::second_type, typename SerializationType::second_type>(value.second, container);
577 }
578 // std::map
579 else if constexpr (Internal::IsMap<StorageType> && Internal::IsMap<SerializationType>)
580 {
581 WriteData<int, VarInt>(static_cast<int>(value.size()), container);
582 for (const auto& p : value)
583 {
584 WriteData<typename StorageType::key_type, typename SerializationType::key_type>(p.first, container);
585 WriteData<typename StorageType::mapped_type, typename SerializationType::mapped_type>(p.second, container);
586 }
587 }
588 // std::bitset
589 else if constexpr (Internal::IsBitset<StorageType> && Internal::IsBitset<SerializationType>)
590 {
591 const size_t N = value.size();
592 std::vector<unsigned char> bytes(N / 8 + (N % 8 != 0), 0);
593 for (size_t i = 0; i < N; ++i)
594 {
595 if (value[i])
596 {
597 bytes[i / 8] |= 1 << (i % 8);
598 }
599 }
600 WriteByteArray(bytes, container);
601 }
602 else
603 {
604 static_assert(Internal::dependant_false<SerializationType>, "Types not supported in WriteData");
605 }
606 }
607
608 template <typename T>
609 void WriteData(std::conditional_t<std::is_arithmetic_v<typename Internal::SerializedType<T>::storage_type> || std::is_enum_v<typename Internal::SerializedType<T>::storage_type>, typename Internal::SerializedType<T>::storage_type, const typename Internal::SerializedType<T>::storage_type&> value, WriteContainer& container)
610 {
611 WriteData<typename Internal::SerializedType<T>::storage_type, typename Internal::SerializedType<T>::serialization_type>(value, container);
612 }
613} // ProtocolCraft
T ChangeEndianness(const T &in)
std::string ReadRawString(ReadIterator &iter, size_t &length, const size_t size)
std::vector< unsigned char > ReadByteArray(ReadIterator &iter, size_t &length, const size_t desired_length)
void WriteData(typename std::conditional_t< std::is_arithmetic_v< StorageType >||std::is_enum_v< StorageType >, StorageType, const StorageType & > value, WriteContainer &container)
std::array< unsigned char, 16 > UUID
void WriteRawString(const std::string &s, WriteContainer &container)
StorageType ReadData(ReadIterator &iter, size_t &length)
std::vector< unsigned char > WriteContainer
std::vector< unsigned char >::const_iterator ReadIterator
void WriteByteArray(const std::vector< unsigned char > &my_array, WriteContainer &container)