diff options
| author | KiritoDv <kiritodev01@gmail.com> | 2024-01-30 23:03:23 -0600 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2024-01-31 12:05:40 -0600 |
| commit | 4668cf08fb240da4abaafc073ba08d9d13ac0fa5 (patch) | |
| tree | 8ef2781da88920eeb1267225e73406e25a3c17b6 /src/utils | |
| parent | 242f8acf212d143443dc2ce846507bdb82571902 (diff) | |
Refactored code and added per file config
Diffstat (limited to 'src/utils')
| -rw-r--r-- | src/utils/Decompressor.cpp | 124 | ||||
| -rw-r--r-- | src/utils/Decompressor.h | 36 | ||||
| -rw-r--r-- | src/utils/MIODecoder.cpp | 28 | ||||
| -rw-r--r-- | src/utils/MIODecoder.h | 12 |
4 files changed, 160 insertions, 40 deletions
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 <stdexcept> +#include "spdlog/spdlog.h" +#include <Companion.h> + +extern "C" { +#include <libmio0/mio0.h> +} + +std::unordered_map<uint32_t, DataChunk*> gCachedChunks; + +DataChunk* Decompressor::Decode(const std::vector<uint8_t>& 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<uint8_t>& buffer) { + if(!node["offset"]){ + throw std::runtime_error("Failed to find offset"); + } + + const auto offset = TranslateAddr(node["offset"].as<uint32_t>()); + + if(node["mio0"]){ + const auto mio0 = node["mio0"].as<uint32_t>(); + auto decoded = Decode(buffer, offset, CompressionType::MIO0); + auto size = node["size"] ? node["size"].as<size_t>() : 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 <vector> +#include <cstdint> +#include <unordered_map> +#include <yaml-cpp/yaml.h> + +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<uint8_t>& buffer, uint32_t offset, CompressionType type); + static DecompressedData AutoDecode(YAML::Node& node, std::vector<uint8_t>& 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 <stdexcept> - -extern "C" { -#include <libmio0/mio0.h> -} - -std::unordered_map<uint32_t, std::vector<uint8_t>> MIO0Decoder::gCachedChunks; - -std::vector<uint8_t>& MIO0Decoder::Decode(std::vector<uint8_t>& 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<uint8_t>(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 <vector> -#include <unordered_map> -#include <cstdint> - -class MIO0Decoder { -public: - static std::unordered_map<uint32_t, std::vector<uint8_t>> gCachedChunks; - static std::vector<uint8_t>& Decode(std::vector<uint8_t>& buffer, uint32_t offset); - static void ClearCache(); -}; |
