Skip to content

Commit

Permalink
O2R Support
Browse files Browse the repository at this point in the history
  • Loading branch information
inspectredc authored and KiritoDv committed Jan 9, 2025
1 parent ef48a4b commit 94be711
Show file tree
Hide file tree
Showing 12 changed files with 263 additions and 43 deletions.
20 changes: 19 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,24 @@ FetchContent_Declare(

FetchContent_MakeAvailable(spdlog)

# Link LibZip

set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(BUILD_TOOLS OFF)
set(BUILD_REGRESS OFF)
set(BUILD_EXAMPLES OFF)
set(BUILD_DOC OFF)
set(BUILD_OSSFUZZ OFF)
set(BUILD_SHARED_LIBS OFF)
FetchContent_Declare(
libzip
GIT_REPOSITORY https://github.com/nih-at/libzip.git
GIT_TAG v1.10.1
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(libzip)
target_include_directories(${PROJECT_NAME} PRIVATE ${libzip_SOURCE_DIR}/lib ${libzip_BINARY_DIR})

# Link TinyXML2
set(tinyxml2_BUILD_TESTING OFF)
FetchContent_Declare(
Expand All @@ -174,7 +192,7 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(tinyxml2)

target_link_libraries(${PROJECT_NAME} PRIVATE spdlog tinyxml2 yaml-cpp storm N64Graphics BinaryTools)
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog tinyxml2 yaml-cpp storm N64Graphics BinaryTools libzip::zip)

if((CMAKE_SYSTEM_NAME MATCHES "Windows") AND ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))
include(../cmake/HandleCompilerRT.cmake)
Expand Down
54 changes: 47 additions & 7 deletions src/Companion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#include "utils/Decompressor.h"
#include "utils/TorchUtils.h"
#include "storm/SWrapper.h"
#include "archive/SWrapper.h"
#include "archive/ZWrapper.h"
#include "spdlog/spdlog.h"
#include "hj/sha1.h"

Expand Down Expand Up @@ -1022,7 +1023,18 @@ void Companion::Process() {
this->gConfig.moddingPath = modding_path;
switch (this->gConfig.exporterType) {
case ExportType::Binary: {
this->gConfig.outputPath = opath && opath["binary"] ? opath["binary"].as<std::string>() : "generic.otr";
std::string extension = "";
switch (this->gConfig.otrMode) {
case ArchiveType::OTR:
extension = ".otr";
break;
case ArchiveType::O2R:
extension = ".o2r";
break;
default:
throw std::runtime_error("Invalid archive type for export type Binary");
}
this->gConfig.outputPath = opath && opath["binary"] ? opath["binary"].as<std::string>() : ("generic" + extension);
break;
}
case ExportType::Header: {
Expand Down Expand Up @@ -1138,7 +1150,24 @@ void Companion::Process() {
}

AudioManager::Instance = new AudioManager();
auto wrapper = this->gConfig.exporterType == ExportType::Binary ? new SWrapper(this->gConfig.outputPath) : nullptr;
BinaryWrapper* wrapper = nullptr;

if (this->gConfig.exporterType == ExportType::Binary) {
switch (this->gConfig.otrMode) {
case ArchiveType::OTR:
wrapper = new SWrapper(this->gConfig.outputPath);
break;
case ArchiveType::O2R:
wrapper = new ZWrapper(this->gConfig.outputPath);
break;
default:
throw std::runtime_error("Invalid archive type for export type Binary");
}
}

if (wrapper) {
wrapper->CreateArchive();
}
this->gCurrentWrapper = wrapper;

auto vWriter = LUS::BinaryWriter();
Expand Down Expand Up @@ -1201,7 +1230,7 @@ void Companion::Process() {
Instance = nullptr;
}

void Companion::Pack(const std::string& folder, const std::string& output) {
void Companion::Pack(const std::string& folder, const std::string& output, const ArchiveType otrMode) {

spdlog::set_level(spdlog::level::debug);
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
Expand All @@ -1225,14 +1254,25 @@ void Companion::Pack(const std::string& folder, const std::string& output) {
files[entry.path().generic_string()] = data;
}

auto wrapper = SWrapper(output);
std::unique_ptr<BinaryWrapper> wrapper;
switch (otrMode) {
case ArchiveType::OTR:
wrapper.reset(new SWrapper(output));
break;
case ArchiveType::O2R:
wrapper.reset(new ZWrapper(output));
break;
default:
throw std::runtime_error("Invalid archive type for export type Binary");
}
wrapper->CreateArchive();

for(auto& [path, data] : files){
std::string normalized = path;
std::replace(normalized.begin(), normalized.end(), '\\', '/');
// Remove parent folder
normalized = normalized.substr(folder.length() + 1);
wrapper.CreateFile(normalized, data);
wrapper->CreateFile(normalized, data);
SPDLOG_INFO("> Added {}", normalized);
}

Expand All @@ -1242,7 +1282,7 @@ void Companion::Pack(const std::string& folder, const std::string& output) {
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");
SPDLOG_INFO("------------------------------------------------");

wrapper.Close();
wrapper->Close();
}

std::optional<std::tuple<std::string, YAML::Node>> Companion::RegisterAsset(const std::string& name, YAML::Node& node) {
Expand Down
24 changes: 15 additions & 9 deletions src/Companion.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "utils/Decompressor.h"
#include "factories/TextureFactory.h"

class SWrapper;
class BinaryWrapper;
namespace fs = std::filesystem;

enum class ParseMode {
Expand All @@ -40,6 +40,12 @@ enum class TableMode {
Append
};

enum class ArchiveType {
None,
OTR,
O2R,
};

struct SegmentConfig {
std::unordered_map<uint32_t, uint32_t> global;
std::unordered_map<uint32_t, uint32_t> local;
Expand Down Expand Up @@ -79,7 +85,7 @@ struct TorchConfig {
std::string moddingPath;
ExportType exporterType;
ParseMode parseMode;
bool otrMode;
ArchiveType otrMode;
bool debug;
bool modding;
};
Expand All @@ -103,14 +109,14 @@ class Companion {
public:
static Companion* Instance;

explicit Companion(std::filesystem::path rom, const bool otr, const bool debug, const bool modding = false) : gCartridge(nullptr) {
explicit Companion(std::filesystem::path rom, const ArchiveType otr, const bool debug, const bool modding = false) : gCartridge(nullptr) {
this->gRomPath = rom;
this->gConfig.otrMode = otr;
this->gConfig.debug = debug;
this->gConfig.modding = modding;
}

explicit Companion(std::vector<uint8_t> rom, const bool otr, const bool debug, const bool modding = false) : gCartridge(nullptr) {
explicit Companion(std::vector<uint8_t> rom, const ArchiveType otr, const bool debug, const bool modding = false) : gCartridge(nullptr) {
this->gRomData = rom;
this->gConfig.otrMode = otr;
this->gConfig.debug = debug;
Expand All @@ -123,7 +129,7 @@ class Companion {

void Process();

bool IsOTRMode() const { return this->gConfig.otrMode; }
bool IsOTRMode() const { return (this->gConfig.otrMode != ArchiveType::None); }
bool IsDebug() const { return this->gConfig.debug; }

N64::Cartridge* GetCartridge() const { return this->gCartridge.get(); }
Expand Down Expand Up @@ -151,13 +157,13 @@ class Companion {
std::optional<Table> SearchTable(uint32_t addr);

static std::string CalculateHash(const std::vector<uint8_t>& data);
static void Pack(const std::string& folder, const std::string& output);
static void Pack(const std::string& folder, const std::string& output, const ArchiveType otrMode);
std::string NormalizeAsset(const std::string& name) const;
std::string RelativePath(const std::string& path) const;
void RegisterCompanionFile(const std::string path, std::vector<char> data);

TorchConfig& GetConfig() { return this->gConfig; }
SWrapper* GetCurrentWrapper() { return this->gCurrentWrapper; }
BinaryWrapper* GetCurrentWrapper() { return this->gCurrentWrapper; }

std::optional<std::tuple<std::string, YAML::Node>> RegisterAsset(const std::string& name, YAML::Node& node);
std::optional<YAML::Node> AddAsset(YAML::Node asset);
Expand All @@ -175,7 +181,7 @@ class Companion {
std::shared_ptr<N64::Cartridge> gCartridge;
std::unordered_map<std::string, std::vector<YAML::Node>> gCourseMetadata;
std::unordered_map<std::string, std::unordered_map<int32_t, std::string>> gEnums;
SWrapper* gCurrentWrapper;
BinaryWrapper* gCurrentWrapper;

// Temporal Variables
std::string gCurrentFile;
Expand Down Expand Up @@ -206,7 +212,7 @@ class Companion {
void ParseModdingConfig();
void ParseCurrentFileConfig(YAML::Node node);
void RegisterFactory(const std::string& type, const std::shared_ptr<BaseFactory>& factory);
void ExtractNode(YAML::Node& node, std::string& name, SWrapper* binary);
void ExtractNode(YAML::Node& node, std::string& name, BinaryWrapper* binary);
void ProcessTables(YAML::Node& rom);
void LoadYAMLRecursively(const std::string &dirPath, std::vector<YAML::Node> &result, bool skipRoot);
std::optional<ParseResultData> ParseNode(YAML::Node& node, std::string& name);
Expand Down
3 changes: 3 additions & 0 deletions src/archive/BinaryWrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "BinaryWrapper.h"

BinaryWrapper::BinaryWrapper(const std::string& path) : mPath(path) {}
19 changes: 19 additions & 0 deletions src/archive/BinaryWrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <vector>
#include <string>
#include <mutex>

class BinaryWrapper {
public:
BinaryWrapper() {}
BinaryWrapper(const std::string& path);
virtual ~BinaryWrapper() = default;

virtual int32_t CreateArchive(void) = 0;
virtual bool CreateFile(const std::string& path, std::vector<char> data) = 0;
virtual int32_t Close(void) = 0;
protected:
std::mutex mMutex;
std::string mPath;
};
28 changes: 19 additions & 9 deletions src/storm/SWrapper.cpp → src/archive/SWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@
namespace fs = std::filesystem;

SWrapper::SWrapper(const std::string& path) {
if(fs::exists(path)) {
fs::remove(path);
mPath = path;
}

int32_t SWrapper::CreateArchive() {
if(fs::exists(mPath)) {
fs::remove(mPath);
}

if(!SFileCreateArchive(path.c_str(), MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, 16 * 1024, &this->hMpq)){
SPDLOG_ERROR("Failed to create archive {} with error code {}", path, GetLastError());
return;
if(!SFileCreateArchive(mPath.c_str(), MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, 16 * 1024, &this->hMpq)){
SPDLOG_ERROR("Failed to create archive {} with error code {}", mPath, GetLastError());
return -1;
}

return 0;
}

bool SWrapper::CreateFile(const std::string& path, std::vector<char> data) {
Expand Down Expand Up @@ -70,10 +76,14 @@ bool SWrapper::CreateFile(const std::string& path, std::vector<char> data) {
return true;
}

void SWrapper::Close() {
int32_t SWrapper::Close(void) {
if(this->hMpq == nullptr) {
SPDLOG_ERROR("Archive already closed");
return;
return -1;
}
SFileCloseArchive(this->hMpq);
}
if (SFileCloseArchive(this->hMpq)) {
SPDLOG_ERROR("Error closing archive");
return -1;
}
return 0;
}
9 changes: 5 additions & 4 deletions src/storm/SWrapper.h → src/archive/SWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
#include <vector>
#include <string>
#include <StormLib/src/StormLib.h>
#include "BinaryWrapper.h"

class SWrapper {
class SWrapper : public BinaryWrapper {
public:
SWrapper(const std::string& path);

std::vector<char> ReadFile(std::string path);
int32_t CreateArchive(void);
bool CreateFile(const std::string& path, std::vector<char> data);
void Close();
int32_t Close(void);
private:
HANDLE hMpq{};
};
};
79 changes: 79 additions & 0 deletions src/archive/ZWrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "ZWrapper.h"
#include <filesystem>
#include <iostream>
#include <fstream>

#include "spdlog/spdlog.h"
#include <Companion.h>

namespace fs = std::filesystem;

ZWrapper::ZWrapper(const std::string& path) {
mPath = path;
}

int32_t ZWrapper::CreateArchive(void) {
int openErr;
zip_t* zip;

if(fs::exists(mPath)) {
fs::remove(mPath);
}

{
const std::lock_guard<std::mutex> lock(mMutex);
zip = zip_open(mPath.c_str(), ZIP_CREATE, &openErr);
}

if (zip == nullptr) {
zip_error_t error;
zip_error_init_with_code(&error, openErr);
SPDLOG_ERROR("Failed to create ZIP (O2R) file. Error: {}", zip_error_strerror(&error));
zip_error_fini(&error);
return -1;
}
mZip = zip;
SPDLOG_INFO("Loaded ZIP (O2R) archive: {}", mPath.c_str());
return 0;
}

bool ZWrapper::CreateFile(const std::string& path, std::vector<char> data) {
char* fileData = data.data();
size_t fileSize = data.size();
zip_source_t* source = zip_source_buffer(mZip, fileData, fileSize, 0);

if (source == nullptr) {
zip_error_t* zipError = zip_get_error(mZip);
SPDLOG_ERROR("Failed to create ZIP source. Error: {}", zip_error_strerror(zipError));
zip_source_free(source);
zip_error_fini(zipError);
return false;
}

if (zip_file_add(mZip, path.c_str(), source, ZIP_FL_OVERWRITE | ZIP_FL_ENC_UTF_8) < 0) {
zip_error_t* zipError = zip_get_error(mZip);
SPDLOG_ERROR("Failed to add file to ZIP. Error: {}", zip_error_strerror(zipError));
zip_source_free(source);
zip_error_fini(zipError);
return false;
}

return true;
}

int32_t ZWrapper::Close(void) {
int err;
{
const std::lock_guard<std::mutex> lock(mMutex);
err = zip_close(mZip);
}
if (err < 0) {
zip_error_t* zipError = zip_get_error(mZip);
SPDLOG_ERROR("Failed to close ZIP (O2R) file. Error: {}", zip_error_strerror(zipError));
printf("fail\n");
zip_error_fini(zipError);
return -1;
}

return 0;
}
Loading

0 comments on commit 94be711

Please sign in to comment.