diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 55b0cb713a..d387ae5259 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -4,47 +4,191 @@ namespace Nif { - osg::Quat NIFStream::getQuaternion() - { - float f[4]; - readBufferOfType<4, float>(mStream, f); - osg::Quat quat; - quat.w() = f[0]; - quat.x() = f[1]; - quat.y() = f[2]; - quat.z() = f[3]; - return quat; - } - - Transformation NIFStream::getTrafo() - { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; - } - - bool NIFStream::getBoolean() - { - return getVersion() < generateVersion(4, 1, 0, 0) ? getInt() != 0 : getChar() != 0; - } - - std::string NIFStream::getString() - { - return getVersion() < generateVersion(20, 1, 0, 1) ? getSizedString() : mReader.getString(getUInt()); - } unsigned int NIFStream::getVersion() const { return mReader.getVersion(); } + unsigned int NIFStream::getUserVersion() const { - return mReader.getBethVersion(); + return mReader.getUserVersion(); } + unsigned int NIFStream::getBethVersion() const { return mReader.getBethVersion(); } + + std::string NIFStream::getSizedString(size_t length) + { + std::string str(length, '\0'); + mStream->read(str.data(), length); + if (mStream->bad()) + throw std::runtime_error("Failed to read sized string of " + std::to_string(length) + " chars"); + size_t end = str.find('\0'); + if (end != std::string::npos) + str.erase(end); + return str; + } + + void NIFStream::getSizedStrings(std::vector& vec, size_t size) + { + vec.resize(size); + for (size_t i = 0; i < vec.size(); i++) + vec[i] = getSizedString(); + } + + std::string NIFStream::getVersionString() + { + std::string result; + std::getline(*mStream, result); + if (mStream->bad()) + throw std::runtime_error("Failed to read version string"); + return result; + } + + std::string NIFStream::getStringPalette() + { + size_t size = get(); + std::string str(size, '\0'); + mStream->read(str.data(), size); + if (mStream->bad()) + throw std::runtime_error("Failed to read string palette of " + std::to_string(size) + " chars"); + return str; + } + + template <> + void NIFStream::read(osg::Vec2f& vec) + { + readBufferOfType<2>(mStream, vec._v); + } + + template <> + void NIFStream::read(osg::Vec3f& vec) + { + readBufferOfType<3>(mStream, vec._v); + } + + template <> + void NIFStream::read(osg::Vec4f& vec) + { + readBufferOfType<4>(mStream, vec._v); + } + + template <> + void NIFStream::read(Matrix3& mat) + { + readBufferOfType<9>(mStream, (float*)&mat.mValues); + } + + template <> + void NIFStream::read(osg::Quat& quat) + { + std::array data; + readArray(data); + quat.w() = data[0]; + quat.x() = data[1]; + quat.y() = data[2]; + quat.z() = data[3]; + } + + template <> + void NIFStream::read(Transformation& t) + { + read(t.pos); + read(t.rotation); + read(t.scale); + } + + template <> + void NIFStream::read(bool& data) + { + if (getVersion() < generateVersion(4, 1, 0, 0)) + data = get() != 0; + else + data = get() != 0; + } + + template <> + void NIFStream::read(std::string& str) + { + if (getVersion() < generateVersion(20, 1, 0, 1)) + str = getSizedString(); + else + str = mReader.getString(get()); + } + + template <> + void NIFStream::read(osg::Vec2f* dest, size_t size) + { + // The packed storage of each Vec2f is 2 floats exactly + readDynamicBufferOfType(mStream, (float*)dest, size * 2); + } + + template <> + void NIFStream::read(osg::Vec3f* dest, size_t size) + { + // The packed storage of each Vec3f is 3 floats exactly + readDynamicBufferOfType(mStream, (float*)dest, size * 3); + } + + template <> + void NIFStream::read(osg::Vec4f* dest, size_t size) + { + // The packed storage of each Vec4f is 4 floats exactly + readDynamicBufferOfType(mStream, (float*)dest, size * 4); + } + + template <> + void NIFStream::read(Matrix3* dest, size_t size) + { + // The packed storage of each Matrix3 is 9 floats exactly + readDynamicBufferOfType(mStream, (float*)dest, size * 9); + } + + template <> + void NIFStream::read(osg::Quat* dest, size_t size) + { + for (size_t i = 0; i < size; i++) + read(dest[i]); + } + + template <> + void NIFStream::read(Transformation* dest, size_t size) + { + for (size_t i = 0; i < size; i++) + read(dest[i]); + } + + template <> + void NIFStream::read(bool* dest, size_t size) + { + if (getVersion() < generateVersion(4, 1, 0, 0)) + { + for (size_t i = 0; i < size; i++) + dest[i] = get() != 0; + } + else + { + for (size_t i = 0; i < size; i++) + dest[i] = get() != 0; + } + } + + template <> + void NIFStream::read(std::string* dest, size_t size) + { + if (getVersion() < generateVersion(20, 1, 0, 1)) + { + for (size_t i = 0; i < size; i++) + dest[i] = getSizedString(); + } + else + { + for (size_t i = 0; i < size; i++) + dest[i] = mReader.getString(get()); + } + } + } diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 1826ae125c..b9b2f1923d 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -55,13 +55,6 @@ namespace Nif for (std::size_t i = 0; i < numInstances; i++) Misc::swapEndiannessInplace(dest[i]); } - template - type inline readType(Files::IStreamPtr& pIStream) - { - type val; - readBufferOfType<1, type>(pIStream, &val); - return val; - } class NIFStream { @@ -77,23 +70,37 @@ namespace Nif 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 void read(T& data) { - data = readType(mStream); + readBufferOfType<1>(mStream, &data); } - void read(osg::Vec3f& data) { readBufferOfType<3, float>(mStream, data._v); } - void read(osg::Vec4f& data) { readBufferOfType<4, float>(mStream, data._v); } - - /// Extract an instance of type - template - T get() + /// Read multiple instances of type into an array + template + void readArray(std::array& arr) { - return readType(mStream); + readBufferOfType(mStream, arr.data()); + } + + /// Read instances of type into a dynamic buffer + template + void read(T* dest, size_t size) + { + readDynamicBufferOfType(mStream, dest, size); } /// Read multiple instances of type into a vector @@ -101,217 +108,100 @@ namespace Nif void readVector(std::vector& vec, size_t size) { vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); + read(vec.data(), size); } - /// Read multiple instances of type into an array - template - void readArray(std::array& arr) + /// Extract an instance of type + template + T get() { - readBufferOfType(mStream, arr.data()); - } - - // DEPRECATED: Use read() or get() whenever relevant - char getChar() { return readType(mStream); } - - // DEPRECATED: Use read() or get() whenever relevant - short getShort() { return readType(mStream); } - - // DEPRECATED: Use read() or get() whenever relevant - unsigned short getUShort() { return readType(mStream); } - - // DEPRECATED: Use read() or get() whenever relevant - int getInt() { return readType(mStream); } - - // DEPRECATED: Use read() or get() whenever relevant - unsigned int getUInt() { return readType(mStream); } - - // DEPRECATED: Use read() or get() whenever relevant - float getFloat() { return readType(mStream); } - - osg::Vec2f getVector2() - { - osg::Vec2f vec; - readBufferOfType<2, float>(mStream, vec._v); - return vec; - } - - // DEPRECATED: Use read() whenever relevant - osg::Vec3f getVector3() - { - osg::Vec3f vec; - readBufferOfType<3, float>(mStream, vec._v); - return vec; - } - - osg::Vec4f getVector4() - { - osg::Vec4f vec; - readBufferOfType<4, float>(mStream, vec._v); - return vec; - } - - Matrix3 getMatrix3() - { - Matrix3 mat; - readBufferOfType<9, float>(mStream, (float*)&mat.mValues); - return mat; - } - - osg::Quat getQuaternion(); - - Transformation getTrafo(); - - /// Read in a boolean. Boolean serialization format differs between versions - bool getBoolean(); - - /// Read in a string, either from the string table or from the stream depending on the version - std::string getString(); - - 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; + T data; + read(data); + return data; } /// Read a string of the given length - std::string getSizedString(size_t length) - { - std::string str(length, '\0'); - mStream->read(str.data(), length); - if (mStream->bad()) - throw std::runtime_error("Failed to read sized string of " + std::to_string(length) + " chars"); - size_t end = str.find('\0'); - if (end != std::string::npos) - str.erase(end); - return str; - } + std::string getSizedString(size_t length); /// Read a string of the length specified in the file - std::string getSizedString() - { - size_t size = readType(mStream); - return getSizedString(size); - } - - /// Read a Bethesda header string that uses a byte for length - std::string getExportString() - { - size_t size = static_cast(readType(mStream)); - return getSizedString(size); - } - - /// Read the version string which doesn't start with a number and ends with "\n" - std::string getVersionString() - { - std::string result; - std::getline(*mStream, result); - if (mStream->bad()) - throw std::runtime_error("Failed to read version string"); - return result; - } - - /// Read a sequence of null-terminated strings - std::string getStringPalette() - { - size_t size = readType(mStream); - std::string str(size, '\0'); - mStream->read(str.data(), size); - if (mStream->bad()) - throw std::runtime_error("Failed to read string palette of " + std::to_string(size) + " chars"); - return str; - } - - // DEPRECATED: Use readVector() - void getChars(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - // DEPRECATED: Use readVector() - void getUChars(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - // DEPRECATED: Use readVector() - void getUShorts(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - // DEPRECATED: Use readVector() - void getFloats(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - // DEPRECATED: Use readVector() - void getInts(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - // DEPRECATED: Use readVector() - void getUInts(std::vector& vec, size_t size) - { - vec.resize(size); - readDynamicBufferOfType(mStream, vec.data(), size); - } - - void getVector2s(std::vector& vec, size_t size) - { - vec.resize(size); - // The packed storage of each Vec2f is 2 floats exactly - readDynamicBufferOfType(mStream, (float*)vec.data(), size * 2); - } - - void getVector3s(std::vector& vec, size_t size) - { - vec.resize(size); - // The packed storage of each Vec3f is 3 floats exactly - readDynamicBufferOfType(mStream, (float*)vec.data(), size * 3); - } - - void getVector4s(std::vector& vec, size_t size) - { - vec.resize(size); - // The packed storage of each Vec4f is 4 floats exactly - readDynamicBufferOfType(mStream, (float*)vec.data(), size * 4); - } - - void getQuaternions(std::vector& quat, size_t size) - { - quat.resize(size); - for (size_t i = 0; i < quat.size(); i++) - quat[i] = getQuaternion(); - } - - void getStrings(std::vector& vec, size_t size) - { - vec.resize(size); - for (size_t i = 0; i < vec.size(); i++) - vec[i] = getString(); - } + std::string getSizedString() { return getSizedString(get()); } /// Read a list of strings without using the string table, e.g. the string table itself - void getSizedStrings(std::vector& vec, size_t size) - { - vec.resize(size); - for (size_t i = 0; i < vec.size(); i++) - vec[i] = getSizedString(); - } + void getSizedStrings(std::vector& vec, size_t size); + + /// Read a Bethesda header string that uses a byte for length + std::string getExportString() { return getSizedString(get()); } + + /// 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(); } + short getShort() { return get(); } + unsigned short getUShort() { return get(); } + int getInt() { return get(); } + unsigned int getUInt() { return get(); } + float getFloat() { return get(); } + osg::Vec2f getVector2() { return get(); } + osg::Vec3f getVector3() { return get(); } + osg::Vec4f getVector4() { return get(); } + Matrix3 getMatrix3() { return get(); } + osg::Quat getQuaternion() { return get(); } + Transformation getTrafo() { return get(); } + bool getBoolean() { return get(); } + std::string getString() { return get(); } + + /// DEPRECATED: Use readVector() + void getChars(std::vector& vec, size_t size) { readVector(vec, size); } + void getUChars(std::vector& vec, size_t size) { readVector(vec, size); } + void getUShorts(std::vector& vec, size_t size) { readVector(vec, size); } + void getFloats(std::vector& vec, size_t size) { readVector(vec, size); } + void getInts(std::vector& vec, size_t size) { readVector(vec, size); } + void getUInts(std::vector& vec, size_t size) { readVector(vec, size); } + void getVector2s(std::vector& vec, size_t size) { readVector(vec, size); } + void getVector3s(std::vector& vec, size_t size) { readVector(vec, size); } + void getVector4s(std::vector& vec, size_t size) { readVector(vec, size); } + void getQuaternions(std::vector& vec, size_t size) { readVector(vec, size); } + void getStrings(std::vector& vec, size_t size) { readVector(vec, size); } }; + template <> + void NIFStream::read(osg::Vec2f& vec); + template <> + void NIFStream::read(osg::Vec3f& vec); + template <> + void NIFStream::read(osg::Vec4f& vec); + template <> + void NIFStream::read(Matrix3& mat); + template <> + void NIFStream::read(osg::Quat& quat); + template <> + void NIFStream::read(Transformation& t); + template <> + void NIFStream::read(bool& data); + template <> + void NIFStream::read(std::string& str); + + template <> + void NIFStream::read(osg::Vec2f* dest, size_t size); + template <> + void NIFStream::read(osg::Vec3f* dest, size_t size); + template <> + void NIFStream::read(osg::Vec4f* dest, size_t size); + template <> + void NIFStream::read(Matrix3* dest, size_t size); + template <> + void NIFStream::read(osg::Quat* dest, size_t size); + template <> + void NIFStream::read(Transformation* dest, size_t size); + template <> + void NIFStream::read(bool* dest, size_t size); + template <> + void NIFStream::read(std::string* dest, size_t size); + } #endif