1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-10-15 15:26:38 +00:00

Handle empty file name in BSA

This commit is contained in:
elsid 2025-09-19 11:50:10 +02:00
parent 91ccb0fe8d
commit c388fda5e4
No known key found for this signature in database
GPG key ID: B845CB9FEE18AB40
5 changed files with 51 additions and 35 deletions

View file

@ -135,11 +135,12 @@ namespace Bsa
std::vector<char> fileName;
uint16_t fileNameSize;
input.read(reinterpret_cast<char*>(&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;

View file

@ -126,11 +126,12 @@ namespace Bsa
std::vector<char> fileName;
uint16_t fileNameSize;
input.read(reinterpret_cast<char*>(&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;

View file

@ -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<uint32_t>(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<uint32_t>(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<const char*>(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<uint32_t>(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<uint32_t>(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<uint32_t>(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;

View file

@ -62,12 +62,6 @@ namespace Bsa
/// Represents one file entry in the archive
struct FileStruct
{
void setNameInfos(size_t index, std::vector<char>* stringBuf)
{
mNameOffset = static_cast<uint32_t>(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<char>* mNamesBuffer = nullptr;
};
typedef std::vector<FileStruct> FileList;

View file

@ -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<uint32_t>(fileRec.mName.size() - 1);
fileStruct.mNamesBuffer = &fileRec.mName;
mFiles.emplace_back(fileStruct);
}
}