diff --git a/components/bsa/ba2dx10file.cpp b/components/bsa/ba2dx10file.cpp index d4f14926c6..b0d999d77e 100644 --- a/components/bsa/ba2dx10file.cpp +++ b/components/bsa/ba2dx10file.cpp @@ -135,11 +135,12 @@ namespace Bsa std::vector fileName; uint16_t fileNameSize; input.read(reinterpret_cast(&fileNameSize), sizeof(uint16_t)); - fileName.resize(fileNameSize); - input.read(fileName.data(), fileName.size()); - fileName.push_back('\0'); + fileName.resize(fileNameSize + 1); + input.read(fileName.data(), fileNameSize); mFileNames.push_back(std::move(fileName)); - mFiles[i].setNameInfos(0, &mFileNames.back()); + mFiles[i].mNameOffset = 0; + mFiles[i].mNameSize = fileNameSize; + mFiles[i].mNamesBuffer = &mFileNames.back(); } mIsLoaded = true; diff --git a/components/bsa/ba2gnrlfile.cpp b/components/bsa/ba2gnrlfile.cpp index 0ff6cd030c..4f77fba5f7 100644 --- a/components/bsa/ba2gnrlfile.cpp +++ b/components/bsa/ba2gnrlfile.cpp @@ -126,11 +126,12 @@ namespace Bsa std::vector fileName; uint16_t fileNameSize; input.read(reinterpret_cast(&fileNameSize), sizeof(uint16_t)); - fileName.resize(fileNameSize); - input.read(fileName.data(), fileName.size()); - fileName.push_back('\0'); + fileName.resize(fileNameSize + 1); + input.read(fileName.data(), fileNameSize); mFileNames.push_back(std::move(fileName)); - mFiles[i].setNameInfos(0, &mFileNames.back()); + mFiles[i].mNameOffset = 0; + mFiles[i].mNameSize = fileNameSize; + mFiles[i].mNamesBuffer = &mFileNames.back(); } mIsLoaded = true; diff --git a/components/bsa/bsafile.cpp b/components/bsa/bsafile.cpp index eaf4542338..0d871235be 100644 --- a/components/bsa/bsafile.cpp +++ b/components/bsa/bsafile.cpp @@ -166,27 +166,35 @@ void BSAFile::readHeader() for (size_t i = 0; i < filenum; i++) { FileStruct& fs = mFiles[i]; - fs.mFileSize = offsets[i * 2]; - fs.mOffset = static_cast(offsets[i * 2 + 1] + fileDataOffset); - auto namesOffset = offsets[2 * filenum + i]; - fs.setNameInfos(namesOffset, &mStringBuf); - fs.mHash = hashes[i]; - if (namesOffset >= mStringBuf.size()) - { - fail("Archive contains names offset outside itself"); - } - const void* end = std::memchr(fs.name(), '\0', mStringBuf.size() - namesOffset); - if (!end) - { - fail("Archive contains non-zero terminated string"); - } + const uint32_t fileSize = offsets[i * 2]; + const uint32_t offset = offsets[i * 2 + 1] + static_cast(fileDataOffset); - endOfNameBuffer = std::max(endOfNameBuffer, namesOffset + std::strlen(fs.name()) + 1); - assert(endOfNameBuffer <= mStringBuf.size()); - - if (fs.mOffset + fs.mFileSize > fsize) + if (fileSize + offset > fsize) fail("Archive contains offsets outside itself"); + + const uint32_t nameOffset = offsets[2 * filenum + i]; + + if (nameOffset >= mStringBuf.size()) + fail("Archive contains names offset outside itself"); + + const char* const begin = mStringBuf.data() + nameOffset; + const char* const end = reinterpret_cast(std::memchr(begin, '\0', mStringBuf.size() - nameOffset)); + + if (end == nullptr) + fail("Archive contains non-zero terminated string"); + + const std::size_t nameSize = end - begin; + + fs.mFileSize = fileSize; + fs.mOffset = offset; + fs.mHash = hashes[i]; + fs.mNameOffset = nameOffset; + fs.mNameSize = static_cast(nameSize); + fs.mNamesBuffer = &mStringBuf; + + endOfNameBuffer = std::max(endOfNameBuffer, nameOffset + nameSize + 1); + assert(endOfNameBuffer <= mStringBuf.size()); } mStringBuf.resize(endOfNameBuffer); @@ -282,7 +290,6 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) FileStruct newFile; file.seekg(0, std::ios::end); newFile.mFileSize = static_cast(file.tellg()); - newFile.setNameInfos(mStringBuf.size(), &mStringBuf); newFile.mHash = getHash(filename); if (mFiles.empty()) @@ -310,8 +317,13 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file) newFile.mOffset = static_cast(stream.tellp()); } + newFile.mNameOffset = mStringBuf.size(); + newFile.mNameSize = filename.size(); + newFile.mNamesBuffer = &mStringBuf; + mStringBuf.insert(mStringBuf.end(), filename.begin(), filename.end()); mStringBuf.push_back('\0'); + mFiles.push_back(newFile); mHasChanged = true; diff --git a/components/bsa/bsafile.hpp b/components/bsa/bsafile.hpp index 20e3180533..af7d101eb0 100644 --- a/components/bsa/bsafile.hpp +++ b/components/bsa/bsafile.hpp @@ -62,12 +62,6 @@ namespace Bsa /// Represents one file entry in the archive struct FileStruct { - void setNameInfos(size_t index, std::vector* stringBuf) - { - mNameOffset = static_cast(index); - mNamesBuffer = stringBuf; - } - // File size and offset in file. We store the offset from the // beginning of the file, not the offset into the data buffer // (which is what is stored in the archive.) @@ -76,9 +70,15 @@ namespace Bsa Hash mHash{}; // Zero-terminated file name - const char* name() const { return &(*mNamesBuffer)[mNameOffset]; } + const char* name() const + { + if (mNameSize == 0) + return ""; + return mNamesBuffer->data() + mNameOffset; + } uint32_t mNameOffset = 0; + uint32_t mNameSize = 0; std::vector* mNamesBuffer = nullptr; }; typedef std::vector FileList; diff --git a/components/bsa/compressedbsafile.cpp b/components/bsa/compressedbsafile.cpp index e9005f327d..cbcb6aeeab 100644 --- a/components/bsa/compressedbsafile.cpp +++ b/components/bsa/compressedbsafile.cpp @@ -183,7 +183,9 @@ namespace Bsa FileStruct fileStruct{}; fileStruct.mFileSize = fileRec.mSize & (~FileSizeFlag_Compression); fileStruct.mOffset = fileRec.mOffset; - fileStruct.setNameInfos(0, &fileRec.mName); + fileStruct.mNameOffset = 0; + fileStruct.mNameSize = fileRec.mName.empty() ? 0 : static_cast(fileRec.mName.size() - 1); + fileStruct.mNamesBuffer = &fileRec.mName; mFiles.emplace_back(fileStruct); } }