#ifndef OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H #define OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H #include #include #include #include #include #include #include namespace Serialization { struct NotEnoughData : std::runtime_error { NotEnoughData() : std::runtime_error("Not enough data") { } }; class BinaryReader { public: explicit BinaryReader(const std::byte* pos, const std::byte* end) : mPos(pos) , mEnd(end) { assert(mPos <= mEnd); } BinaryReader(const BinaryReader&) = delete; template void operator()(Format&& format, T& value) { if constexpr (std::is_enum_v) (*this)(std::forward(format), static_cast&>(value)); else if constexpr (std::is_arithmetic_v) { if (mEnd - mPos < static_cast(sizeof(T))) throw NotEnoughData(); std::memcpy(&value, mPos, sizeof(T)); mPos += sizeof(T); value = Misc::toLittleEndian(value); } else if constexpr (std::is_pointer_v) value = reinterpret_cast(mPos); else { format(*this, value); } } template auto operator()(Format&& format, T* data, std::size_t count) { if constexpr (std::is_enum_v) (*this)(std::forward(format), reinterpret_cast*>(data), count); else if constexpr (std::is_arithmetic_v) { const std::size_t size = sizeof(T) * count; if (mEnd - mPos < static_cast(size)) throw NotEnoughData(); std::memcpy(data, mPos, size); mPos += size; if constexpr (!Misc::IS_LITTLE_ENDIAN) std::for_each(data, data + count, [&](T& v) { v = Misc::fromLittleEndian(v); }); } else { format(*this, data, count); } } private: const std::byte* mPos; const std::byte* const mEnd; }; } #endif