#pragma once #include "endian.hpp" #include "types.hpp" #include "../utils.hpp" #include #include #include namespace sibs { class DeserializeException : public std::runtime_error { public: DeserializeException(const std::string &errMsg) : std::runtime_error(errMsg) {} }; /** * Endian independent deserializer */ class SafeDeserializer { public: SafeDeserializer(const u8 *_data, usize _size) : data(_data), size(_size) { } /* * Throws DeserializeException on failure */ template T extract() { constexpr usize typeSize = sizeof(T); verifyExtractSize(typeSize); size -= typeSize; T result; memmove(&result, data, typeSize); #if BYTE_ORDER == BIG_ENDIAN std::reverse((char*)&result, (char*)&result + typeSize); #endif data += typeSize; return result; } /* * Throws DeserializeException on failure */ void extract(u8 *destination, usize destinationSize) { if(destinationSize > 0) { verifyExtractSize(destinationSize); size -= destinationSize; memmove(destination, data, destinationSize); data += destinationSize; } } bool empty() const { return size == 0; } const u8* getBuffer() { return data; } usize getSize() const { return size; } void skip(usize bytesToSkip) { bytesToSkip = bytesToSkip < size ? bytesToSkip : size; size -= bytesToSkip; data += bytesToSkip; } private: void verifyExtractSize(usize typeSize) const { if(typeSize > size) { std::string errMsg = "Unable to extract "; errMsg += std::to_string(typeSize); errMsg += " bytes, only "; errMsg += std::to_string(size); errMsg += " bytes left in buffer"; throw DeserializeException(errMsg); } } private: const u8 *data; usize size; }; }