mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
Added Yay0 support with auto detection for pkmn-stadium files
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#include "yay0.h"
|
||||
#include "libmio0/utils.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
uint8_t* yay0_decode(const uint8_t* in_buf, uint32_t* out_size){
|
||||
|
||||
const uint8_t* in = in_buf;
|
||||
const char* magic = (const char*) in;
|
||||
if(!strncmp(magic, "PERS-SZP", 8)){
|
||||
uint32_t header_size = read_u32_be(in + 8);
|
||||
magic += header_size;
|
||||
in += header_size;
|
||||
}
|
||||
|
||||
if(strncmp(magic, "Yay0", 4) != 0){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t decompressed_size = read_u32_be(in + 4);
|
||||
uint32_t link_table_offset = read_u32_be(in + 8);
|
||||
uint32_t chunk_offset = read_u32_be(in + 12);
|
||||
|
||||
uint32_t link_table_idx = link_table_offset;
|
||||
uint32_t chunk_idx = chunk_offset;
|
||||
uint32_t other_idx = 16;
|
||||
|
||||
uint32_t mask_bit_counter = 0;
|
||||
uint32_t current_mask = 0;
|
||||
uint32_t idx = 0;
|
||||
|
||||
uint8_t* out = malloc(decompressed_size);
|
||||
memset(out, 0, decompressed_size);
|
||||
*out_size = decompressed_size;
|
||||
|
||||
while(idx < decompressed_size){
|
||||
if(mask_bit_counter == 0){
|
||||
current_mask = read_u32_be(in + other_idx);
|
||||
other_idx += 4;
|
||||
mask_bit_counter = 32;
|
||||
}
|
||||
|
||||
if(current_mask & 0x80000000){
|
||||
out[idx] = in[chunk_idx];
|
||||
idx++;
|
||||
chunk_idx++;
|
||||
} else {
|
||||
uint16_t link = read_u16_be(in + link_table_idx);
|
||||
link_table_idx += 2;
|
||||
uint32_t offset = idx - (link & 0xFFF);
|
||||
uint32_t count = link >> 12;
|
||||
|
||||
if(count == 0){
|
||||
uint8_t count_modifier = in[chunk_idx];
|
||||
chunk_idx++;
|
||||
count = count_modifier + 18;
|
||||
} else {
|
||||
count += 2;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < count; i++){
|
||||
out[idx] = out[offset + i - 1];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
current_mask <<= 1;
|
||||
mask_bit_counter--;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern uint8_t* yay0_decode(const uint8_t* in, uint32_t* out_size);
|
||||
+2
-25
@@ -339,7 +339,7 @@ void Companion::ParseCurrentFileConfig(YAML::Node node) {
|
||||
if (segments[0].IsSequence() && segments[0].size() == 2) {
|
||||
gCurrentSegmentNumber = segments[0][0].as<uint32_t>();
|
||||
gCurrentFileOffset = segments[0][1].as<uint32_t>();
|
||||
gCurrentCompressionType = GetCompressionType(this->gRomData, gCurrentFileOffset);
|
||||
gCurrentCompressionType = Decompressor::GetCompressionType(this->gRomData, gCurrentFileOffset);
|
||||
if(node["no_compression"]) {
|
||||
gCurrentCompressionType = CompressionType::None;
|
||||
}
|
||||
@@ -518,7 +518,7 @@ void Companion::ProcessFile(YAML::Node root) {
|
||||
if (segments[0].IsSequence() && segments[0].size() == 2) {
|
||||
gCurrentSegmentNumber = segments[0][0].as<uint32_t>();
|
||||
gCurrentFileOffset = segments[0][1].as<uint32_t>();
|
||||
gCurrentCompressionType = GetCompressionType(this->gRomData, gCurrentFileOffset);
|
||||
gCurrentCompressionType = Decompressor::GetCompressionType(this->gRomData, gCurrentFileOffset);
|
||||
if(root[":config"]["no_compression"]) {
|
||||
gCurrentCompressionType = CompressionType::None;
|
||||
}
|
||||
@@ -1263,29 +1263,6 @@ std::optional<std::shared_ptr<BaseFactory>> Companion::GetFactory(const std::str
|
||||
return this->gFactories[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param offset Rom offset of compressed mio0 file.
|
||||
* @returns CompressionType
|
||||
*/
|
||||
CompressionType Companion::GetCompressionType(std::vector<uint8_t>& buffer, const uint32_t offset) {
|
||||
if (offset) {
|
||||
LUS::BinaryReader reader((char*) buffer.data() + offset, sizeof(uint32_t));
|
||||
reader.SetEndianness(Torch::Endianness::Big);
|
||||
|
||||
const std::string header = reader.ReadCString();
|
||||
|
||||
// Check if a compressed header exists
|
||||
if (header == "MIO0") {
|
||||
return CompressionType::MIO0;
|
||||
} else if (header == "YAY0") {
|
||||
return CompressionType::YAY0;
|
||||
} else if (header == "YAZ0") {
|
||||
return CompressionType::YAZ0;
|
||||
}
|
||||
}
|
||||
return CompressionType::None;
|
||||
}
|
||||
|
||||
std::optional<Table> Companion::SearchTable(uint32_t addr){
|
||||
for(auto& table : this->gTables){
|
||||
if(addr >= table.start && addr <= table.end){
|
||||
|
||||
@@ -147,7 +147,6 @@ public:
|
||||
std::optional<std::uint32_t> GetFileOffset(void) const { return this->gCurrentFileOffset; };
|
||||
std::optional<std::uint32_t> GetCurrSegmentNumber(void) const { return this->gCurrentSegmentNumber; };
|
||||
CompressionType GetCurrCompressionType(void) const { return this->gCurrentCompressionType; };
|
||||
CompressionType GetCompressionType(std::vector<uint8_t>& buffer, const uint32_t offset);
|
||||
std::optional<VRAMEntry> GetCurrentVRAM(void) const { return this->gCurrentVram; };
|
||||
std::optional<Table> SearchTable(uint32_t addr);
|
||||
|
||||
|
||||
+45
-20
@@ -6,6 +6,7 @@
|
||||
|
||||
extern "C" {
|
||||
#include <libmio0/mio0.h>
|
||||
#include <libyay0/yay0.h>
|
||||
#include <libmio0/tkmk00.h>
|
||||
}
|
||||
|
||||
@@ -31,13 +32,23 @@ DataChunk* Decompressor::Decode(const std::vector<uint8_t>& buffer, const uint32
|
||||
gCachedChunks[offset] = new DataChunk{ decompressed, head.dest_size };
|
||||
return gCachedChunks[offset];
|
||||
}
|
||||
case CompressionType::YAY0: {
|
||||
uint32_t size = 0;
|
||||
uint8_t* decompressed = yay0_decode(in_buf, &size);
|
||||
|
||||
if(!decompressed){
|
||||
throw std::runtime_error("Failed to decode YAY0");
|
||||
}
|
||||
|
||||
gCachedChunks[offset] = new DataChunk{ decompressed, size };
|
||||
return gCachedChunks[offset];
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unknown compression type");
|
||||
}
|
||||
}
|
||||
|
||||
DataChunk* Decompressor::DecodeTKMK00(const std::vector<uint8_t>& buffer, const uint32_t offset, const uint32_t size, const uint32_t alpha) {
|
||||
|
||||
if(gCachedChunks.contains(offset)){
|
||||
return gCachedChunks[offset];
|
||||
}
|
||||
@@ -59,18 +70,13 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t>
|
||||
auto fileOffset = TranslateAddr(offset, true);
|
||||
|
||||
// Extract compressed assets.
|
||||
if (node["mio0"]) {
|
||||
auto assetPtr = ASSET_PTR(offset);
|
||||
auto gameSize = Companion::Instance->GetRomData().size();
|
||||
|
||||
auto fileOffset = TranslateAddr(offset, true);
|
||||
offset = ASSET_PTR(offset);
|
||||
|
||||
auto decoded = Decode(buffer, fileOffset + offset, CompressionType::MIO0);
|
||||
if (node["mio0"] || node["yay0"]) {
|
||||
auto foffset = TranslateAddr(offset, true);
|
||||
auto decoded = Decode(buffer, foffset, node["mio0"] ? CompressionType::MIO0 : CompressionType::YAY0);
|
||||
auto size = node["size"] ? node["size"].as<size_t>() : manualSize.value_or(decoded->size);
|
||||
return {
|
||||
.root = decoded,
|
||||
.segment = { decoded->data, size }
|
||||
.root = decoded,
|
||||
.segment = { decoded->data, size }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -80,8 +86,6 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t>
|
||||
const auto width = GetSafeNode<uint32_t>(node, "width");
|
||||
const auto height = GetSafeNode<uint32_t>(node, "height");
|
||||
const auto textureSize = width * height * 2;
|
||||
auto assetPtr = ASSET_PTR(offset);
|
||||
auto gameSize = Companion::Instance->GetRomData().size();
|
||||
|
||||
auto fileOffset = TranslateAddr(offset, true);
|
||||
offset = ASSET_PTR(offset);
|
||||
@@ -89,26 +93,24 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t>
|
||||
auto decoded = DecodeTKMK00(buffer, fileOffset + offset, textureSize, alpha);
|
||||
auto size = node["size"] ? node["size"].as<size_t>() : manualSize.value_or(decoded->size);
|
||||
return {
|
||||
.root = decoded,
|
||||
.segment = { decoded->data, size }
|
||||
.root = decoded,
|
||||
.segment = { decoded->data, size }
|
||||
};
|
||||
}
|
||||
|
||||
// Extract compressed files that contain many assets.
|
||||
switch(type) {
|
||||
case CompressionType::MIO0:
|
||||
{
|
||||
case CompressionType::YAY0:
|
||||
case CompressionType::MIO0: {
|
||||
offset = ASSET_PTR(offset);
|
||||
|
||||
auto decoded = Decode(buffer, fileOffset, CompressionType::MIO0);
|
||||
auto decoded = Decode(buffer, fileOffset, type);
|
||||
auto size = node["size"] ? node["size"].as<size_t>() : manualSize.value_or(decoded->size - offset);
|
||||
return {
|
||||
.root = decoded,
|
||||
.segment = { decoded->data + offset, size }
|
||||
};
|
||||
}
|
||||
case CompressionType::YAY0:
|
||||
throw std::runtime_error("Found compressed yay0 segment.\nDecompression of yay0 has not been implemented yet.");
|
||||
case CompressionType::YAZ0:
|
||||
throw std::runtime_error("Found compressed yaz0 segment.\nDecompression of yaz0 has not been implemented yet.");
|
||||
case CompressionType::None: // The data does not have compression
|
||||
@@ -158,6 +160,29 @@ uint32_t Decompressor::TranslateAddr(uint32_t addr, bool baseAddress){
|
||||
return addr;
|
||||
}
|
||||
|
||||
CompressionType Decompressor::GetCompressionType(std::vector<uint8_t>& buffer, const uint32_t offset) {
|
||||
if (offset) {
|
||||
LUS::BinaryReader reader((char*) buffer.data() + offset, sizeof(uint32_t));
|
||||
reader.SetEndianness(Torch::Endianness::Big);
|
||||
|
||||
const std::string header = reader.ReadCString();
|
||||
|
||||
// Check if a compressed header exists
|
||||
if (header == "MIO0") {
|
||||
return CompressionType::MIO0;
|
||||
}
|
||||
|
||||
if (header == "Yay0" || header == "PERS") {
|
||||
return CompressionType::YAY0;
|
||||
}
|
||||
|
||||
if (header == "Yaz0") {
|
||||
return CompressionType::YAZ0;
|
||||
}
|
||||
}
|
||||
return CompressionType::None;
|
||||
}
|
||||
|
||||
bool Decompressor::IsSegmented(uint32_t addr) {
|
||||
if(IS_SEGMENTED(addr)){
|
||||
const auto segment = Companion::Instance->GetFileOffsetFromSegmentedAddr(SEGMENT_NUMBER(addr));
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
static DataChunk* DecodeTKMK00(const std::vector<uint8_t>& buffer, const uint32_t offset, const uint32_t size, const uint32_t alpha);
|
||||
static DecompressedData AutoDecode(YAML::Node& node, std::vector<uint8_t>& buffer, std::optional<size_t> size = std::nullopt);
|
||||
static DecompressedData AutoDecode(uint32_t offset, std::optional<size_t> size, std::vector<uint8_t>& buffer);
|
||||
static CompressionType GetCompressionType(std::vector<uint8_t>& buffer, const uint32_t offset);
|
||||
static uint32_t TranslateAddr(uint32_t addr, bool baseAddress = false);
|
||||
static bool IsSegmented(uint32_t addr);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user