348 lines
8.8 KiB
Plaintext
348 lines
8.8 KiB
Plaintext
|
|
// Wii Opening.bnr Banner File Format
|
||
|
|
|
||
|
|
type wii_bnr [root, display="Wii Banner"] byteorder BE
|
||
|
|
{
|
||
|
|
criteria {
|
||
|
|
require _ext == "bnr" || _ext == "app";
|
||
|
|
require ascii(bytesat(0x40, 4)) == "IMET" || ascii(bytesat(0x80, 4)) == "IMET";
|
||
|
|
}
|
||
|
|
|
||
|
|
disc_imet = ascii(bytesat(0x40, 4));
|
||
|
|
nand_imet = ascii(bytesat(0x80, 4));
|
||
|
|
|
||
|
|
if (disc_imet == "IMET") {
|
||
|
|
format_type = "Disc";
|
||
|
|
|
||
|
|
ui("format_type", "Format");
|
||
|
|
padding_size = 0x40;
|
||
|
|
} else {
|
||
|
|
format_type = "NAND";
|
||
|
|
|
||
|
|
ui("format_type", "Format");
|
||
|
|
padding_size = 0x80;
|
||
|
|
}
|
||
|
|
|
||
|
|
_padding = read(padding_size);
|
||
|
|
|
||
|
|
imet_magic = ascii(read(4));
|
||
|
|
|
||
|
|
|
||
|
|
ui("imet_magic", "Magic");
|
||
|
|
u32 hash_size;
|
||
|
|
|
||
|
|
ui("hash_size", "Hash Size");
|
||
|
|
u32 imet_version;
|
||
|
|
|
||
|
|
ui("imet_version", "Version");
|
||
|
|
|
||
|
|
u32 icon_size;
|
||
|
|
|
||
|
|
|
||
|
|
ui("icon_size", "icon.bin Size");
|
||
|
|
u32 banner_size;
|
||
|
|
|
||
|
|
ui("banner_size", "banner.bin Size");
|
||
|
|
u32 sound_size;
|
||
|
|
|
||
|
|
ui("sound_size", "sound.bin Size");
|
||
|
|
|
||
|
|
u32 flag1;
|
||
|
|
|
||
|
|
|
||
|
|
ui("flag1", "Flag");
|
||
|
|
|
||
|
|
skip_tree("localized_names");
|
||
|
|
lang_idx = 0;
|
||
|
|
repeat(10) {
|
||
|
|
name_data = read(84);
|
||
|
|
ctx_set("_bnr_lang_idx", lang_idx);
|
||
|
|
name_child = name_data |> parse wii_bnr_name_row;
|
||
|
|
push("localized_names", name_child);
|
||
|
|
lang_idx = lang_idx + 1;
|
||
|
|
}
|
||
|
|
ui_table("localized_names", "localized_names", "Language,ChannelName");
|
||
|
|
|
||
|
|
_zeroes = read(588);
|
||
|
|
md5_hash = hex(read(16));
|
||
|
|
|
||
|
|
ui("md5_hash", "MD5 Hash");
|
||
|
|
|
||
|
|
u8_archive_offset = pos();
|
||
|
|
|
||
|
|
|
||
|
|
ui("u8_archive_offset", "U8 Archive Offset");
|
||
|
|
remaining = size() - pos();
|
||
|
|
|
||
|
|
if (remaining > 32) {
|
||
|
|
u8_magic_check = u32at(pos());
|
||
|
|
if (u8_magic_check == 0x55AA382D) {
|
||
|
|
archive_type = "U8 Archive";
|
||
|
|
|
||
|
|
ui("archive_type", "Archive Type");
|
||
|
|
|
||
|
|
u8_magic = hex(read(4));
|
||
|
|
|
||
|
|
|
||
|
|
ui("u8_magic", "U8 Magic");
|
||
|
|
u32 root_node_offset;
|
||
|
|
|
||
|
|
ui("root_node_offset", "Root Node Offset");
|
||
|
|
u32 header_size;
|
||
|
|
|
||
|
|
ui("header_size", "Header Size");
|
||
|
|
u32 data_offset;
|
||
|
|
|
||
|
|
ui("data_offset", "Data Offset");
|
||
|
|
_u8_reserved = read(16);
|
||
|
|
|
||
|
|
seek(u8_archive_offset + root_node_offset + 8);
|
||
|
|
u32 total_nodes;
|
||
|
|
|
||
|
|
ui("total_nodes", "Total Nodes");
|
||
|
|
|
||
|
|
seen_dirs = ",";
|
||
|
|
seen_offsets = ",";
|
||
|
|
|
||
|
|
seek(u8_archive_offset + root_node_offset);
|
||
|
|
node_idx = 0;
|
||
|
|
repeat(total_nodes) {
|
||
|
|
u8 node_type;
|
||
|
|
u8 name_off_hi;
|
||
|
|
u16 name_off_lo;
|
||
|
|
name_offset = (name_off_hi * 65536) + name_off_lo;
|
||
|
|
u32 node_data_offset;
|
||
|
|
u32 node_size;
|
||
|
|
|
||
|
|
string_table_offset = u8_archive_offset + root_node_offset + (total_nodes * 12);
|
||
|
|
saved_pos = pos();
|
||
|
|
|
||
|
|
seek(string_table_offset + name_offset);
|
||
|
|
node_name = cstring();
|
||
|
|
seek(saved_pos);
|
||
|
|
|
||
|
|
if (node_idx > 0) {
|
||
|
|
offset_key = "," + node_data_offset + ",";
|
||
|
|
if (node_type == 0 && node_size > 0 && node_name != "") {
|
||
|
|
is_dupe = contains(seen_offsets, offset_key);
|
||
|
|
if (is_dupe == 0) {
|
||
|
|
seen_offsets = seen_offsets + node_data_offset + ",";
|
||
|
|
file_pos = u8_archive_offset + node_data_offset;
|
||
|
|
if (file_pos + node_size <= size()) {
|
||
|
|
ctx_set("_bnr_node_name", node_name);
|
||
|
|
ctx_set("_bnr_node_size", node_size);
|
||
|
|
ctx_set("_bnr_file_offset", file_pos);
|
||
|
|
seek(file_pos);
|
||
|
|
file_data = read(node_size);
|
||
|
|
file_child = file_data |> parse wii_bnr_u8_file;
|
||
|
|
push("files", file_child);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else if (node_type == 1 && node_name != "") {
|
||
|
|
dir_key = "," + node_name + ",";
|
||
|
|
is_dir_dupe = contains(seen_dirs, dir_key);
|
||
|
|
if (is_dir_dupe == 0) {
|
||
|
|
seen_dirs = seen_dirs + node_name + ",";
|
||
|
|
ctx_set("_bnr_node_name", node_name);
|
||
|
|
ctx_set("_bnr_node_size", node_size);
|
||
|
|
dummy = bytesat(0, 1);
|
||
|
|
dir_child = dummy |> parse wii_bnr_u8_directory;
|
||
|
|
push("directories", dir_child);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
seek(saved_pos);
|
||
|
|
node_idx = node_idx + 1;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
archive_type = "Unknown";
|
||
|
|
|
||
|
|
ui("archive_type", "Archive Type");
|
||
|
|
set_preview("data", read(remaining));
|
||
|
|
set_viewer("hex");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
file_size = size();
|
||
|
|
|
||
|
|
ui("file_size", "Total File Size");
|
||
|
|
}
|
||
|
|
|
||
|
|
type wii_bnr_name_row [display="Name"] byteorder BE
|
||
|
|
{
|
||
|
|
set_hidden();
|
||
|
|
lang_idx = ctx_get("_bnr_lang_idx");
|
||
|
|
|
||
|
|
if (lang_idx == 0) { language = "Japanese"; }
|
||
|
|
else if (lang_idx == 1) { language = "English"; }
|
||
|
|
else if (lang_idx == 2) { language = "German"; }
|
||
|
|
else if (lang_idx == 3) { language = "French"; }
|
||
|
|
else if (lang_idx == 4) { language = "Spanish"; }
|
||
|
|
else if (lang_idx == 5) { language = "Italian"; }
|
||
|
|
else if (lang_idx == 6) { language = "Dutch"; }
|
||
|
|
else if (lang_idx == 7) { language = "Chinese (Simplified)"; }
|
||
|
|
else if (lang_idx == 8) { language = "Chinese (Traditional)"; }
|
||
|
|
else if (lang_idx == 9) { language = "Korean"; }
|
||
|
|
else { language = "Unknown"; }
|
||
|
|
|
||
|
|
channel_name = wstring_be();
|
||
|
|
Language = language;
|
||
|
|
ChannelName = channel_name;
|
||
|
|
}
|
||
|
|
|
||
|
|
type wii_bnr_u8_directory [display="Directory"] byteorder BE
|
||
|
|
{
|
||
|
|
node_name = ctx_get("_bnr_node_name");
|
||
|
|
node_size = ctx_get("_bnr_node_size");
|
||
|
|
set_name(node_name);
|
||
|
|
name = node_name;
|
||
|
|
|
||
|
|
ui("name", "Name");
|
||
|
|
next_sibling = node_size;
|
||
|
|
|
||
|
|
ui("next_sibling", "Next Sibling Index");
|
||
|
|
}
|
||
|
|
|
||
|
|
type wii_bnr_u8_file [display="File"] byteorder BE
|
||
|
|
{
|
||
|
|
node_name = ctx_get("_bnr_node_name");
|
||
|
|
set_name(node_name);
|
||
|
|
file_size = size();
|
||
|
|
|
||
|
|
ui("file_size", "Size");
|
||
|
|
|
||
|
|
if (size() >= 32) {
|
||
|
|
magic_check = ascii(bytesat(0, 4));
|
||
|
|
if (magic_check == "IMD5") {
|
||
|
|
imd5_magic = ascii(read(4));
|
||
|
|
|
||
|
|
ui("imd5_magic", "Magic");
|
||
|
|
u32 payload_size;
|
||
|
|
|
||
|
|
ui("payload_size", "Payload Size");
|
||
|
|
_imd5_zeroes = read(8);
|
||
|
|
imd5_md5 = hex(read(16));
|
||
|
|
|
||
|
|
ui("imd5_md5", "MD5 Hash");
|
||
|
|
if (pos() + 4 <= size()) {
|
||
|
|
inner_magic = ascii(bytesat(pos(), 4));
|
||
|
|
if (inner_magic == "LZ77") {
|
||
|
|
compression = "LZ77";
|
||
|
|
|
||
|
|
ui("compression", "Compression");
|
||
|
|
lz77_magic = ascii(read(4));
|
||
|
|
|
||
|
|
ui("lz77_magic", "LZ77 Magic");
|
||
|
|
u32 decompressed_size;
|
||
|
|
|
||
|
|
ui("decompressed_size", "Decompressed Size");
|
||
|
|
set_preview(node_name, read(size() - pos()));
|
||
|
|
set_viewer("hex");
|
||
|
|
} else if (inner_magic == "RIFF") {
|
||
|
|
// WAV audio inside IMD5 container (sound.bin)
|
||
|
|
compression = "None (WAV)";
|
||
|
|
|
||
|
|
ui("compression", "Compression");
|
||
|
|
wav_data = read(size() - pos());
|
||
|
|
wav_size = len(wav_data);
|
||
|
|
|
||
|
|
ui("wav_size", "WAV Size");
|
||
|
|
wav_name = "sound.wav";
|
||
|
|
if (ends_with(node_name, ".bin")) {
|
||
|
|
wav_name = substr(node_name, 0, len(node_name) - 4) + ".wav";
|
||
|
|
}
|
||
|
|
set_preview(wav_name, wav_data);
|
||
|
|
set_viewer("audio");
|
||
|
|
} else {
|
||
|
|
compression = "None";
|
||
|
|
|
||
|
|
ui("compression", "Compression");
|
||
|
|
set_preview(node_name, read(size() - pos()));
|
||
|
|
set_viewer("hex");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else if (magic_check == "BNS ") {
|
||
|
|
parse_here("wii_bns");
|
||
|
|
} else {
|
||
|
|
seek(0);
|
||
|
|
set_preview(node_name, read(size()));
|
||
|
|
set_viewer("hex");
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
set_preview(node_name, read(size()));
|
||
|
|
set_viewer("hex");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
type wii_bns [display="BNS Audio"] byteorder BE
|
||
|
|
{
|
||
|
|
magic = ascii(read(4));
|
||
|
|
|
||
|
|
ui("magic", "Magic");
|
||
|
|
u32 endian_check;
|
||
|
|
|
||
|
|
ui("endian_check", "Endian Check");
|
||
|
|
u32 bns_file_size;
|
||
|
|
|
||
|
|
ui("bns_file_size", "File Size");
|
||
|
|
u16 header_size;
|
||
|
|
|
||
|
|
ui("header_size", "Header Size");
|
||
|
|
u16 chunk_count;
|
||
|
|
|
||
|
|
ui("chunk_count", "Chunk Count");
|
||
|
|
chunk_idx = 0;
|
||
|
|
repeat(chunk_count) {
|
||
|
|
u32 chunk_offset;
|
||
|
|
|
||
|
|
ui("chunk_offset", "Chunk Offset");
|
||
|
|
u32 chunk_size;
|
||
|
|
|
||
|
|
ui("chunk_size", "Chunk Size");
|
||
|
|
ctx_set("_bns_chunk_" + chunk_idx + "_offset", chunk_offset);
|
||
|
|
ctx_set("_bns_chunk_" + chunk_idx + "_size", chunk_size);
|
||
|
|
chunk_idx = chunk_idx + 1;
|
||
|
|
}
|
||
|
|
total_size = size();
|
||
|
|
|
||
|
|
ui("total_size", "Total Size");
|
||
|
|
if (pos() < size()) { set_preview("audio.bns", read(size() - pos())); set_viewer("audio"); }
|
||
|
|
}
|
||
|
|
|
||
|
|
type wii_imd5 [display="IMD5 Container"] byteorder BE
|
||
|
|
{
|
||
|
|
magic = ascii(read(4));
|
||
|
|
|
||
|
|
ui("magic", "Magic");
|
||
|
|
u32 payload_size;
|
||
|
|
|
||
|
|
ui("payload_size", "Payload Size");
|
||
|
|
_zeroes = read(8);
|
||
|
|
md5_hash = hex(read(16));
|
||
|
|
|
||
|
|
ui("md5_hash", "MD5 Hash");
|
||
|
|
if (pos() + 4 <= size()) {
|
||
|
|
inner_magic = ascii(bytesat(pos(), 4));
|
||
|
|
if (inner_magic == "LZ77") {
|
||
|
|
compression = "LZ77";
|
||
|
|
|
||
|
|
ui("compression", "Compression");
|
||
|
|
lz77_magic = ascii(read(4));
|
||
|
|
|
||
|
|
ui("lz77_magic", "LZ77 Magic");
|
||
|
|
u32 decompressed_size;
|
||
|
|
|
||
|
|
ui("decompressed_size", "Decompressed Size");
|
||
|
|
set_preview("imd5_data.bin", read(size() - pos()));
|
||
|
|
set_viewer("hex");
|
||
|
|
} else {
|
||
|
|
compression = "None";
|
||
|
|
|
||
|
|
ui("compression", "Compression");
|
||
|
|
set_preview("imd5_data.bin", read(size() - pos()));
|
||
|
|
set_viewer("hex");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
imd5_file_size = size();
|
||
|
|
|
||
|
|
ui("imd5_file_size", "Total File Size");
|
||
|
|
}
|