Skip to content

Commit

Permalink
.meta files (#449)
Browse files Browse the repository at this point in the history
* start refactoring, legacy load still working

* account for path in meta file

* meta

* clang format

* move addfile

* more cleanup
  • Loading branch information
briaguya-ai authored Feb 19, 2024
1 parent 18ebff9 commit 0ea6b6d
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 67 deletions.
141 changes: 105 additions & 36 deletions src/resource/archive/Archive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);

// 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);
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;
}

// 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());

// 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;
}

fileToLoad->InitData = fileToLoadMeta;
auto binaryReader = std::get<std::shared_ptr<BinaryReader>>(fileToLoad->Reader);
binaryReader->SetEndianness(fileToLoad->InitData->ByteOrder);
switch (fileToLoad->InitData->Format) {
case RESOURCE_FORMAT_BINARY:
fileToLoad->Reader = CreateBinaryReader(fileToLoad);
break;
case RESOURCE_FORMAT_XML:
fileToLoad->Reader = CreateXMLReader(fileToLoad);
break;
}

return fileToLoad;
Expand Down
17 changes: 10 additions & 7 deletions src/resource/archive/Archive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 0 additions & 10 deletions src/resource/archive/O2rArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 0 additions & 3 deletions src/resource/archive/O2rArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 0 additions & 8 deletions src/resource/archive/OtrArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 0 additions & 3 deletions src/resource/archive/OtrArchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down

0 comments on commit 0ea6b6d

Please sign in to comment.