mirror of
https://github.com/OpenMW/openmw.git
synced 2025-10-16 03:16:33 +00:00
Handle empty file name in BSA
This commit is contained in:
parent
91ccb0fe8d
commit
c388fda5e4
5 changed files with 51 additions and 35 deletions
|
@ -135,11 +135,12 @@ namespace Bsa
|
||||||
std::vector<char> fileName;
|
std::vector<char> fileName;
|
||||||
uint16_t fileNameSize;
|
uint16_t fileNameSize;
|
||||||
input.read(reinterpret_cast<char*>(&fileNameSize), sizeof(uint16_t));
|
input.read(reinterpret_cast<char*>(&fileNameSize), sizeof(uint16_t));
|
||||||
fileName.resize(fileNameSize);
|
fileName.resize(fileNameSize + 1);
|
||||||
input.read(fileName.data(), fileName.size());
|
input.read(fileName.data(), fileNameSize);
|
||||||
fileName.push_back('\0');
|
|
||||||
mFileNames.push_back(std::move(fileName));
|
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;
|
mIsLoaded = true;
|
||||||
|
|
|
@ -126,11 +126,12 @@ namespace Bsa
|
||||||
std::vector<char> fileName;
|
std::vector<char> fileName;
|
||||||
uint16_t fileNameSize;
|
uint16_t fileNameSize;
|
||||||
input.read(reinterpret_cast<char*>(&fileNameSize), sizeof(uint16_t));
|
input.read(reinterpret_cast<char*>(&fileNameSize), sizeof(uint16_t));
|
||||||
fileName.resize(fileNameSize);
|
fileName.resize(fileNameSize + 1);
|
||||||
input.read(fileName.data(), fileName.size());
|
input.read(fileName.data(), fileNameSize);
|
||||||
fileName.push_back('\0');
|
|
||||||
mFileNames.push_back(std::move(fileName));
|
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;
|
mIsLoaded = true;
|
||||||
|
|
|
@ -166,27 +166,35 @@ void BSAFile::readHeader()
|
||||||
for (size_t i = 0; i < filenum; i++)
|
for (size_t i = 0; i < filenum; i++)
|
||||||
{
|
{
|
||||||
FileStruct& fs = mFiles[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())
|
const uint32_t fileSize = offsets[i * 2];
|
||||||
{
|
const uint32_t offset = offsets[i * 2 + 1] + static_cast<uint32_t>(fileDataOffset);
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
endOfNameBuffer = std::max(endOfNameBuffer, namesOffset + std::strlen(fs.name()) + 1);
|
if (fileSize + offset > fsize)
|
||||||
assert(endOfNameBuffer <= mStringBuf.size());
|
|
||||||
|
|
||||||
if (fs.mOffset + fs.mFileSize > fsize)
|
|
||||||
fail("Archive contains offsets outside itself");
|
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);
|
mStringBuf.resize(endOfNameBuffer);
|
||||||
|
|
||||||
|
@ -282,7 +290,6 @@ void Bsa::BSAFile::addFile(const std::string& filename, std::istream& file)
|
||||||
FileStruct newFile;
|
FileStruct newFile;
|
||||||
file.seekg(0, std::ios::end);
|
file.seekg(0, std::ios::end);
|
||||||
newFile.mFileSize = static_cast<uint32_t>(file.tellg());
|
newFile.mFileSize = static_cast<uint32_t>(file.tellg());
|
||||||
newFile.setNameInfos(mStringBuf.size(), &mStringBuf);
|
|
||||||
newFile.mHash = getHash(filename);
|
newFile.mHash = getHash(filename);
|
||||||
|
|
||||||
if (mFiles.empty())
|
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.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.insert(mStringBuf.end(), filename.begin(), filename.end());
|
||||||
mStringBuf.push_back('\0');
|
mStringBuf.push_back('\0');
|
||||||
|
|
||||||
mFiles.push_back(newFile);
|
mFiles.push_back(newFile);
|
||||||
|
|
||||||
mHasChanged = true;
|
mHasChanged = true;
|
||||||
|
|
|
@ -62,12 +62,6 @@ namespace Bsa
|
||||||
/// Represents one file entry in the archive
|
/// Represents one file entry in the archive
|
||||||
struct FileStruct
|
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
|
// File size and offset in file. We store the offset from the
|
||||||
// beginning of the file, not the offset into the data buffer
|
// beginning of the file, not the offset into the data buffer
|
||||||
// (which is what is stored in the archive.)
|
// (which is what is stored in the archive.)
|
||||||
|
@ -76,9 +70,15 @@ namespace Bsa
|
||||||
Hash mHash{};
|
Hash mHash{};
|
||||||
|
|
||||||
// Zero-terminated file name
|
// 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 mNameOffset = 0;
|
||||||
|
uint32_t mNameSize = 0;
|
||||||
std::vector<char>* mNamesBuffer = nullptr;
|
std::vector<char>* mNamesBuffer = nullptr;
|
||||||
};
|
};
|
||||||
typedef std::vector<FileStruct> FileList;
|
typedef std::vector<FileStruct> FileList;
|
||||||
|
|
|
@ -183,7 +183,9 @@ namespace Bsa
|
||||||
FileStruct fileStruct{};
|
FileStruct fileStruct{};
|
||||||
fileStruct.mFileSize = fileRec.mSize & (~FileSizeFlag_Compression);
|
fileStruct.mFileSize = fileRec.mSize & (~FileSizeFlag_Compression);
|
||||||
fileStruct.mOffset = fileRec.mOffset;
|
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);
|
mFiles.emplace_back(fileStruct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue