mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 07:53:53 +00:00
Merge branch 'Newer-Bsa-formats-no-longer-load' into 'master'
#6651 Newer bsa formats no longer load Closes #6651 See merge request OpenMW/openmw!1703
This commit is contained in:
commit
3558196098
6 changed files with 119 additions and 91 deletions
|
@ -151,62 +151,11 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
template<typename File>
|
||||||
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
int list(std::unique_ptr<File>& bsa, Arguments& info)
|
||||||
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
|
||||||
int add(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Arguments info;
|
|
||||||
if(!parseOptions (argc, argv, info))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// Open file
|
|
||||||
std::unique_ptr<Bsa::BSAFile> bsa;
|
|
||||||
|
|
||||||
Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(info.filename);
|
|
||||||
|
|
||||||
if (bsaVersion == Bsa::BSAVER_COMPRESSED)
|
|
||||||
bsa = std::make_unique<Bsa::CompressedBSAFile>(Bsa::CompressedBSAFile());
|
|
||||||
else
|
|
||||||
bsa = std::make_unique<Bsa::BSAFile>(Bsa::BSAFile());
|
|
||||||
|
|
||||||
if (info.mode == "create")
|
|
||||||
{
|
|
||||||
bsa->open(info.filename);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bsa->open(info.filename);
|
|
||||||
|
|
||||||
if (info.mode == "list")
|
|
||||||
return list(bsa, info);
|
|
||||||
else if (info.mode == "extract")
|
|
||||||
return extract(bsa, info);
|
|
||||||
else if (info.mode == "extractall")
|
|
||||||
return extractAll(bsa, info);
|
|
||||||
else if (info.mode == "add")
|
|
||||||
return add(bsa, info);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (std::exception& e)
|
|
||||||
{
|
|
||||||
std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|
||||||
{
|
{
|
||||||
// List all files
|
// List all files
|
||||||
const Bsa::BSAFile::FileList &files = bsa->getList();
|
const auto &files = bsa->getList();
|
||||||
for (const auto& file : files)
|
for (const auto& file : files)
|
||||||
{
|
{
|
||||||
if(info.longformat)
|
if(info.longformat)
|
||||||
|
@ -225,7 +174,8 @@ int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
template<typename File>
|
||||||
|
int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
std::string archivePath = info.extractfile;
|
std::string archivePath = info.extractfile;
|
||||||
Misc::StringUtils::replaceAll(archivePath, "/", "\\");
|
Misc::StringUtils::replaceAll(archivePath, "/", "\\");
|
||||||
|
@ -281,7 +231,8 @@ int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
template<typename File>
|
||||||
|
int extractAll(std::unique_ptr<File>& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
for (const auto &file : bsa->getList())
|
for (const auto &file : bsa->getList())
|
||||||
{
|
{
|
||||||
|
@ -315,10 +266,62 @@ int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int add(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
template<typename File>
|
||||||
|
int add(std::unique_ptr<File>& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
boost::filesystem::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
|
boost::filesystem::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
|
||||||
bsa->addFile(info.addfile, stream);
|
bsa->addFile(info.addfile, stream);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename File>
|
||||||
|
int call(Arguments& info)
|
||||||
|
{
|
||||||
|
std::unique_ptr<File> bsa = std::make_unique<File>();
|
||||||
|
if (info.mode == "create")
|
||||||
|
{
|
||||||
|
bsa->open(info.filename);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bsa->open(info.filename);
|
||||||
|
|
||||||
|
if (info.mode == "list")
|
||||||
|
return list(bsa, info);
|
||||||
|
else if (info.mode == "extract")
|
||||||
|
return extract(bsa, info);
|
||||||
|
else if (info.mode == "extractall")
|
||||||
|
return extractAll(bsa, info);
|
||||||
|
else if (info.mode == "add")
|
||||||
|
return add(bsa, info);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Unsupported mode. That is not supposed to happen." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Arguments info;
|
||||||
|
if (!parseOptions(argc, argv, info))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Open file
|
||||||
|
|
||||||
|
Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(info.filename);
|
||||||
|
|
||||||
|
if (bsaVersion == Bsa::BSAVER_COMPRESSED)
|
||||||
|
return call<Bsa::CompressedBSAFile>(info);
|
||||||
|
else
|
||||||
|
return call<Bsa::BSAFile>(info);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "ERROR reading BSA archive\nDetails:\n" << e.what() << std::endl;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ public:
|
||||||
return Files::openConstrainedFileStream (mFilename.c_str (), file->offset, file->fileSize);
|
return Files::openConstrainedFileStream (mFilename.c_str (), file->offset, file->fileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void addFile(const std::string& filename, std::istream& file);
|
void addFile(const std::string& filename, std::istream& file);
|
||||||
|
|
||||||
/// Get a list of all files
|
/// Get a list of all files
|
||||||
/// @note Thread safe.
|
/// @note Thread safe.
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Bsa
|
||||||
BSAVER_COMPRESSED = 0x415342 //B, S, A
|
BSAVER_COMPRESSED = 0x415342 //B, S, A
|
||||||
};
|
};
|
||||||
|
|
||||||
class CompressedBSAFile : public BSAFile
|
class CompressedBSAFile : private BSAFile
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
//special marker for invalid records,
|
//special marker for invalid records,
|
||||||
|
@ -85,6 +85,10 @@ namespace Bsa
|
||||||
static std::uint64_t generateHash(std::string stem, std::string extension) ;
|
static std::uint64_t generateHash(std::string stem, std::string extension) ;
|
||||||
Files::IStreamPtr getFile(const FileRecord& fileRecord);
|
Files::IStreamPtr getFile(const FileRecord& fileRecord);
|
||||||
public:
|
public:
|
||||||
|
using BSAFile::open;
|
||||||
|
using BSAFile::getList;
|
||||||
|
using BSAFile::getFilename;
|
||||||
|
|
||||||
CompressedBSAFile();
|
CompressedBSAFile();
|
||||||
virtual ~CompressedBSAFile();
|
virtual ~CompressedBSAFile();
|
||||||
|
|
||||||
|
@ -96,7 +100,7 @@ namespace Bsa
|
||||||
|
|
||||||
Files::IStreamPtr getFile(const char* filePath);
|
Files::IStreamPtr getFile(const char* filePath);
|
||||||
Files::IStreamPtr getFile(const FileStruct* fileStruct);
|
Files::IStreamPtr getFile(const FileStruct* fileStruct);
|
||||||
void addFile(const std::string& filename, std::istream& file) override;
|
void addFile(const std::string& filename, std::istream& file);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Bsa
|
||||||
|
|
||||||
Memory buffer is freed once the class instance is destroyed.
|
Memory buffer is freed once the class instance is destroyed.
|
||||||
*/
|
*/
|
||||||
class MemoryInputStream : private std::vector<char>, public virtual Files::MemBuf, public std::istream {
|
class MemoryInputStream : private std::vector<char>, public Files::MemBuf, public std::istream {
|
||||||
public:
|
public:
|
||||||
explicit MemoryInputStream(size_t bufferSize)
|
explicit MemoryInputStream(size_t bufferSize)
|
||||||
: std::vector<char>(bufferSize)
|
: std::vector<char>(bufferSize)
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace VFS
|
||||||
|
|
||||||
BsaArchive::BsaArchive(const std::string &filename)
|
BsaArchive::BsaArchive(const std::string &filename)
|
||||||
{
|
{
|
||||||
mFile = std::make_unique<Bsa::BSAFile>(Bsa::BSAFile());
|
mFile = std::make_unique<Bsa::BSAFile>();
|
||||||
mFile->open(filename);
|
mFile->open(filename);
|
||||||
|
|
||||||
const Bsa::BSAFile::FileList &filelist = mFile->getList();
|
const Bsa::BSAFile::FileList &filelist = mFile->getList();
|
||||||
|
@ -53,31 +53,6 @@ std::string BsaArchive::getDescription() const
|
||||||
return std::string{"BSA: "} + mFile->getFilename();
|
return std::string{"BSA: "} + mFile->getFilename();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompressedBsaArchive::CompressedBsaArchive(const std::string &filename)
|
|
||||||
: BsaArchive()
|
|
||||||
{
|
|
||||||
mFile = std::make_unique<Bsa::BSAFile>(Bsa::CompressedBSAFile());
|
|
||||||
mFile->open(filename);
|
|
||||||
|
|
||||||
const Bsa::BSAFile::FileList &filelist = mFile->getList();
|
|
||||||
for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it)
|
|
||||||
{
|
|
||||||
mResources.emplace_back(&*it, mFile.get());
|
|
||||||
mCompressedResources.emplace_back(&*it, static_cast<Bsa::CompressedBSAFile*>(mFile.get()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CompressedBsaArchive::listResources(std::map<std::string, File *> &out, char (*normalize_function)(char))
|
|
||||||
{
|
|
||||||
for (std::vector<CompressedBsaArchiveFile>::iterator it = mCompressedResources.begin(); it != mCompressedResources.end(); ++it)
|
|
||||||
{
|
|
||||||
std::string ent = it->mInfo->name();
|
|
||||||
std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function);
|
|
||||||
|
|
||||||
out[ent] = &*it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------
|
||||||
|
|
||||||
BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa)
|
BsaArchiveFile::BsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::BSAFile* bsa)
|
||||||
|
@ -92,8 +67,50 @@ Files::IStreamPtr BsaArchiveFile::open()
|
||||||
return mFile->getFile(mInfo);
|
return mFile->getFile(mInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompressedBsaArchive::CompressedBsaArchive(const std::string &filename)
|
||||||
|
: Archive()
|
||||||
|
{
|
||||||
|
mCompressedFile = std::make_unique<Bsa::CompressedBSAFile>();
|
||||||
|
mCompressedFile->open(filename);
|
||||||
|
|
||||||
|
const Bsa::BSAFile::FileList &filelist = mCompressedFile->getList();
|
||||||
|
for(Bsa::BSAFile::FileList::const_iterator it = filelist.begin();it != filelist.end();++it)
|
||||||
|
{
|
||||||
|
mCompressedResources.emplace_back(&*it, mCompressedFile.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressedBsaArchive::listResources(std::map<std::string, File *> &out, char (*normalize_function)(char))
|
||||||
|
{
|
||||||
|
for (std::vector<CompressedBsaArchiveFile>::iterator it = mCompressedResources.begin(); it != mCompressedResources.end(); ++it)
|
||||||
|
{
|
||||||
|
std::string ent = it->mInfo->name();
|
||||||
|
std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function);
|
||||||
|
|
||||||
|
out[ent] = &*it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompressedBsaArchive::contains(const std::string& file, char (*normalize_function)(char)) const
|
||||||
|
{
|
||||||
|
for (const auto& it : mCompressedResources)
|
||||||
|
{
|
||||||
|
std::string ent = it.mInfo->name();
|
||||||
|
std::transform(ent.begin(), ent.end(), ent.begin(), normalize_function);
|
||||||
|
if(file == ent)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CompressedBsaArchive::getDescription() const
|
||||||
|
{
|
||||||
|
return std::string{"BSA: "} + mCompressedFile->getFilename();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CompressedBsaArchiveFile::CompressedBsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::CompressedBSAFile* bsa)
|
CompressedBsaArchiveFile::CompressedBsaArchiveFile(const Bsa::BSAFile::FileStruct *info, Bsa::CompressedBSAFile* bsa)
|
||||||
: BsaArchiveFile(info, bsa)
|
: mInfo(info)
|
||||||
, mCompressedFile(bsa)
|
, mCompressedFile(bsa)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,14 @@ namespace VFS
|
||||||
Bsa::BSAFile* mFile;
|
Bsa::BSAFile* mFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CompressedBsaArchiveFile : public BsaArchiveFile
|
class CompressedBsaArchiveFile : public File
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompressedBsaArchiveFile(const Bsa::BSAFile::FileStruct* info, Bsa::CompressedBSAFile* bsa);
|
CompressedBsaArchiveFile(const Bsa::BSAFile::FileStruct* info, Bsa::CompressedBSAFile* bsa);
|
||||||
|
|
||||||
Files::IStreamPtr open() override;
|
Files::IStreamPtr open() override;
|
||||||
|
|
||||||
|
const Bsa::BSAFile::FileStruct* mInfo;
|
||||||
Bsa::CompressedBSAFile* mCompressedFile;
|
Bsa::CompressedBSAFile* mCompressedFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,12 +46,14 @@ namespace VFS
|
||||||
std::vector<BsaArchiveFile> mResources;
|
std::vector<BsaArchiveFile> mResources;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CompressedBsaArchive : public BsaArchive
|
class CompressedBsaArchive : public Archive
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompressedBsaArchive(const std::string& filename);
|
CompressedBsaArchive(const std::string& filename);
|
||||||
void listResources(std::map<std::string, File*>& out, char (*normalize_function) (char)) override;
|
|
||||||
virtual ~CompressedBsaArchive() {}
|
virtual ~CompressedBsaArchive() {}
|
||||||
|
void listResources(std::map<std::string, File*>& out, char (*normalize_function) (char)) override;
|
||||||
|
bool contains(const std::string& file, char (*normalize_function) (char)) const override;
|
||||||
|
std::string getDescription() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Bsa::CompressedBSAFile> mCompressedFile;
|
std::unique_ptr<Bsa::CompressedBSAFile> mCompressedFile;
|
||||||
|
|
Loading…
Reference in a new issue