mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-30 17:56:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			79 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			79 lines
		
	
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H
 | |
| #define OPENMW_COMPONENTS_SERIALIZATION_BINARYREADER_H
 | |
| 
 | |
| #include <components/misc/endianness.hpp>
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <cassert>
 | |
| #include <cstddef>
 | |
| #include <cstring>
 | |
| #include <stdexcept>
 | |
| #include <type_traits>
 | |
| 
 | |
| 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 <class Format, class T>
 | |
|         void operator()(Format&& format, T& value)
 | |
|         {
 | |
|             if constexpr (std::is_enum_v<T>)
 | |
|                 (*this)(std::forward<Format>(format), static_cast<std::underlying_type_t<T>&>(value));
 | |
|             else if constexpr (std::is_arithmetic_v<T>)
 | |
|             {
 | |
|                 if (mEnd - mPos < static_cast<std::ptrdiff_t>(sizeof(T)))
 | |
|                     throw NotEnoughData();
 | |
|                 std::memcpy(&value, mPos, sizeof(T));
 | |
|                 mPos += sizeof(T);
 | |
|                 value = Misc::toLittleEndian(value);
 | |
|             }
 | |
|             else if constexpr (std::is_pointer_v<T>)
 | |
|                 value = reinterpret_cast<T>(mPos);
 | |
|             else
 | |
|             {
 | |
|                 format(*this, value);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template <class Format, class T>
 | |
|         auto operator()(Format&& format, T* data, std::size_t count)
 | |
|         {
 | |
|             if constexpr (std::is_enum_v<T>)
 | |
|                 (*this)(std::forward<Format>(format), reinterpret_cast<std::underlying_type_t<T>*>(data), count);
 | |
|             else if constexpr (std::is_arithmetic_v<T>)
 | |
|             {
 | |
|                 const std::size_t size = sizeof(T) * count;
 | |
|                 if (mEnd - mPos < static_cast<std::ptrdiff_t>(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
 |