#pragma once #ifndef MESSMER_CPPUTILS_DATA_DESERIALIZER_H #define MESSMER_CPPUTILS_DATA_DESERIALIZER_H #include "Data.h" #include "../macros.h" #include "../assert/assert.h" namespace cpputils { class Deserializer final { public: Deserializer(const Data *source); uint8_t readUint8(); int8_t readInt8(); uint16_t readUint16(); int16_t readInt16(); uint32_t readUint32(); int32_t readInt32(); uint64_t readUint64(); int64_t readInt64(); Data readData(); std::string readString(); void finished(); private: template DataType _read(); size_t _pos; const Data *_source; DISALLOW_COPY_AND_ASSIGN(Deserializer); }; inline Deserializer::Deserializer(const Data *source): _pos(0), _source(source) { } inline uint8_t Deserializer::readUint8() { return _read(); } inline int8_t Deserializer::readInt8() { return _read(); } inline uint16_t Deserializer::readUint16() { return _read(); } inline int16_t Deserializer::readInt16() { return _read(); } inline uint32_t Deserializer::readUint32() { return _read(); } inline int32_t Deserializer::readInt32() { return _read(); } inline uint64_t Deserializer::readUint64() { return _read(); } inline int64_t Deserializer::readInt64() { return _read(); } template inline DataType Deserializer::_read() { static_assert(std::is_pod::value, "Can only deserialize PODs"); if (_pos + sizeof(DataType) > _source->size()) { throw std::runtime_error("Deserialization failed - size overflow"); } DataType result = *reinterpret_cast(_source->dataOffset(_pos)); _pos += sizeof(DataType); return result; } inline Data Deserializer::readData() { uint64_t size = readUint64(); if (_pos + size > _source->size()) { throw std::runtime_error("Deserialization failed - size overflow"); } Data result(size); std::memcpy(static_cast(result.data()), static_cast(_source->dataOffset(_pos)), size); _pos += size; return result; } inline std::string Deserializer::readString() { //TODO Test whether that works when string ends (a) at beginning (b) in middle (c) at end of data region const void *nullbytepos = std::memchr(_source->dataOffset(_pos), '\0', _source->size()-_pos); if (nullbytepos == nullptr) { throw std::runtime_error("Deserialization failed - missing nullbyte for string termination"); } uint64_t size = static_cast(nullbytepos) - static_cast(_source->dataOffset(_pos)); std::string result(reinterpret_cast(_source->dataOffset(_pos)), size); _pos += size + 1; return result; } inline void Deserializer::finished() { if (_pos != _source->size()) { throw std::runtime_error("Deserialization failed - size not fully used."); } } } #endif