// 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"); }