Allow loading arbitrary NIF files

This commit is contained in:
Alexei Dobrohotov 2020-11-07 02:05:16 +03:00
parent f6b43b9321
commit 7e63afdecf
4 changed files with 73 additions and 3 deletions

View file

@ -1,9 +1,12 @@
#include "niffile.hpp"
#include "effect.hpp"
#include <array>
#include <map>
#include <sstream>
#include <components/settings/settings.hpp>
namespace Nif
{
@ -137,15 +140,46 @@ void NIFFile::parse(Files::IStreamPtr stream)
// Check the header string
std::string head = nif.getVersionString();
if(head.compare(0, 22, "NetImmerse File Format") != 0)
static const std::array<std::string, 2> verStrings =
{
"NetImmerse File Format",
"Gamebryo File Format"
};
bool supported = false;
for (const std::string& verString : verStrings)
{
supported = (head.compare(0, verString.size(), verString) == 0);
if (supported)
break;
}
if (!supported)
fail("Invalid NIF header: " + head);
supported = false;
// Get BCD version
ver = nif.getUInt();
// 4.0.0.0 is an older, practically identical version of the format.
// It's not used by Morrowind assets but Morrowind supports it.
if(ver != NIFStream::generateVersion(4,0,0,0) && ver != VER_MW)
fail("Unsupported NIF version: " + printVersion(ver));
static const std::array<uint32_t, 2> supportedVers =
{
NIFStream::generateVersion(4,0,0,0),
VER_MW
};
for (uint32_t supportedVer : supportedVers)
{
supported = (ver == supportedVer);
if (supported)
break;
}
if (!supported)
{
static const bool ignoreUnsupported = Settings::Manager::getBool("load unsupported nif files", "Models");
if (ignoreUnsupported)
warn("Unsupported NIF version: " + printVersion(ver) + ". Proceed with caution!");
else
fail("Unsupported NIF version: " + printVersion(ver));
}
// NIF data endianness
if (ver >= NIFStream::generateVersion(20,0,0,4))
@ -245,6 +279,9 @@ void NIFFile::parse(Files::IStreamPtr stream)
else
fail("Unknown record type " + rec);
if (!supported)
Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")";
assert(r != nullptr);
assert(r->recType != RC_MISSING);
r->recName = rec;