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:
parent
91ccb0fe8d
commit
c388fda5e4
5 changed files with 51 additions and 35 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue