mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 15:56:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			205 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /// Functions used to read raw binary data from .nif files
 | |
| 
 | |
| #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
 | |
| #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP
 | |
| 
 | |
| #include <array>
 | |
| #include <cassert>
 | |
| #include <istream>
 | |
| #include <stdexcept>
 | |
| #include <stdint.h>
 | |
| #include <string>
 | |
| #include <type_traits>
 | |
| #include <vector>
 | |
| 
 | |
| #include <components/files/istreamptr.hpp>
 | |
| #include <components/misc/endianness.hpp>
 | |
| #include <components/misc/float16.hpp>
 | |
| 
 | |
| #include <osg/BoundingSphere>
 | |
| #include <osg/Quat>
 | |
| #include <osg/Vec3f>
 | |
| #include <osg/Vec4f>
 | |
| 
 | |
| #include "niftypes.hpp"
 | |
| 
 | |
| namespace ToUTF8
 | |
| {
 | |
|     class StatelessUtf8Encoder;
 | |
| }
 | |
| 
 | |
| namespace Nif
 | |
| {
 | |
| 
 | |
|     class Reader;
 | |
| 
 | |
|     template <std::size_t numInstances, typename T>
 | |
|     inline void readBufferOfType(Files::IStreamPtr& pIStream, T* dest)
 | |
|     {
 | |
|         static_assert(
 | |
|             std::is_arithmetic_v<T> || std::is_same_v<T, Misc::float16_t>, "Buffer element type is not arithmetic");
 | |
|         static_assert(!std::is_same_v<T, bool>, "Buffer element type is boolean");
 | |
|         pIStream->read((char*)dest, numInstances * sizeof(T));
 | |
|         if (pIStream->bad())
 | |
|             throw std::runtime_error("Failed to read typed (" + std::string(typeid(T).name()) + ") buffer of "
 | |
|                 + std::to_string(numInstances) + " instances");
 | |
|         if constexpr (Misc::IS_BIG_ENDIAN)
 | |
|             for (std::size_t i = 0; i < numInstances; i++)
 | |
|                 Misc::swapEndiannessInplace(dest[i]);
 | |
|     }
 | |
| 
 | |
|     template <std::size_t numInstances, typename T>
 | |
|     inline void readBufferOfType(Files::IStreamPtr& pIStream, T (&dest)[numInstances])
 | |
|     {
 | |
|         readBufferOfType<numInstances>(pIStream, static_cast<T*>(dest));
 | |
|     }
 | |
| 
 | |
|     template <typename T>
 | |
|     inline void readDynamicBufferOfType(Files::IStreamPtr& pIStream, T* dest, std::size_t numInstances)
 | |
|     {
 | |
|         static_assert(
 | |
|             std::is_arithmetic_v<T> || std::is_same_v<T, Misc::float16_t>, "Buffer element type is not arithmetic");
 | |
|         static_assert(!std::is_same_v<T, bool>, "Buffer element type is boolean");
 | |
|         pIStream->read((char*)dest, numInstances * sizeof(T));
 | |
|         if (pIStream->bad())
 | |
|             throw std::runtime_error("Failed to read typed (" + std::string(typeid(T).name()) + ") dynamic buffer of "
 | |
|                 + std::to_string(numInstances) + " instances");
 | |
|         if constexpr (Misc::IS_BIG_ENDIAN)
 | |
|             for (std::size_t i = 0; i < numInstances; i++)
 | |
|                 Misc::swapEndiannessInplace(dest[i]);
 | |
|     }
 | |
| 
 | |
|     class NIFStream
 | |
|     {
 | |
|         const Reader& mReader;
 | |
|         Files::IStreamPtr mStream;
 | |
|         const ToUTF8::StatelessUtf8Encoder* mEncoder;
 | |
|         std::string mBuffer;
 | |
| 
 | |
|     public:
 | |
|         explicit NIFStream(
 | |
|             const Reader& reader, Files::IStreamPtr&& stream, const ToUTF8::StatelessUtf8Encoder* encoder)
 | |
|             : mReader(reader)
 | |
|             , mStream(std::move(stream))
 | |
|             , mEncoder(encoder)
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         const Reader& getFile() const { return mReader; }
 | |
| 
 | |
|         unsigned int getVersion() const;
 | |
|         unsigned int getUserVersion() const;
 | |
|         unsigned int getBethVersion() const;
 | |
| 
 | |
|         /// Convert human-readable version numbers into a number that can be compared.
 | |
|         static constexpr uint32_t generateVersion(uint8_t major, uint8_t minor, uint8_t patch, uint8_t rev)
 | |
|         {
 | |
|             return (major << 24) + (minor << 16) + (patch << 8) + rev;
 | |
|         }
 | |
| 
 | |
|         void skip(size_t size) { mStream->ignore(size); }
 | |
| 
 | |
|         /// Read into a single instance of type
 | |
|         template <class T>
 | |
|         void read(T& data)
 | |
|         {
 | |
|             readBufferOfType<1>(mStream, &data);
 | |
|         }
 | |
| 
 | |
|         /// Read multiple instances of type into an array
 | |
|         template <class T, size_t size>
 | |
|         void readArray(std::array<T, size>& arr)
 | |
|         {
 | |
|             readBufferOfType<size>(mStream, arr.data());
 | |
|         }
 | |
| 
 | |
|         /// Read instances of type into a dynamic buffer
 | |
|         template <class T>
 | |
|         void read(T* dest, size_t size)
 | |
|         {
 | |
|             readDynamicBufferOfType<T>(mStream, dest, size);
 | |
|         }
 | |
| 
 | |
|         /// Read multiple instances of type into a vector
 | |
|         template <class T>
 | |
|         void readVector(std::vector<T>& vec, size_t size)
 | |
|         {
 | |
|             if (size == 0)
 | |
|                 return;
 | |
|             vec.resize(size);
 | |
|             read(vec.data(), size);
 | |
|         }
 | |
| 
 | |
|         /// Extract an instance of type
 | |
|         template <class T>
 | |
|         T get()
 | |
|         {
 | |
|             T data;
 | |
|             read(data);
 | |
|             return data;
 | |
|         }
 | |
| 
 | |
|         /// Read a string of the given length
 | |
|         std::string getSizedString(size_t length);
 | |
| 
 | |
|         /// Read a string of the length specified in the file
 | |
|         std::string getSizedString() { return getSizedString(get<uint32_t>()); }
 | |
| 
 | |
|         /// Read a list of strings without using the string table, e.g. the string table itself
 | |
|         void getSizedStrings(std::vector<std::string>& vec, size_t size);
 | |
| 
 | |
|         /// Read a Bethesda header string that uses a byte for length
 | |
|         std::string getExportString() { return getSizedString(get<uint8_t>()); }
 | |
| 
 | |
|         /// Read the version string which doesn't start with a number and ends with "\n"
 | |
|         std::string getVersionString();
 | |
| 
 | |
|         /// Read a sequence of null-terminated strings
 | |
|         std::string getStringPalette();
 | |
|     };
 | |
| 
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec2f>(osg::Vec2f& vec);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec3f>(osg::Vec3f& vec);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec4f>(osg::Vec4f& vec);
 | |
|     template <>
 | |
|     void NIFStream::read<Matrix3>(Matrix3& mat);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Quat>(osg::Quat& quat);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::BoundingSpheref>(osg::BoundingSpheref& sphere);
 | |
|     template <>
 | |
|     void NIFStream::read<NiTransform>(NiTransform& transform);
 | |
|     template <>
 | |
|     void NIFStream::read<NiQuatTransform>(NiQuatTransform& transform);
 | |
|     template <>
 | |
|     void NIFStream::read<bool>(bool& data);
 | |
|     template <>
 | |
|     void NIFStream::read<std::string>(std::string& str);
 | |
| 
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec2f>(osg::Vec2f* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec3f>(osg::Vec3f* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Vec4f>(osg::Vec4f* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<Matrix3>(Matrix3* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::Quat>(osg::Quat* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<osg::BoundingSpheref>(osg::BoundingSpheref* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<NiTransform>(NiTransform* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<NiQuatTransform>(NiQuatTransform* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<bool>(bool* dest, size_t size);
 | |
|     template <>
 | |
|     void NIFStream::read<std::string>(std::string* dest, size_t size);
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif
 |