mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 04:20:29 +00:00
Merge branch 'whatdoesbtrevenmean' into 'master'
niftest: parse BTO, BTR, RDT and PSA files See merge request OpenMW/openmw!4376
This commit is contained in:
commit
834bd9bc6c
@ -25,29 +25,89 @@
|
|||||||
// Create local aliases for brevity
|
// Create local aliases for brevity
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
/// See if the file has the named extension
|
enum class FileType
|
||||||
bool hasExtension(const std::filesystem::path& filename, std::string_view extensionToFind)
|
|
||||||
{
|
{
|
||||||
const auto extension = Files::pathToUnicodeString(filename.extension());
|
BSA,
|
||||||
return Misc::StringUtils::ciEqual(extension, extensionToFind);
|
BA2,
|
||||||
|
BGEM,
|
||||||
|
BGSM,
|
||||||
|
NIF,
|
||||||
|
KF,
|
||||||
|
BTO,
|
||||||
|
BTR,
|
||||||
|
RDT,
|
||||||
|
PSA,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class FileClass
|
||||||
|
{
|
||||||
|
Archive,
|
||||||
|
Material,
|
||||||
|
NIF,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::pair<FileType, FileClass> classifyFile(const std::filesystem::path& filename)
|
||||||
|
{
|
||||||
|
const std::string extension = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(filename.extension()));
|
||||||
|
if (extension == ".bsa")
|
||||||
|
return { FileType::BSA, FileClass::Archive };
|
||||||
|
if (extension == ".ba2")
|
||||||
|
return { FileType::BA2, FileClass::Archive };
|
||||||
|
if (extension == ".bgem")
|
||||||
|
return { FileType::BGEM, FileClass::Material };
|
||||||
|
if (extension == ".bgsm")
|
||||||
|
return { FileType::BGSM, FileClass::Material };
|
||||||
|
if (extension == ".nif")
|
||||||
|
return { FileType::NIF, FileClass::NIF };
|
||||||
|
if (extension == ".kf")
|
||||||
|
return { FileType::KF, FileClass::NIF };
|
||||||
|
if (extension == ".bto")
|
||||||
|
return { FileType::BTO, FileClass::NIF };
|
||||||
|
if (extension == ".btr")
|
||||||
|
return { FileType::BTR, FileClass::NIF };
|
||||||
|
if (extension == ".rdt")
|
||||||
|
return { FileType::RDT, FileClass::NIF };
|
||||||
|
if (extension == ".psa")
|
||||||
|
return { FileType::PSA, FileClass::NIF };
|
||||||
|
|
||||||
|
return { FileType::Unknown, FileClass::Unknown };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See if the file has the "nif" extension.
|
std::string getFileTypeName(FileType fileType)
|
||||||
bool isNIF(const std::filesystem::path& filename)
|
|
||||||
{
|
{
|
||||||
return hasExtension(filename, ".nif") || hasExtension(filename, ".kf");
|
switch (fileType)
|
||||||
|
{
|
||||||
|
case FileType::BSA:
|
||||||
|
return "BSA";
|
||||||
|
case FileType::BA2:
|
||||||
|
return "BA2";
|
||||||
|
case FileType::BGEM:
|
||||||
|
return "BGEM";
|
||||||
|
case FileType::BGSM:
|
||||||
|
return "BGSM";
|
||||||
|
case FileType::NIF:
|
||||||
|
return "NIF";
|
||||||
|
case FileType::KF:
|
||||||
|
return "KF";
|
||||||
|
case FileType::BTO:
|
||||||
|
return "BTO";
|
||||||
|
case FileType::BTR:
|
||||||
|
return "BTR";
|
||||||
|
case FileType::RDT:
|
||||||
|
return "RDT";
|
||||||
|
case FileType::PSA:
|
||||||
|
return "PSA";
|
||||||
|
case FileType::Unknown:
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the file is a material file.
|
bool isBSA(const std::filesystem::path& path)
|
||||||
bool isMaterial(const std::filesystem::path& filename)
|
|
||||||
{
|
{
|
||||||
return hasExtension(filename, ".bgem") || hasExtension(filename, ".bgsm");
|
return classifyFile(path).second == FileClass::Archive;
|
||||||
}
|
|
||||||
|
|
||||||
/// See if the file has the "bsa" extension.
|
|
||||||
bool isBSA(const std::filesystem::path& filename)
|
|
||||||
{
|
|
||||||
return hasExtension(filename, ".bsa") || hasExtension(filename, ".ba2");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
@ -59,17 +119,17 @@ std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readFile(
|
bool readFile(
|
||||||
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
||||||
{
|
{
|
||||||
|
const auto [fileType, fileClass] = classifyFile(path);
|
||||||
|
if (fileClass != FileClass::NIF && fileClass != FileClass::Material)
|
||||||
|
return false;
|
||||||
|
|
||||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
const bool isNif = isNIF(path);
|
|
||||||
if (!quiet)
|
if (!quiet)
|
||||||
{
|
{
|
||||||
if (isNif)
|
std::cout << "Reading " << getFileTypeName(fileType) << " file '" << pathStr << "'";
|
||||||
std::cout << "Reading " << (hasExtension(path, ".nif") ? "NIF" : "KF") << " file '" << pathStr << "'";
|
|
||||||
else
|
|
||||||
std::cout << "Reading " << (hasExtension(path, ".bgsm") ? "BGSM" : "BGEM") << " file '" << pathStr << "'";
|
|
||||||
if (!source.empty())
|
if (!source.empty())
|
||||||
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
@ -77,27 +137,35 @@ void readFile(
|
|||||||
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
const std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (isNif)
|
switch (fileClass)
|
||||||
{
|
{
|
||||||
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
case FileClass::NIF:
|
||||||
Nif::Reader reader(file, nullptr);
|
{
|
||||||
if (vfs != nullptr)
|
Nif::NIFFile file(Files::pathToUnicodeString(fullPath));
|
||||||
reader.parse(vfs->get(pathStr));
|
Nif::Reader reader(file, nullptr);
|
||||||
else
|
if (vfs != nullptr)
|
||||||
reader.parse(Files::openConstrainedFileStream(fullPath));
|
reader.parse(vfs->get(pathStr));
|
||||||
}
|
else
|
||||||
else
|
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||||
{
|
break;
|
||||||
if (vfs != nullptr)
|
}
|
||||||
Bgsm::parse(vfs->get(pathStr));
|
case FileClass::Material:
|
||||||
else
|
{
|
||||||
Bgsm::parse(Files::openConstrainedFileStream(fullPath));
|
if (vfs != nullptr)
|
||||||
|
Bgsm::parse(vfs->get(pathStr));
|
||||||
|
else
|
||||||
|
Bgsm::parse(Files::openConstrainedFileStream(fullPath));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "Failed to read '" << pathStr << "':" << std::endl << e.what() << std::endl;
|
std::cerr << "Failed to read '" << pathStr << "':" << std::endl << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check all the nif files in a given VFS::Archive
|
/// Check all the nif files in a given VFS::Archive
|
||||||
@ -116,10 +184,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
|||||||
|
|
||||||
for (const auto& name : vfs.getRecursiveDirectoryIterator())
|
for (const auto& name : vfs.getRecursiveDirectoryIterator())
|
||||||
{
|
{
|
||||||
if (isNIF(name.value()) || isMaterial(name.value()))
|
readFile(archivePath, name.value(), &vfs, quiet);
|
||||||
{
|
|
||||||
readFile(archivePath, name.value(), &vfs, quiet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!archivePath.empty() && !isBSA(archivePath))
|
if (!archivePath.empty() && !isBSA(archivePath))
|
||||||
@ -148,10 +213,11 @@ void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::pat
|
|||||||
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
||||||
bool& writeDebugLog, bool& quiet)
|
bool& writeDebugLog, bool& quiet)
|
||||||
{
|
{
|
||||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF, KF, BGEM/BGSM and BSA/BA2 files
|
bpo::options_description desc(
|
||||||
|
R"(Ensure that OpenMW can use the provided NIF, KF, BTO/BTR, RDT, PSA, BGEM/BGSM and BSA/BA2 files
|
||||||
|
|
||||||
Usages:
|
Usages:
|
||||||
niftest <nif files, kf files, bgem/bgsm files, BSA/BA2 files, or directories>
|
niftest <nif files, kf files, bto/btr files, rdt files, psa files, bgem/bgsm files, BSA/BA2 files, or directories>
|
||||||
Scan the file or directories for NIF errors.
|
Scan the file or directories for NIF errors.
|
||||||
|
|
||||||
Allowed options)");
|
Allowed options)");
|
||||||
@ -240,18 +306,18 @@ int main(int argc, char** argv)
|
|||||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (isNIF(path) || isMaterial(path))
|
const bool isFile = readFile({}, path, vfs.get(), quiet);
|
||||||
|
if (!isFile)
|
||||||
{
|
{
|
||||||
readFile({}, path, vfs.get(), quiet);
|
if (auto archive = makeArchive(path))
|
||||||
}
|
{
|
||||||
else if (auto archive = makeArchive(path))
|
readVFS(std::move(archive), path, quiet);
|
||||||
{
|
}
|
||||||
readVFS(std::move(archive), path, quiet);
|
else
|
||||||
}
|
{
|
||||||
else
|
std::cerr << "Error: '" << pathStr << "' is not a NIF file, material file, archive, or directory"
|
||||||
{
|
<< std::endl;
|
||||||
std::cerr << "Error: '" << pathStr << "' is not a NIF/KF/BGEM/BGSM file, BSA/BA2 archive, or directory"
|
}
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user