.meta files (#449)

* start refactoring, legacy load still working

* account for path in meta file

* meta

* clang format

* move addfile

* more cleanup
This commit is contained in:
briaguya
2024-02-19 14:40:21 -05:00
committed by GitHub
parent 18ebff9333
commit 0ea6b6d79c
6 changed files with 114 additions and 66 deletions
+104 -35
View File
@@ -8,6 +8,7 @@
#include "resource/ResourceLoader.h"
#include "utils/binarytools/MemoryStream.h"
#include <StrHash64.h>
#include <nlohmann/json.hpp>
// TODO: Delete me and find an implementation
// Comes from stormlib. May not be the most efficient, but it's also important to be consistent.
@@ -103,62 +104,130 @@ void Archive::SetGameVersion(uint32_t gameVersion) {
}
void Archive::AddFile(const std::string& filePath) {
if (filePath.length() > 5 && filePath.substr(filePath.length() - 5) == ".meta") {
AddFile(filePath.substr(0, filePath.length() - 5));
return;
}
(*mHashes)[CRC64(filePath.c_str())] = filePath;
}
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath) {
auto fileToLoad = LoadFileRaw(filePath);
std::shared_ptr<ResourceInitData> Archive::ReadResourceInitData(const std::string& filePath,
std::shared_ptr<File> metaFileToLoad) {
auto initData = CreateDefaultResourceInitData();
// just using metaFileToLoad->Buffer->data() leads to garbage at the end
// that causes nlohmann to fail parsing, following the pattern used for
// xml resolves that issue
auto stream = std::make_shared<MemoryStream>(metaFileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);
auto parsed = nlohmann::json::parse(binaryReader->ReadCString());
if (parsed.contains("path")) {
initData->Path = parsed["path"];
} else {
initData->Path = filePath;
}
auto formatString = parsed["format"];
if (formatString == "XML") {
initData->Format = RESOURCE_FORMAT_XML;
}
initData->Type = Context::GetInstance()->GetResourceManager()->GetResourceLoader()->GetResourceType(parsed["type"]);
initData->ResourceVersion = parsed["version"];
return initData;
}
std::shared_ptr<ResourceInitData> Archive::ReadResourceInitDataLegacy(const std::string& filePath,
std::shared_ptr<File> fileToLoad) {
// Determine if file is binary or XML...
if (fileToLoad->Buffer->at(0) == '<') {
// File is XML
// Read the xml document
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);
fileToLoad->Reader = std::make_shared<tinyxml2::XMLDocument>();
auto xmlReader = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(fileToLoad->Reader);
auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();
xmlReader->Parse(binaryReader->ReadCString().data());
if (xmlReader->Error()) {
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", filePath, xmlReader->ErrorStr());
return nullptr;
}
fileToLoad->InitData = ReadResourceInitDataXml(filePath, xmlReader);
return ReadResourceInitDataXml(filePath, xmlReader);
} else {
// File is Binary
auto fileToLoadMeta = LoadFileMeta(filePath);
auto headerBuffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(),
fileToLoad->Buffer->begin() + OTR_HEADER_SIZE);
// Split out the header for reading.
if (fileToLoadMeta != nullptr) {
fileToLoad->Buffer =
std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(), fileToLoad->Buffer->end());
} else {
auto headerBuffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin(),
fileToLoad->Buffer->begin() + OTR_HEADER_SIZE);
if (headerBuffer->size() < OTR_HEADER_SIZE) {
SPDLOG_ERROR("Failed to parse ResourceInitData, buffer size too small. File: {}. Got {} bytes and "
"needed {} bytes.",
filePath, headerBuffer->size(), OTR_HEADER_SIZE);
return nullptr;
}
fileToLoad->Buffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE,
fileToLoad->Buffer->end());
// Create a reader for the header buffer
auto headerStream = std::make_shared<MemoryStream>(headerBuffer);
auto headerReader = std::make_shared<BinaryReader>(headerStream);
fileToLoadMeta = ReadResourceInitDataBinary(filePath, headerReader);
if (headerBuffer->size() < OTR_HEADER_SIZE) {
SPDLOG_ERROR("Failed to parse ResourceInitData, buffer size too small. File: {}. Got {} bytes and "
"needed {} bytes.",
filePath, headerBuffer->size(), OTR_HEADER_SIZE);
return nullptr;
}
// Create a reader for the data buffer
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
fileToLoad->Reader = std::make_shared<BinaryReader>(stream);
// Factories expect the buffer to not include the header,
// so we need to remove it from the buffer on the file
fileToLoad->Buffer = std::make_shared<std::vector<char>>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE,
fileToLoad->Buffer->end());
fileToLoad->InitData = fileToLoadMeta;
auto binaryReader = std::get<std::shared_ptr<BinaryReader>>(fileToLoad->Reader);
binaryReader->SetEndianness(fileToLoad->InitData->ByteOrder);
// Create a reader for the header buffer
auto headerStream = std::make_shared<MemoryStream>(headerBuffer);
auto headerReader = std::make_shared<BinaryReader>(headerStream);
return ReadResourceInitDataBinary(filePath, headerReader);
}
}
std::shared_ptr<BinaryReader> Archive::CreateBinaryReader(std::shared_ptr<File> fileToLoad) {
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto reader = std::make_shared<BinaryReader>(stream);
reader->SetEndianness(fileToLoad->InitData->ByteOrder);
return reader;
}
std::shared_ptr<tinyxml2::XMLDocument> Archive::CreateXMLReader(std::shared_ptr<File> fileToLoad) {
auto stream = std::make_shared<MemoryStream>(fileToLoad->Buffer);
auto binaryReader = std::make_shared<BinaryReader>(stream);
auto xmlReader = std::make_shared<tinyxml2::XMLDocument>();
xmlReader->Parse(binaryReader->ReadCString().data());
if (xmlReader->Error()) {
SPDLOG_ERROR("Failed to parse XML file {}. Error: {}", fileToLoad->InitData->Path, xmlReader->ErrorStr());
return nullptr;
}
return xmlReader;
}
std::shared_ptr<File> Archive::LoadFile(const std::string& filePath) {
auto metaFilePath = filePath + ".meta";
auto metaFileToLoad = LoadFileRaw(metaFilePath);
std::shared_ptr<File> fileToLoad = nullptr;
if (metaFileToLoad != nullptr) {
auto initData = ReadResourceInitData(filePath, metaFileToLoad);
fileToLoad = LoadFileRaw(initData->Path);
fileToLoad->InitData = initData;
} else {
fileToLoad = LoadFileRaw(filePath);
fileToLoad->InitData = ReadResourceInitDataLegacy(filePath, fileToLoad);
}
if (fileToLoad == nullptr) {
SPDLOG_ERROR("Failed to load file at path {}.", filePath);
return nullptr;
}
switch (fileToLoad->InitData->Format) {
case RESOURCE_FORMAT_BINARY:
fileToLoad->Reader = CreateBinaryReader(fileToLoad);
break;
case RESOURCE_FORMAT_XML:
fileToLoad->Reader = CreateXMLReader(fileToLoad);
break;
}
return fileToLoad;
+10 -7
View File
@@ -40,19 +40,22 @@ class Archive {
virtual std::shared_ptr<File> LoadFileRaw(uint64_t hash) = 0;
protected:
static std::shared_ptr<ResourceInitData> ReadResourceInitDataBinary(const std::string& filePath,
std::shared_ptr<BinaryReader> headerReader);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataXml(const std::string& filePath,
std::shared_ptr<tinyxml2::XMLDocument> document);
virtual std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath) = 0;
virtual std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash) = 0;
void SetLoaded(bool isLoaded);
void SetGameVersion(uint32_t gameVersion);
void AddFile(const std::string& filePath);
private:
static std::shared_ptr<ResourceInitData> CreateDefaultResourceInitData();
std::shared_ptr<ResourceInitData> ReadResourceInitData(const std::string& filePath,
std::shared_ptr<File> metaFileToLoad);
std::shared_ptr<ResourceInitData> ReadResourceInitDataLegacy(const std::string& filePath,
std::shared_ptr<File> fileToLoad);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataBinary(const std::string& filePath,
std::shared_ptr<BinaryReader> headerReader);
static std::shared_ptr<ResourceInitData> ReadResourceInitDataXml(const std::string& filePath,
std::shared_ptr<tinyxml2::XMLDocument> document);
std::shared_ptr<BinaryReader> CreateBinaryReader(std::shared_ptr<File> fileToLoad);
std::shared_ptr<tinyxml2::XMLDocument> CreateXMLReader(std::shared_ptr<File> fileToLoad);
bool mIsLoaded;
bool mHasGameVersion;
-10
View File
@@ -18,16 +18,6 @@ std::shared_ptr<File> O2rArchive::LoadFileRaw(const std::string& filePath) {
return nullptr;
}
std::shared_ptr<ResourceInitData> O2rArchive::LoadFileMeta(const std::string& filePath) {
// Search for file with .meta postfix.
// If exists, return a ResourceInitData with that data parsed out. Else return a default ResourceInitData
return nullptr;
}
std::shared_ptr<ResourceInitData> O2rArchive::LoadFileMeta(uint64_t hash) {
return nullptr;
}
bool O2rArchive::LoadRaw() {
return false;
}
-3
View File
@@ -24,9 +24,6 @@ class O2rArchive : virtual public Archive {
std::shared_ptr<File> LoadFileRaw(uint64_t hash);
protected:
std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath);
std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash);
private:
};
} // namespace LUS
-8
View File
@@ -56,14 +56,6 @@ std::shared_ptr<File> OtrArchive::LoadFileRaw(uint64_t hash) {
return LoadFileRaw(filePath);
}
std::shared_ptr<ResourceInitData> OtrArchive::LoadFileMeta(const std::string& filePath) {
return nullptr;
}
std::shared_ptr<ResourceInitData> OtrArchive::LoadFileMeta(uint64_t hash) {
return nullptr;
}
bool OtrArchive::LoadRaw() {
const bool opened = SFileOpenArchive(GetPath().c_str(), 0, MPQ_OPEN_READ_ONLY, &mHandle);
if (opened) {
-3
View File
@@ -30,9 +30,6 @@ class OtrArchive : virtual public Archive {
std::shared_ptr<File> LoadFileRaw(uint64_t hash);
protected:
std::shared_ptr<ResourceInitData> LoadFileMeta(const std::string& filePath);
std::shared_ptr<ResourceInitData> LoadFileMeta(uint64_t hash);
private:
HANDLE mHandle;
};