From 4668cf08fb240da4abaafc073ba08d9d13ac0fa5 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Tue, 30 Jan 2024 23:03:23 -0600 Subject: Refactored code and added per file config --- src/utils/Decompressor.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++ src/utils/Decompressor.h | 36 +++++++++++++ src/utils/MIODecoder.cpp | 28 ---------- src/utils/MIODecoder.h | 12 ----- 4 files changed, 160 insertions(+), 40 deletions(-) create mode 100644 src/utils/Decompressor.cpp create mode 100644 src/utils/Decompressor.h delete mode 100644 src/utils/MIODecoder.cpp delete mode 100644 src/utils/MIODecoder.h (limited to 'src/utils') diff --git a/src/utils/Decompressor.cpp b/src/utils/Decompressor.cpp new file mode 100644 index 0000000..064adc6 --- /dev/null +++ b/src/utils/Decompressor.cpp @@ -0,0 +1,124 @@ +#include "Decompressor.h" + +#include +#include "spdlog/spdlog.h" +#include + +extern "C" { +#include +} + +std::unordered_map gCachedChunks; + +DataChunk* Decompressor::Decode(const std::vector& buffer, const uint32_t offset, const CompressionType type) { + + if(gCachedChunks.contains(offset)){ + return gCachedChunks[offset]; + } + + const unsigned char* in_buf = buffer.data() + offset; + + switch (type) { + case CompressionType::MIO0: { + + mio0_header_t head; + if(!mio0_decode_header(in_buf, &head)){ + throw std::runtime_error("Failed to decode MIO0 header"); + } + + const auto decompressed = new uint8_t[head.dest_size]; + mio0_decode(in_buf, decompressed, nullptr); + gCachedChunks[offset] = new DataChunk{ decompressed, head.dest_size }; + return gCachedChunks[offset]; + } + default: + throw std::runtime_error("Unknown compression type"); + } +} + +DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector& buffer) { + if(!node["offset"]){ + throw std::runtime_error("Failed to find offset"); + } + + const auto offset = TranslateAddr(node["offset"].as()); + + if(node["mio0"]){ + const auto mio0 = node["mio0"].as(); + auto decoded = Decode(buffer, offset, CompressionType::MIO0); + auto size = node["size"] ? node["size"].as() : decoded->size - mio0; + + return { + .root = decoded, + .segment = { decoded->data + mio0, size } + }; + } + + if(node["yay0"]){ + throw std::runtime_error("Yay0 not implemented"); + } + + if(node["yaz0"]){ + throw std::runtime_error("Yaz0 not implemented"); + } + + return { + .root = nullptr, + .segment = { buffer.data() + offset, buffer.size() - offset } + }; +} + +uint32_t Decompressor::TranslateAddr(uint32_t addr){ + if(IS_SEGMENTED(addr)){ + const auto segment = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(addr)); + + if(!segment.has_value()) { + SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(addr)); + return 0; + } + + return segment.value() + SEGMENT_OFFSET(addr); + } + + return addr; +} + +bool Decompressor::IsSegmented(uint32_t addr) { + if(IS_SEGMENTED(addr)){ + const auto segment = Companion::Instance->GetSegmentedAddr(SEGMENT_NUMBER(addr)); + + if(!segment.has_value()) { + SPDLOG_ERROR("Segment data missing from game config\nPlease add an entry for segment {}", SEGMENT_NUMBER(addr)); + return false; + } + + return true; + } + + return false; +} + +bool Decompressor::IsCompressed(YAML::Node& node) { + return node["mio0"] || node["yay0"] || node["yaz0"]; +} + +void Decompressor::CopyCompression(YAML::Node& from, YAML::Node& to){ + if(from["mio0"]){ + to["mio0"] = from["mio0"]; + } + + if(from["yay0"]){ + to["yay0"] = from["yay0"]; + } + + if(from["yaz0"]){ + to["yaz0"] = from["yaz0"]; + } +} + +void Decompressor::ClearCache() { + for(auto& [key, value] : gCachedChunks){ + delete value->data; + } + gCachedChunks.clear(); +} diff --git a/src/utils/Decompressor.h b/src/utils/Decompressor.h new file mode 100644 index 0000000..1bd5c05 --- /dev/null +++ b/src/utils/Decompressor.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include +#include + +enum class CompressionType { + MIO0, + Yay0, + Yaz0, + None, +}; + + +struct DataChunk { + uint8_t* data; + size_t size; +}; + +struct DecompressedData { + DataChunk* root; + DataChunk segment; +}; + +class Decompressor { +public: + static DataChunk* Decode(const std::vector& buffer, uint32_t offset, CompressionType type); + static DecompressedData AutoDecode(YAML::Node& node, std::vector& buffer); + static uint32_t TranslateAddr(uint32_t addr); + static bool IsSegmented(uint32_t addr); + static bool IsCompressed(YAML::Node& node); + static void CopyCompression(YAML::Node& from, YAML::Node& to); + + static void ClearCache(); +}; \ No newline at end of file diff --git a/src/utils/MIODecoder.cpp b/src/utils/MIODecoder.cpp deleted file mode 100644 index 7574e55..0000000 --- a/src/utils/MIODecoder.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "MIODecoder.h" -#include - -extern "C" { -#include -} - -std::unordered_map> MIO0Decoder::gCachedChunks; - -std::vector& MIO0Decoder::Decode(std::vector& buffer, uint32_t offset) { - const unsigned char* in_buf = buffer.data() + offset; - - mio0_header_t head; - if(!mio0_decode_header(in_buf, &head)){ - throw std::runtime_error("Failed to decode MIO0 header"); - } - - auto decompressed = new uint8_t[head.dest_size]; - mio0_decode(in_buf, decompressed, nullptr); - gCachedChunks[offset] = std::vector(decompressed, decompressed + head.dest_size); - - delete[] decompressed; - return gCachedChunks[offset]; -} - -void MIO0Decoder::ClearCache() { - gCachedChunks.clear(); -} diff --git a/src/utils/MIODecoder.h b/src/utils/MIODecoder.h deleted file mode 100644 index ecf2ca4..0000000 --- a/src/utils/MIODecoder.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include -#include - -class MIO0Decoder { -public: - static std::unordered_map> gCachedChunks; - static std::vector& Decode(std::vector& buffer, uint32_t offset); - static void ClearCache(); -}; -- cgit v1.2.3