summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2024-01-30 23:03:23 -0600
committerLywx <kiritodev01@gmail.com>2024-01-31 12:05:40 -0600
commit4668cf08fb240da4abaafc073ba08d9d13ac0fa5 (patch)
tree8ef2781da88920eeb1267225e73406e25a3c17b6 /src/utils
parent242f8acf212d143443dc2ce846507bdb82571902 (diff)
Refactored code and added per file config
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/Decompressor.cpp124
-rw-r--r--src/utils/Decompressor.h36
-rw-r--r--src/utils/MIODecoder.cpp28
-rw-r--r--src/utils/MIODecoder.h12
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();
-};