From 0ea6b6d79cb6a0aa89082f52f813593bebac210b Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Mon, 19 Feb 2024 14:40:21 -0500 Subject: [PATCH] `.meta` files (#449) * start refactoring, legacy load still working * account for path in meta file * meta * clang format * move addfile * more cleanup --- src/resource/archive/Archive.cpp | 139 +++++++++++++++++++++------- src/resource/archive/Archive.h | 17 ++-- src/resource/archive/O2rArchive.cpp | 10 -- src/resource/archive/O2rArchive.h | 3 - src/resource/archive/OtrArchive.cpp | 8 -- src/resource/archive/OtrArchive.h | 3 - 6 files changed, 114 insertions(+), 66 deletions(-) diff --git a/src/resource/archive/Archive.cpp b/src/resource/archive/Archive.cpp index ff25612..99d9096 100644 --- a/src/resource/archive/Archive.cpp +++ b/src/resource/archive/Archive.cpp @@ -8,6 +8,7 @@ #include "resource/ResourceLoader.h" #include "utils/binarytools/MemoryStream.h" #include +#include // 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 Archive::LoadFile(const std::string& filePath) { - auto fileToLoad = LoadFileRaw(filePath); +std::shared_ptr Archive::ReadResourceInitData(const std::string& filePath, + std::shared_ptr 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(metaFileToLoad->Buffer); + auto binaryReader = std::make_shared(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 Archive::ReadResourceInitDataLegacy(const std::string& filePath, + std::shared_ptr 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(fileToLoad->Buffer); auto binaryReader = std::make_shared(stream); - fileToLoad->Reader = std::make_shared(); - auto xmlReader = std::get>(fileToLoad->Reader); + + auto xmlReader = std::make_shared(); 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>(fileToLoad->Buffer->begin(), + fileToLoad->Buffer->begin() + OTR_HEADER_SIZE); - // Split out the header for reading. - if (fileToLoadMeta != nullptr) { - fileToLoad->Buffer = - std::make_shared>(fileToLoad->Buffer->begin(), fileToLoad->Buffer->end()); - } else { - auto headerBuffer = std::make_shared>(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>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE, - fileToLoad->Buffer->end()); - - // Create a reader for the header buffer - auto headerStream = std::make_shared(headerBuffer); - auto headerReader = std::make_shared(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(fileToLoad->Buffer); - fileToLoad->Reader = std::make_shared(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>(fileToLoad->Buffer->begin() + OTR_HEADER_SIZE, + fileToLoad->Buffer->end()); - fileToLoad->InitData = fileToLoadMeta; - auto binaryReader = std::get>(fileToLoad->Reader); - binaryReader->SetEndianness(fileToLoad->InitData->ByteOrder); + // Create a reader for the header buffer + auto headerStream = std::make_shared(headerBuffer); + auto headerReader = std::make_shared(headerStream); + return ReadResourceInitDataBinary(filePath, headerReader); + } +} + +std::shared_ptr Archive::CreateBinaryReader(std::shared_ptr fileToLoad) { + auto stream = std::make_shared(fileToLoad->Buffer); + auto reader = std::make_shared(stream); + reader->SetEndianness(fileToLoad->InitData->ByteOrder); + return reader; +} + +std::shared_ptr Archive::CreateXMLReader(std::shared_ptr fileToLoad) { + auto stream = std::make_shared(fileToLoad->Buffer); + auto binaryReader = std::make_shared(stream); + + auto xmlReader = std::make_shared(); + + 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 Archive::LoadFile(const std::string& filePath) { + auto metaFilePath = filePath + ".meta"; + auto metaFileToLoad = LoadFileRaw(metaFilePath); + + std::shared_ptr 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; diff --git a/src/resource/archive/Archive.h b/src/resource/archive/Archive.h index 32991e1..d5d3d9f 100644 --- a/src/resource/archive/Archive.h +++ b/src/resource/archive/Archive.h @@ -40,19 +40,22 @@ class Archive { virtual std::shared_ptr LoadFileRaw(uint64_t hash) = 0; protected: - static std::shared_ptr ReadResourceInitDataBinary(const std::string& filePath, - std::shared_ptr headerReader); - static std::shared_ptr ReadResourceInitDataXml(const std::string& filePath, - std::shared_ptr document); - virtual std::shared_ptr LoadFileMeta(const std::string& filePath) = 0; - virtual std::shared_ptr 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 CreateDefaultResourceInitData(); + std::shared_ptr ReadResourceInitData(const std::string& filePath, + std::shared_ptr metaFileToLoad); + std::shared_ptr ReadResourceInitDataLegacy(const std::string& filePath, + std::shared_ptr fileToLoad); + static std::shared_ptr ReadResourceInitDataBinary(const std::string& filePath, + std::shared_ptr headerReader); + static std::shared_ptr ReadResourceInitDataXml(const std::string& filePath, + std::shared_ptr document); + std::shared_ptr CreateBinaryReader(std::shared_ptr fileToLoad); + std::shared_ptr CreateXMLReader(std::shared_ptr fileToLoad); bool mIsLoaded; bool mHasGameVersion; diff --git a/src/resource/archive/O2rArchive.cpp b/src/resource/archive/O2rArchive.cpp index 1995653..6acaf39 100644 --- a/src/resource/archive/O2rArchive.cpp +++ b/src/resource/archive/O2rArchive.cpp @@ -18,16 +18,6 @@ std::shared_ptr O2rArchive::LoadFileRaw(const std::string& filePath) { return nullptr; } -std::shared_ptr 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 O2rArchive::LoadFileMeta(uint64_t hash) { - return nullptr; -} - bool O2rArchive::LoadRaw() { return false; } diff --git a/src/resource/archive/O2rArchive.h b/src/resource/archive/O2rArchive.h index cc00c34..168f4f9 100644 --- a/src/resource/archive/O2rArchive.h +++ b/src/resource/archive/O2rArchive.h @@ -24,9 +24,6 @@ class O2rArchive : virtual public Archive { std::shared_ptr LoadFileRaw(uint64_t hash); protected: - std::shared_ptr LoadFileMeta(const std::string& filePath); - std::shared_ptr LoadFileMeta(uint64_t hash); - private: }; } // namespace LUS diff --git a/src/resource/archive/OtrArchive.cpp b/src/resource/archive/OtrArchive.cpp index 8f60ede..45b7c6f 100644 --- a/src/resource/archive/OtrArchive.cpp +++ b/src/resource/archive/OtrArchive.cpp @@ -56,14 +56,6 @@ std::shared_ptr OtrArchive::LoadFileRaw(uint64_t hash) { return LoadFileRaw(filePath); } -std::shared_ptr OtrArchive::LoadFileMeta(const std::string& filePath) { - return nullptr; -} - -std::shared_ptr 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) { diff --git a/src/resource/archive/OtrArchive.h b/src/resource/archive/OtrArchive.h index 4fab6e8..424c2b8 100644 --- a/src/resource/archive/OtrArchive.h +++ b/src/resource/archive/OtrArchive.h @@ -30,9 +30,6 @@ class OtrArchive : virtual public Archive { std::shared_ptr LoadFileRaw(uint64_t hash); protected: - std::shared_ptr LoadFileMeta(const std::string& filePath); - std::shared_ptr LoadFileMeta(uint64_t hash); - private: HANDLE mHandle; };