1
0
Fork 0
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:
psi29a 2022-03-01 07:22:04 +00:00
commit 3558196098
6 changed files with 119 additions and 91 deletions

View file

@ -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;
}
}

View file

@ -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.

View file

@ -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);
}; };
} }

View 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)

View file

@ -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)
{ {

View file

@ -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;