XPlor/definitions/thqa/pak.xscript

209 lines
6.2 KiB
Plaintext
Raw Normal View History

// PAK Archive format - THQ Australia Engine
// Used by: SpongeBob, Avatar, Jimmy Neutron, Megamind, etc.
// Dispatcher that routes to platform-specific parser based on magic and version
//
// Big-endian "pack" magic: Xbox 360, Wii, PS2 (newer games like Avatar)
// Little-endian "kcap" magic: Original Xbox, GameCube, PS2 (older games like SpongeBob)
// Main dispatcher for big-endian PAK files
type thqa_pak ui("THQA PAK Archive", root) byteorder BE
{
criteria {
require ascii(bytesat(0, 4)) == "pack";
}
original_name = _name;
pak_version = u32at(4);
set_display("THQA PAK Archive");
if (pak_version == 2) {
// Xbox 360 format (24-byte entries)
set_name(original_name + " (Xbox 360)");
platform = "Xbox 360" ui("Platform");
parse_here("thqa_pak_xenon");
} else if (pak_version == 1) {
// Wii format (16-byte entries)
set_name(original_name + " (Wii)");
platform = "Wii" ui("Platform");
parse_here("thqa_pak_wii");
} else {
// Unknown version
set_name(original_name + " (Unknown v" + pak_version + ")");
platform = "Unknown" ui("Platform");
magic = ascii(read(4)) ui("Magic");
u32 version ui("Unknown Version");
}
}
// Dispatcher for little-endian PAK files (original Xbox, GameCube)
type thqa_pak_le ui("THQA PAK Archive", root) byteorder LE
{
criteria {
require ascii(bytesat(0, 4)) == "kcap";
}
original_name = _name;
set_display("THQA PAK Archive");
set_name(original_name + " (Xbox)");
platform = "Xbox" ui("Platform");
parse_here("thqa_pak_xbox");
}
// PAK entry child for big-endian files (Xbox 360/Wii)
// Some file types (gml, mmp, ofx, rcb, rsc) are zlib compressed
// Inherits byteorder from parent
type thqa_pak_entry_be ui("PAK Entry")
{
entry_name = ctx_get("_thqa_pak_entry_name");
set_name(entry_name);
raw_size = size() ui("Size");
// Check if this is a zlib-compressed file type
is_compressed = ends_with(entry_name, ".gml") ||
ends_with(entry_name, ".mmp") ||
ends_with(entry_name, ".ofx") ||
ends_with(entry_name, ".rcb") ||
ends_with(entry_name, ".rsc");
if (is_compressed) {
compressed_data = read(size());
decompressed_data = zlib(compressed_data);
decompressed_size = len(decompressed_data) ui("Decompressed Size");
file_magic = ascii(bytesof(decompressed_data, 0, 4)) ui("Magic");
if (file_magic == "0lmg") {
set_display("GML Script");
child = decompressed_data |> parse thqa_pak_gml_be;
push("content", child);
} else if (file_magic == "g4rc") {
if (ends_with(entry_name, ".rcb")) {
set_display("RCB Texture");
child = decompressed_data |> parse thqa_pak_rcb_be;
push("content", child);
} else {
set_display("G4RC Resource");
child = decompressed_data |> parse thqa_pak_g4rc_be;
push("content", child);
}
} else if (file_magic == "dsrc") {
set_display("RSC Model");
child = decompressed_data |> parse thqa_pak_rsc_be;
push("content", child);
} else {
set_display("Decompressed Data");
ctx_set("_thqa_decomp_name", entry_name);
child = decompressed_data |> parse thqa_pak_decomp_be;
push("content", child);
}
} else {
// Check extension-based types first (before reading magic)
if (ends_with(entry_name, ".sub")) {
set_display("Subtitle File");
parse_here("thqa_sub");
} else {
// Magic-based detection
file_magic = ascii(bytesat(0, 4)) ui("Magic");
if (file_magic == "pack") {
set_display("Nested PAK");
parse_here("thqa_pak");
} else if (file_magic == "rad0") {
set_display("RAD Resource");
parse_here("thqa_rad");
} else if (file_magic == "FSB3" || file_magic == "FSB4" || file_magic == "FSB5") {
set_display("FSB Sound Bank");
parse_here("fmod_fsb_embedded");
} else if (file_magic == "bats") {
set_display("String Table");
parse_here("thqa_str");
} else {
data = read(size());
}
}
}
}
// PAK entry child for little-endian files (original Xbox)
// Inherits byteorder from parent
type thqa_pak_entry_le ui("PAK Entry")
{
entry_name = ctx_get("_thqa_pak_entry_name");
set_name(entry_name);
raw_size = size() ui("Size");
// Check extension-based types first (before reading magic)
if (ends_with(entry_name, ".sub")) {
set_display("Subtitle File");
parse_here("thqa_sub");
} else if (size() >= 4) {
// Magic-based detection
file_magic = ascii(bytesat(0, 4)) ui("Magic");
if (file_magic == "kcap") {
set_display("Nested PAK");
parse_here("thqa_pak_le");
} else if (file_magic == "0dar") {
set_display("RAD Resource");
parse_here("thqa_rad_le");
} else if (file_magic == "0lmg") {
set_display("GML Script");
parse_here("thqa_gml_le");
} else if (file_magic == "bats") {
set_display("String Table");
parse_here("thqa_str_le");
} else if (file_magic == "FSB3" || file_magic == "FSB4" || file_magic == "FSB5") {
set_display("FSB Sound Bank");
parse_here("fmod_fsb_embedded");
} else {
data = read(size());
}
} else {
data = read(size());
}
}
// Child types for decompressed BE content
// These inherit byteorder from parent (thqa_pak_entry_be)
type thqa_pak_gml_be ui("GML Script")
{
set_name("Decompressed GML");
file_magic = ascii(bytesat(0, 4)) ui("Magic");
data_size = size() ui("Size");
parse_here("thqa_gml");
}
type thqa_pak_g4rc_be ui("G4RC Resource")
{
set_name("Decompressed G4RC");
file_magic = ascii(bytesat(0, 4)) ui("Magic");
data_size = size() ui("Size");
data = read(size());
}
type thqa_pak_rcb_be ui("RCB Texture")
{
set_name("Decompressed RCB");
file_magic = ascii(bytesat(0, 4)) ui("Magic");
data_size = size() ui("Size");
parse_here("thqa_rcb");
}
type thqa_pak_rsc_be ui("RSC Model")
{
set_name("Decompressed RSC");
file_magic = ascii(bytesat(0, 4)) ui("Magic");
data_size = size() ui("Size");
parse_here("thqa_rsc");
}
type thqa_pak_decomp_be ui("Decompressed Data")
{
set_name(ctx_get("_thqa_decomp_name"));
file_magic = ascii(bytesat(0, 4)) ui("Magic");
data_size = size() ui("Size");
data = read(size());
}