#pragma once #ifndef MESSMER_CPPUTILS_DATA_DESERIALIZER_H #define MESSMER_CPPUTILS_DATA_DESERIALIZER_H #include "Data.h" #include "../macros.h" #include "../assert/assert.h" #include "FixedSizeData.h" #include "SerializationHelper.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(); std::string readString(); Data readData(); template FixedSizeData readFixedSizeData(); Data readTailData(); void finished(); private: template DataType _read(); Data _readData(size_t size); void _readData(void *target, size_t size); 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 = deserialize(_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"); } return _readData(size); } inline Data Deserializer::readTailData() { uint64_t size = _source->size() - _pos; return _readData(size); } inline Data Deserializer::_readData(size_t size) { Data result(size); _readData(result.data(), size); return result; } inline void Deserializer::_readData(void *target, size_t size) { std::memcpy(static_cast(target), static_cast(_source->dataOffset(_pos)), size); _pos += size; } template inline FixedSizeData Deserializer::readFixedSizeData() { FixedSizeData result(FixedSizeData::Null()); _readData(result.data(), 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(static_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