|
|
|
@ -6,7 +6,8 @@
|
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
|
#include <boost/filesystem/fstream.hpp>
|
|
|
|
|
|
|
|
|
|
#include <components/bsa/bsa_file.hpp>
|
|
|
|
|
#include <components/bsa/compressedbsafile.hpp>
|
|
|
|
|
#include <components/misc/stringops.hpp>
|
|
|
|
|
|
|
|
|
|
#define BSATOOL_VERSION 1.1
|
|
|
|
|
|
|
|
|
@ -25,16 +26,6 @@ struct Arguments
|
|
|
|
|
bool fullpath;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void replaceAll(std::string& str, const std::string& needle, const std::string& substitute)
|
|
|
|
|
{
|
|
|
|
|
size_t pos = str.find(needle);
|
|
|
|
|
while(pos != std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
str.replace(pos, needle.size(), substitute);
|
|
|
|
|
pos = str.find(needle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool parseOptions (int argc, char** argv, Arguments &info)
|
|
|
|
|
{
|
|
|
|
|
bpo::options_description desc("Inspect and extract files from Bethesda BSA archives\n\n"
|
|
|
|
@ -144,9 +135,9 @@ bool parseOptions (int argc, char** argv, Arguments &info)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int list(Bsa::BSAFile& bsa, Arguments& info);
|
|
|
|
|
int extract(Bsa::BSAFile& bsa, Arguments& info);
|
|
|
|
|
int extractAll(Bsa::BSAFile& bsa, Arguments& info);
|
|
|
|
|
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
|
|
|
|
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
|
|
|
|
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info);
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
|
{
|
|
|
|
@ -157,8 +148,16 @@ int main(int argc, char** argv)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
// Open file
|
|
|
|
|
Bsa::BSAFile bsa;
|
|
|
|
|
bsa.open(info.filename);
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
bsa->open(info.filename);
|
|
|
|
|
|
|
|
|
|
if (info.mode == "list")
|
|
|
|
|
return list(bsa, info);
|
|
|
|
@ -179,10 +178,10 @@ int main(int argc, char** argv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int list(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
int list(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|
|
|
|
{
|
|
|
|
|
// List all files
|
|
|
|
|
const Bsa::BSAFile::FileList &files = bsa.getList();
|
|
|
|
|
const Bsa::BSAFile::FileList &files = bsa->getList();
|
|
|
|
|
for (const auto& file : files)
|
|
|
|
|
{
|
|
|
|
|
if(info.longformat)
|
|
|
|
@ -201,15 +200,15 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int extract(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
int extract(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|
|
|
|
{
|
|
|
|
|
std::string archivePath = info.extractfile;
|
|
|
|
|
replaceAll(archivePath, "/", "\\");
|
|
|
|
|
Misc::StringUtils::replaceAll(archivePath, "/", "\\");
|
|
|
|
|
|
|
|
|
|
std::string extractPath = info.extractfile;
|
|
|
|
|
replaceAll(extractPath, "\\", "/");
|
|
|
|
|
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
|
|
|
|
|
|
|
|
|
if (!bsa.exists(archivePath.c_str()))
|
|
|
|
|
if (!bsa->exists(archivePath.c_str()))
|
|
|
|
|
{
|
|
|
|
|
std::cout << "ERROR: file '" << archivePath << "' not found\n";
|
|
|
|
|
std::cout << "In archive: " << info.filename << std::endl;
|
|
|
|
@ -237,7 +236,7 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get a stream for the file to extract
|
|
|
|
|
Files::IStreamPtr stream = bsa.getFile(archivePath.c_str());
|
|
|
|
|
Files::IStreamPtr stream = bsa->getFile(archivePath.c_str());
|
|
|
|
|
|
|
|
|
|
bfs::ofstream out(target, std::ios::binary);
|
|
|
|
|
|
|
|
|
@ -250,12 +249,12 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
int extractAll(std::unique_ptr<Bsa::BSAFile>& bsa, Arguments& info)
|
|
|
|
|
{
|
|
|
|
|
for (const auto &file : bsa.getList())
|
|
|
|
|
for (const auto &file : bsa->getList())
|
|
|
|
|
{
|
|
|
|
|
std::string extractPath(file.name);
|
|
|
|
|
replaceAll(extractPath, "\\", "/");
|
|
|
|
|
Misc::StringUtils::replaceAll(extractPath, "\\", "/");
|
|
|
|
|
|
|
|
|
|
// Get the target path (the path the file will be extracted to)
|
|
|
|
|
bfs::path target (info.outdir);
|
|
|
|
@ -273,7 +272,7 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
|
|
|
|
|
|
|
|
|
// Get a stream for the file to extract
|
|
|
|
|
// (inefficient because getFile iter on the list again)
|
|
|
|
|
Files::IStreamPtr data = bsa.getFile(file.name);
|
|
|
|
|
Files::IStreamPtr data = bsa->getFile(file.name);
|
|
|
|
|
bfs::ofstream out(target, std::ios::binary);
|
|
|
|
|
|
|
|
|
|
// Write the file to disk
|
|
|
|
|