From 246759ecd2c5c2daf46bc250a6323240197073e5 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 19 Sep 2025 13:30:42 +0200 Subject: [PATCH] Only reserve capacity when reading collections But do not initialize. If the meta information is invalid and has a big value, initialization will take significant amount of time but there might be no actual data in the file because it's too small. --- components/nif/controller.cpp | 49 +++++++------- components/nif/controller.hpp | 2 + components/nif/data.cpp | 124 ++++++++++++++++++++-------------- components/nif/data.hpp | 7 +- components/nif/extra.cpp | 31 +++------ components/nif/extra.hpp | 2 + components/nif/niffile.cpp | 21 +++--- components/nif/nifkey.hpp | 83 +++++++++++++---------- components/nif/nifstream.cpp | 7 +- components/nif/nifstream.hpp | 42 ++++++++++++ components/nif/node.cpp | 17 +++-- components/nif/node.hpp | 2 + components/nif/particle.cpp | 13 +--- components/nif/physics.cpp | 6 +- components/nif/property.cpp | 28 +++++--- components/nif/recordptr.hpp | 11 +-- 16 files changed, 252 insertions(+), 193 deletions(-) diff --git a/components/nif/controller.cpp b/components/nif/controller.cpp index 7e9b6b917e..b70b8c16a7 100644 --- a/components/nif/controller.cpp +++ b/components/nif/controller.cpp @@ -8,6 +8,13 @@ namespace Nif { + namespace + { + void readSkinnedShapeGroup(NIFStream& stream, std::vector& value) + { + stream.readVectorOfRecords(value); + } + } void NiTimeController::read(NIFStream* nif) { @@ -84,11 +91,10 @@ namespace Nif nif->read(mAccumRootName); mTextKeys.read(nif); } - mControlledBlocks.resize(nif->get()); + const uint32_t size = nif->get(); if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 106)) nif->read(mArrayGrowBy); - for (ControlledBlock& block : mControlledBlocks) - block.read(nif); + nif->readVectorOfRecords(size, mControlledBlocks); } void NiSequence::post(Reader& nif) @@ -122,13 +128,8 @@ namespace Nif mStringPalette.read(nif); else if (nif->getVersion() >= NIFFile::NIFVersion::VER_BGS && nif->getBethVersion() >= 24) { - if (nif->getBethVersion() >= 29) - mAnimNotesList.resize(nif->get()); - else - mAnimNotesList.resize(1); - - for (auto& notes : mAnimNotesList) - notes.read(nif); + const uint16_t size = nif->getBethVersion() >= 29 ? nif->get() : 1; + nif->readVectorOfRecords(size, mAnimNotesList); } } @@ -482,29 +483,27 @@ namespace Nif mData.post(nif); } + void NiBoneLODController::SkinInfo::read(NIFStream* nif) + { + mShape.read(nif); + mSkin.read(nif); + } + void NiBoneLODController::read(NIFStream* nif) { NiTimeController::read(nif); nif->read(mLOD); - mNodeGroups.resize(nif->get()); + const uint32_t nodeGroupsCount = nif->get(); + mNodeGroups.reserve(nodeGroupsCount); nif->read(mNumNodeGroups); - for (NiAVObjectList& group : mNodeGroups) - readRecordList(nif, group); + for (uint32_t i = 0; i < nodeGroupsCount; ++i) + readRecordList(nif, mNodeGroups.emplace_back()); if (nif->getBethVersion() != 0 || nif->getVersion() < NIFStream::generateVersion(4, 2, 2, 0)) return; - mSkinnedShapeGroups.resize(nif->get()); - for (std::vector& group : mSkinnedShapeGroups) - { - group.resize(nif->get()); - for (SkinInfo& info : group) - { - info.mShape.read(nif); - info.mSkin.read(nif); - } - } + nif->readVectorOfRecords(readSkinnedShapeGroup, mSkinnedShapeGroups); readRecordList(nif, mShapeGroups); } @@ -892,9 +891,7 @@ namespace Nif void BSTreadTransfInterpolator::read(NIFStream* nif) { - mTransforms.resize(nif->get()); - for (BSTreadTransform& transform : mTransforms) - transform.read(nif); + nif->readVectorOfRecords(mTransforms); mData.read(nif); } diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 2226a6e9df..4f0a2d6a53 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -322,6 +322,8 @@ namespace Nif { NiTriBasedGeomPtr mShape; NiSkinInstancePtr mSkin; + + void read(NIFStream* nif); }; uint32_t mLOD; diff --git a/components/nif/data.cpp b/components/nif/data.cpp index a134749bdc..3351658090 100644 --- a/components/nif/data.cpp +++ b/components/nif/data.cpp @@ -8,6 +8,46 @@ namespace Nif { + namespace + { + void readNiSkinDataVertWeight(NIFStream& stream, NiSkinData::VertWeight& value) + { + auto& [vertex, weight] = value; + stream.read(vertex); + stream.read(weight); + } + + struct ReadNiSkinDataBoneInfo + { + bool mHasVertexWeights; + + void operator()(NIFStream& stream, NiSkinData::BoneInfo& value) const + { + stream.read(value.mTransform); + stream.read(value.mBoundSphere); + + const uint16_t numVertices = stream.get(); + + if (!mHasVertexWeights) + return; + + stream.readVectorOfRecords(numVertices, readNiSkinDataVertWeight, value.mWeights); + } + }; + + struct ReadNiMorphDataMorphData + { + uint32_t mNumVerts; + + void operator()(NIFStream& stream, NiMorphData::MorphData& value) const + { + value.mKeyFrames = std::make_shared(); + value.mKeyFrames->read(&stream, /*morph*/ true); + stream.readVector(value.mVertices, mNumVerts); + } + }; + } + void NiGeometryData::read(NIFStream* nif) { if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 114)) @@ -215,20 +255,21 @@ namespace Nif nif->read(mSigned); } + void NiPixelData::Mipmap::read(NIFStream* nif) + { + nif->read(mWidth); + nif->read(mHeight); + nif->read(mOffset); + } + void NiPixelData::read(NIFStream* nif) { mPixelFormat.read(nif); mPalette.read(nif); - mMipmaps.resize(nif->get()); + const uint32_t mipmapsCount = nif->get(); nif->read(mBytesPerPixel); - for (Mipmap& mip : mMipmaps) - { - nif->read(mip.mWidth); - nif->read(mip.mHeight); - nif->read(mip.mOffset); - } - uint32_t numPixels; - nif->read(numPixels); + nif->readVectorOfRecords(mipmapsCount, mMipmaps); + const uint32_t numPixels = nif->get(); if (nif->getVersion() >= NIFStream::generateVersion(10, 4, 0, 2)) nif->read(mNumFaces); nif->readVector(mData, numPixels * mNumFaces); @@ -247,12 +288,14 @@ namespace Nif void NiVisData::read(NIFStream* nif) { - mKeys = std::make_shared>>(nif->get()); - for (auto& [time, value] : *mKeys) - { - nif->read(time); - value = nif->get() != 0; - } + const auto readPair = [](NIFStream& stream, std::pair& value) { + stream.read(value.first); + value.second = stream.get() != 0; + }; + + std::vector> keys; + nif->readVectorOfRecords(readPair, keys); + mKeys = std::make_shared>>(std::move(keys)); } void NiSkinInstance::read(NIFStream* nif) @@ -296,16 +339,17 @@ namespace Nif return partitions; } + void BSDismemberSkinInstance::BodyPart::read(NIFStream* nif) + { + nif->read(mFlags); + nif->read(mType); + } + void BSDismemberSkinInstance::read(NIFStream* nif) { NiSkinInstance::read(nif); - mParts.resize(nif->get()); - for (BodyPart& part : mParts) - { - nif->read(part.mFlags); - nif->read(part.mType); - } + nif->readVectorOfRecords(mParts); } void BSSkinInstance::read(NIFStream* nif) @@ -339,8 +383,7 @@ namespace Nif { nif->read(mTransform); - uint32_t numBones; - nif->read(numBones); + const uint32_t numBones = nif->get(); bool hasVertexWeights = true; if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW) { @@ -351,25 +394,8 @@ namespace Nif nif->read(hasVertexWeights); } - mBones.resize(numBones); - for (BoneInfo& bi : mBones) - { - nif->read(bi.mTransform); - nif->read(bi.mBoundSphere); - - uint16_t numVertices; - nif->read(numVertices); - - if (!hasVertexWeights) - continue; - - bi.mWeights.resize(numVertices); - for (auto& [vertex, weight] : bi.mWeights) - { - nif->read(vertex); - nif->read(weight); - } - } + const ReadNiSkinDataBoneInfo readBoneInfo{ .mHasVertexWeights = hasVertexWeights }; + nif->readVectorOfRecords(numBones, readBoneInfo, mBones); } void NiSkinData::post(Reader& nif) @@ -467,18 +493,12 @@ namespace Nif void NiMorphData::read(NIFStream* nif) { - uint32_t numMorphs, numVerts; - nif->read(numMorphs); - nif->read(numVerts); + const uint32_t numMorphs = nif->get(); + const uint32_t numVerts = nif->get(); nif->read(mRelativeTargets); - mMorphs.resize(numMorphs); - for (MorphData& morph : mMorphs) - { - morph.mKeyFrames = std::make_shared(); - morph.mKeyFrames->read(nif, /*morph*/ true); - nif->readVector(morph.mVertices, numVerts); - } + const ReadNiMorphDataMorphData readMorph{ .mNumVerts = numVerts }; + nif->readVectorOfRecords(numMorphs, readMorph, mMorphs); } void NiKeyframeData::read(NIFStream* nif) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 4000055e8c..55ae92074a 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -169,8 +169,11 @@ namespace Nif { struct Mipmap { - uint32_t mWidth, mHeight; + uint32_t mWidth; + uint32_t mHeight; uint32_t mOffset; + + void read(NIFStream* nif); }; NiPixelFormat mPixelFormat; @@ -218,6 +221,8 @@ namespace Nif { uint16_t mFlags; uint16_t mType; + + void read(NIFStream* nif); }; std::vector mParts; diff --git a/components/nif/extra.cpp b/components/nif/extra.cpp index 4ebd0bf517..a9f8f7994c 100644 --- a/components/nif/extra.cpp +++ b/components/nif/extra.cpp @@ -2,7 +2,6 @@ namespace Nif { - void NiExtraData::read(NIFStream* nif) { Extra::read(nif); @@ -17,18 +16,17 @@ namespace Nif nif->getSizedStrings(mData, nif->get()); } + void NiTextKeyExtraData::TextKey::read(NIFStream* nif) + { + nif->read(mTime); + nif->read(mText); + } + void NiTextKeyExtraData::read(NIFStream* nif) { Extra::read(nif); - uint32_t numKeys; - nif->read(numKeys); - mList.resize(numKeys); - for (TextKey& key : mList) - { - nif->read(key.mTime); - nif->read(key.mText); - } + nif->readVectorOfRecords(mList); } void NiVertWeightsExtraData::read(NIFStream* nif) @@ -66,20 +64,11 @@ namespace Nif { Extra::read(nif); - uint32_t num; - nif->read(num); + const uint32_t num = nif->get(); if (nif->getBethVersion() <= NIFFile::BethVersion::BETHVER_FO3) - { - mLegacyMarkers.resize(num); - for (auto& marker : mLegacyMarkers) - marker.read(nif); - } + nif->readVectorOfRecords(num, mLegacyMarkers); else - { - mMarkers.resize(num); - for (auto& marker : mMarkers) - marker.read(nif); - } + nif->readVectorOfRecords(num, mMarkers); } void BSInvMarker::read(NIFStream* nif) diff --git a/components/nif/extra.hpp b/components/nif/extra.hpp index 2b46c81e26..f5c48b3517 100644 --- a/components/nif/extra.hpp +++ b/components/nif/extra.hpp @@ -77,6 +77,8 @@ namespace Nif { float mTime; std::string mText; + + void read(NIFStream* nif); }; std::vector mList; diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index c0a1da4846..92646ea73e 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -600,7 +600,9 @@ namespace Nif if (hasUserVersion) nif.read(mUserVersion); - mRecords.resize(nif.get()); + const std::uint32_t recordsCount = nif.get(); + + mRecords.reserve(recordsCount); // Bethesda stream header { @@ -646,14 +648,14 @@ namespace Nif else { nif.getSizedStrings(recTypes, nif.get()); - nif.readVector(recTypeIndices, mRecords.size()); + nif.readVector(recTypeIndices, recordsCount); } } if (hasRecordSizes) // Record sizes { std::vector recSizes; // Currently unused - nif.readVector(recSizes, mRecords.size()); + nif.readVector(recSizes, recordsCount); } if (hasStringTable) @@ -670,7 +672,7 @@ namespace Nif nif.readVector(groups, nif.get()); } - for (std::size_t i = 0; i < mRecords.size(); i++) + for (std::size_t i = 0; i < recordsCount; i++) { std::unique_ptr r; @@ -701,22 +703,23 @@ namespace Nif r->recName = std::move(rec); r->recIndex = static_cast(i); r->read(&nif); - mRecords[i] = std::move(r); + mRecords.push_back(std::move(r)); } // Determine which records are roots - mRoots.resize(nif.get()); - for (std::size_t i = 0; i < mRoots.size(); i++) + const std::uint32_t rootsCount = nif.get(); + mRoots.reserve(rootsCount); + for (std::size_t i = 0; i < rootsCount; i++) { std::int32_t idx; nif.read(idx); if (idx >= 0 && static_cast(idx) < mRecords.size()) { - mRoots[i] = mRecords[idx].get(); + mRoots.push_back(mRecords[idx].get()); } else { - mRoots[i] = nullptr; + mRoots.push_back(nullptr); Log(Debug::Warning) << "NIFFile Warning: Root " << i + 1 << " does not point to a record: index " << idx << ". File: " << mFilename; } diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index e32ef76d95..df28c03f30 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -76,8 +76,7 @@ namespace Nif } } - uint32_t count; - nif->read(count); + const uint32_t count = nif->get(); if (count == 0 && !morph) return; @@ -86,42 +85,21 @@ namespace Nif mKeys.reserve(count); - KeyType key = {}; - if (mInterpolationType == InterpolationType_Linear || mInterpolationType == InterpolationType_Constant) { - for (size_t i = 0; i < count; i++) - { - float time; - nif->read(time); - readValue(*nif, key); - mKeys.emplace_back(time, key); - } + nif->readVectorOfRecords(count, readValuePair, mKeys); } else if (mInterpolationType == InterpolationType_Quadratic) { - for (size_t i = 0; i < count; i++) - { - float time; - nif->read(time); - readQuadratic(*nif, key); - mKeys.emplace_back(time, key); - } + nif->readVectorOfRecords(count, readQuadraticPair, mKeys); } else if (mInterpolationType == InterpolationType_TCB) { - std::vector> tcbKeys(count); - for (TCBKey& tcbKey : tcbKeys) - { - nif->read(tcbKey.mTime); - tcbKey.mValue = ((*nif).*getValue)(); - nif->read(tcbKey.mTension); - nif->read(tcbKey.mContinuity); - nif->read(tcbKey.mBias); - } + std::vector> tcbKeys; + nif->readVectorOfRecords(count, readTCBKey, tcbKeys); generateTCBTangents(tcbKeys); for (TCBKey& tcbKey : tcbKeys) - mKeys.emplace_back(std::move(tcbKey.mTime), + mKeys.emplace_back(tcbKey.mTime, KeyType{ std::move(tcbKey.mValue), std::move(tcbKey.mInTan), std::move(tcbKey.mOutTan) }); } else if (mInterpolationType == InterpolationType_XYZ) @@ -143,17 +121,42 @@ namespace Nif } private: - static void readValue(NIFStream& nif, KeyT& key) { key.mValue = (nif.*getValue)(); } + static void readValue(NIFStream& nif, KeyType& key) { key.mValue = (nif.*getValue)(); } - template - static void readQuadratic(NIFStream& nif, KeyT& key) + static void readValuePair(NIFStream& nif, std::pair& value) { - readValue(nif, key); - key.mInTan = (nif.*getValue)(); - key.mOutTan = (nif.*getValue)(); + nif.read(value.first); + readValue(nif, value.second); } - static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } + static void readQuadratic(NIFStream& nif, KeyType& key) + { + if constexpr (std::is_same_v) + { + readValue(nif, key); + } + else + { + readValue(nif, key); + key.mInTan = (nif.*getValue)(); + key.mOutTan = (nif.*getValue)(); + } + } + + static void readQuadraticPair(NIFStream& nif, std::pair& value) + { + nif.read(value.first); + readQuadratic(nif, value.second); + } + + static void readTCBKey(NIFStream& nif, TCBKey& value) + { + nif.read(value.mTime); + value.mValue = (nif.*getValue)(); + nif.read(value.mTension); + nif.read(value.mContinuity); + nif.read(value.mBias); + } template static void generateTCBTangents(std::vector>& keys) @@ -192,6 +195,16 @@ namespace Nif } }; + template + void readKeyMapPair(NIFStream& stream, std::pair>& value); + + template <> + inline void readKeyMapPair(NIFStream& stream, std::pair>& value) + { + stream.read(value.first); + value.second.mValue = stream.get() != 0; + } + using FloatKeyMap = KeyMapT>; using Vector3KeyMap = KeyMapT>; using Vector4KeyMap = KeyMapT>; diff --git a/components/nif/nifstream.cpp b/components/nif/nifstream.cpp index 51ba2c9bac..0b32205aac 100644 --- a/components/nif/nifstream.cpp +++ b/components/nif/nifstream.cpp @@ -73,9 +73,10 @@ namespace Nif void NIFStream::getSizedStrings(std::vector& vec, size_t size) { - vec.resize(size); - for (size_t i = 0; i < vec.size(); i++) - vec[i] = getSizedString(); + vec.clear(); + vec.reserve(size); + for (size_t i = 0; i < size; i++) + vec.push_back(getSizedString()); } std::string NIFStream::getVersionString() diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index e5c2ce41d6..f4b3e09533 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -73,6 +73,11 @@ namespace Nif Misc::swapEndiannessInplace(dest[i]); } + class NIFStream; + + template + void readRecord(NIFStream& stream, T& value); + class NIFStream { const Reader& mReader; @@ -166,10 +171,47 @@ namespace Nif /// Read a sequence of null-terminated strings std::string getStringPalette(); + template + void readVectorOfRecords(Count count, Read&& read, std::vector& values) + { + values.clear(); + values.reserve(count); + for (Count i = 0; i < count; ++i) + { + T value; + read(*this, value); + values.push_back(std::move(value)); + } + } + + template + void readVectorOfRecords(Read&& read, std::vector& values) + { + readVectorOfRecords(get(), std::forward(read), values); + } + + template + void readVectorOfRecords(Count count, std::vector& values) + { + readVectorOfRecords(count, readRecord, values); + } + + template + void readVectorOfRecords(std::vector& values) + { + readVectorOfRecords(readRecord, values); + } + private: void checkStreamSize(std::size_t size); }; + template + void readRecord(NIFStream& stream, T& value) + { + value.read(&stream); + } + template <> void NIFStream::read(osg::Vec2f& vec); template <> diff --git a/components/nif/node.cpp b/components/nif/node.cpp index 7dba288164..086d1969ae 100644 --- a/components/nif/node.cpp +++ b/components/nif/node.cpp @@ -105,9 +105,7 @@ namespace Nif } case UNION_BV: { - mChildren.resize(nif->get()); - for (BoundingVolume& child : mChildren) - child.read(nif); + nif->readVectorOfRecords(mChildren); break; } case HALFSPACE_BV: @@ -426,6 +424,12 @@ namespace Nif nif->read(mInitialIndex); } + void NiLODNode::LODRange::read(NIFStream* nif) + { + nif->read(mMinRange); + nif->read(mMaxRange); + } + void NiLODNode::read(NIFStream* nif) { NiSwitchNode::read(nif); @@ -439,12 +443,7 @@ namespace Nif if (nif->getVersion() >= NIFFile::NIFVersion::VER_MW) nif->read(mLODCenter); - mLODLevels.resize(nif->get()); - for (LODRange& level : mLODLevels) - { - nif->read(level.mMinRange); - nif->read(level.mMaxRange); - } + nif->readVectorOfRecords(mLODLevels); } void NiFltAnimationNode::read(NIFStream* nif) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index e9306fa83f..86a75bb287 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -232,6 +232,8 @@ namespace Nif { float mMinRange; float mMaxRange; + + void read(NIFStream* nif); }; osg::Vec3f mLODCenter; diff --git a/components/nif/particle.cpp b/components/nif/particle.cpp index 9249541717..a8c69fd04e 100644 --- a/components/nif/particle.cpp +++ b/components/nif/particle.cpp @@ -225,11 +225,7 @@ namespace Nif bool hasData = nif->getBethVersion() < NIFFile::BethVersion::BETHVER_FO3; if (hasData) - { - mParticles.resize(mNumVertices); - for (NiParticleInfo& info : mParticles) - info.read(nif); - } + nif->readVectorOfRecords(mNumVertices, mParticles); if (nif->getBethVersion() > NIFFile::BethVersion::BETHVER_FO4) nif->skip(12); // Unknown @@ -680,12 +676,7 @@ namespace Nif mFloatKeyList = std::make_shared(); mFloatKeyList->read(nif); mVisKeyList = std::make_shared(); - mVisKeyList->mKeys.resize(nif->get()); - for (auto& [time, key] : mVisKeyList->mKeys) - { - nif->read(time); - key.mValue = nif->get() != 0; - } + nif->readVectorOfRecords(readKeyMapPair, mVisKeyList->mKeys); } void NiPSysCollider::read(NIFStream* nif) diff --git a/components/nif/physics.cpp b/components/nif/physics.cpp index f855edb30a..917c92a1de 100644 --- a/components/nif/physics.cpp +++ b/components/nif/physics.cpp @@ -555,11 +555,7 @@ namespace Nif if (nif->getVersion() >= NIFStream::generateVersion(10, 1, 0, 0)) nif->read(mScale); readRecordList(nif, mData); - uint32_t numFilters; - nif->read(numFilters); - mHavokFilters.resize(numFilters); - for (HavokFilter& filter : mHavokFilters) - filter.read(nif); + nif->readVectorOfRecords(mHavokFilters); } void bhkNiTriStripsShape::post(Reader& nif) diff --git a/components/nif/property.cpp b/components/nif/property.cpp index 00ffe9f14a..4768dce670 100644 --- a/components/nif/property.cpp +++ b/components/nif/property.cpp @@ -73,10 +73,12 @@ namespace Nif if (nif->getVersion() <= NIFStream::generateVersion(20, 1, 0, 1)) mApplyMode = static_cast(nif->get()); - mTextures.resize(nif->get()); - for (size_t i = 0; i < mTextures.size(); i++) + const uint32_t texturesSize = nif->get(); + + mTextures.reserve(texturesSize); + for (size_t i = 0; i < texturesSize; i++) { - mTextures[i].read(nif); + mTextures.emplace_back().read(nif); if (i == 5 && mTextures[5].mEnabled) { @@ -89,13 +91,16 @@ namespace Nif if (nif->getVersion() >= NIFStream::generateVersion(10, 0, 1, 0)) { - mShaderTextures.resize(nif->get()); - mShaderIds.resize(mShaderTextures.size()); - for (size_t i = 0; i < mShaderTextures.size(); i++) + const uint32_t sharedTexturesSize = nif->get(); + mShaderTextures.reserve(sharedTexturesSize); + mShaderIds.reserve(sharedTexturesSize); + for (size_t i = 0; i < sharedTexturesSize; i++) { - mShaderTextures[i].read(nif); + mShaderTextures.emplace_back().read(nif); + uint32_t id = 0; if (mShaderTextures[i].mEnabled) - nif->read(mShaderIds[i]); + nif->read(id); + mShaderIds.push_back(id); } } } @@ -346,9 +351,10 @@ namespace Nif mTranslucency.read(nif); if (nif->get() != 0) { - mTextureArrays.resize(nif->get()); - for (std::vector& textureArray : mTextureArrays) - nif->getSizedStrings(textureArray, nif->get()); + const uint32_t size = nif->get(); + mTextureArrays.reserve(size); + for (uint32_t i = 0; i < size; ++i) + nif->getSizedStrings(mTextureArrays.emplace_back(), nif->get()); } } if (nif->getBethVersion() >= NIFFile::BethVersion::BETHVER_STF) diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5ff7390c8..71e7bc97a5 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -160,16 +160,7 @@ namespace Nif template void readRecordList(NIFStream* nif, RecordListT& list) { - const std::uint32_t length = nif->get(); - - // No reasonable list can hit this generous limit - if (length >= (1 << 24)) - throw std::runtime_error("Record list too long: " + std::to_string(length)); - - list.resize(length); - - for (auto& value : list) - value.read(nif); + nif->readVectorOfRecords(list); } template