1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-30 03:32:36 +00:00
OpenMW/components/nif/nifstream.hpp
Alexei Kotov d078907dcb NIFStream: rewrite loading for everything
Replace overloading with read() template specializations for every type that needs specific handling
Make use of the new read() or get() in all methods
Move complex string-related methods to implementation
2023-08-17 09:15:45 +03:00

208 lines
7.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 <type_traits>
#include <vector>
#include <components/files/istreamptr.hpp>
#include <components/misc/endianness.hpp>
#include <components/misc/float16.hpp>
#include <osg/Quat>
#include <osg/Vec3f>
#include <osg/Vec4f>
#include "niftypes.hpp"
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 <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;
public:
explicit NIFStream(const Reader& reader, Files::IStreamPtr&& stream)
: mReader(reader)
, mStream(std::move(stream))
{
}
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)
{
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();
/// DEPRECATED: Use read() or get()
char getChar() { return get<char>(); }
short getShort() { return get<short>(); }
unsigned short getUShort() { return get<unsigned short>(); }
int getInt() { return get<int>(); }
unsigned int getUInt() { return get<unsigned int>(); }
float getFloat() { return get<float>(); }
osg::Vec2f getVector2() { return get<osg::Vec2f>(); }
osg::Vec3f getVector3() { return get<osg::Vec3f>(); }
osg::Vec4f getVector4() { return get<osg::Vec4f>(); }
Matrix3 getMatrix3() { return get<Matrix3>(); }
osg::Quat getQuaternion() { return get<osg::Quat>(); }
Transformation getTrafo() { return get<Transformation>(); }
bool getBoolean() { return get<bool>(); }
std::string getString() { return get<std::string>(); }
/// DEPRECATED: Use readVector()
void getChars(std::vector<char>& vec, size_t size) { readVector(vec, size); }
void getUChars(std::vector<unsigned char>& vec, size_t size) { readVector(vec, size); }
void getUShorts(std::vector<unsigned short>& vec, size_t size) { readVector(vec, size); }
void getFloats(std::vector<float>& vec, size_t size) { readVector(vec, size); }
void getInts(std::vector<int>& vec, size_t size) { readVector(vec, size); }
void getUInts(std::vector<unsigned int>& vec, size_t size) { readVector(vec, size); }
void getVector2s(std::vector<osg::Vec2f>& vec, size_t size) { readVector(vec, size); }
void getVector3s(std::vector<osg::Vec3f>& vec, size_t size) { readVector(vec, size); }
void getVector4s(std::vector<osg::Vec4f>& vec, size_t size) { readVector(vec, size); }
void getQuaternions(std::vector<osg::Quat>& vec, size_t size) { readVector(vec, size); }
void getStrings(std::vector<std::string>& vec, size_t size) { readVector(vec, size); }
};
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<Transformation>(Transformation& t);
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<Transformation>(Transformation* 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