diff --git a/src/archive/u8.rs b/src/archive/u8.rs index 42bd52b..aa57d8d 100644 --- a/src/archive/u8.rs +++ b/src/archive/u8.rs @@ -345,19 +345,3 @@ impl U8Archive { Ok(buf) } } - -// pub fn print_full_tree(dir: &Rc>, indent: usize) { -// let prefix = " ".repeat(indent); -// println!("{}D {}", prefix, dir.borrow().name); -// -// // Print subdirectories -// for subdir in &dir.borrow().dirs { -// print_full_tree(subdir, indent + 1); -// } -// -// // Print files -// for file in &dir.borrow().files { -// let file_name = &file.borrow().name; -// println!("{} F {}", prefix, file_name); -// } -// } diff --git a/src/bin/rustii/filetypes.rs b/src/bin/rustii/filetypes.rs index 4da2b69..ae0706c 100644 --- a/src/bin/rustii/filetypes.rs +++ b/src/bin/rustii/filetypes.rs @@ -4,7 +4,7 @@ // Common code for identifying Wii file types. use std::{str, fs::File}; -use std::io::Read; +use std::io::{Read, Seek, SeekFrom}; use std::path::Path; use regex::RegexBuilder; @@ -13,7 +13,8 @@ use regex::RegexBuilder; pub enum WiiFileType { Wad, Tmd, - Ticket + Ticket, + U8, } pub fn identify_file_type(input: &str) -> Option { @@ -35,14 +36,30 @@ pub fn identify_file_type(input: &str) -> Option { if input.extension().is_some_and(|f| f.eq_ignore_ascii_case("wad")) { return Some(WiiFileType::Wad); } - // Advanced WAD detection, where we read and compare the first 8 bytes (only if the path exists.) + // == U8 == + if input.extension().is_some_and(|f| f.eq_ignore_ascii_case("arc")) || + input.extension().is_some_and(|f| f.eq_ignore_ascii_case("app")) { + return Some(WiiFileType::U8); + } + + // == Advanced == + // These require reading the magic number of the file, so we only try this after everything + // else has been tried. These are separated from the other methods of detecting these types so + // that we only have to open the file for reading once. if input.exists() { let mut f = File::open(input).unwrap(); + // We need to read more bytes for WADs since they don't have a proper magic number. let mut magic_number = vec![0u8; 8]; f.read_exact(&mut magic_number).unwrap(); if magic_number == b"\x00\x00\x00\x20\x49\x73\x00\x00" || magic_number == b"\x00\x00\x00\x20\x69\x62\x00\x00" { return Some(WiiFileType::Wad); } + let mut magic_number = vec![0u8; 4]; + f.seek(SeekFrom::Start(0)).unwrap(); + f.read_exact(&mut magic_number).unwrap(); + if magic_number == b"\x55\xAA\x38\x2D" { + return Some(WiiFileType::U8); + } } // == No match found! == diff --git a/src/bin/rustii/info.rs b/src/bin/rustii/info.rs index 2b8f706..95fc05f 100644 --- a/src/bin/rustii/info.rs +++ b/src/bin/rustii/info.rs @@ -4,8 +4,11 @@ // Code for the info command in the rustii CLI. use std::{str, fs}; +use std::cell::RefCell; use std::path::Path; +use std::rc::Rc; use anyhow::{bail, Context, Result}; +use rustii::archive::u8; use rustii::{title, title::cert, title::tmd, title::ticket, title::wad, title::versions}; use crate::filetypes::{WiiFileType, identify_file_type}; @@ -240,6 +243,35 @@ fn print_wad_info(wad: wad::WAD) -> Result<()> { Ok(()) } +fn print_full_tree(dir: &Rc>, indent: usize) { + let prefix = " ".repeat(indent); + let dir_name = if !dir.borrow().name.is_empty() { + &dir.borrow().name + } else { + &String::from("root") + }; + println!("{}D {}", prefix, dir_name); + + // Print subdirectories + for subdir in &dir.borrow().dirs { + print_full_tree(subdir, indent + 1); + } + + // Print files + for file in &dir.borrow().files { + let file_name = &file.borrow().name; + println!("{} F {}", prefix, file_name); + } +} + +fn print_u8_info(u8_archive: u8::U8Archive) -> Result<()> { + println!("U8 Archive Info"); + println!(" Node Count: {}", u8_archive.node_tree.borrow().count()); + println!(" Archive Data:"); + print_full_tree(&u8_archive.node_tree, 2); + Ok(()) +} + pub fn info(input: &str) -> Result<()> { let in_path = Path::new(input); if !in_path.exists() { @@ -247,17 +279,21 @@ pub fn info(input: &str) -> Result<()> { } match identify_file_type(input) { Some(WiiFileType::Tmd) => { - let tmd = tmd::TMD::from_bytes(fs::read(in_path)?.as_slice()).with_context(|| "The provided TMD file could not be parsed, and is likely invalid.")?; + let tmd = tmd::TMD::from_bytes(&fs::read(in_path)?).with_context(|| "The provided TMD file could not be parsed, and is likely invalid.")?; print_tmd_info(tmd, None)?; }, Some(WiiFileType::Ticket) => { - let ticket = ticket::Ticket::from_bytes(fs::read(in_path)?.as_slice()).with_context(|| "The provided Ticket file could not be parsed, and is likely invalid.")?; + let ticket = ticket::Ticket::from_bytes(&fs::read(in_path)?).with_context(|| "The provided Ticket file could not be parsed, and is likely invalid.")?; print_ticket_info(ticket, None)?; }, Some(WiiFileType::Wad) => { - let wad = wad::WAD::from_bytes(fs::read(in_path)?.as_slice()).with_context(|| "The provided WAD file could not be parsed, and is likely invalid.")?; + let wad = wad::WAD::from_bytes(&fs::read(in_path)?).with_context(|| "The provided WAD file could not be parsed, and is likely invalid.")?; print_wad_info(wad)?; }, + Some(WiiFileType::U8) => { + let u8_archive = u8::U8Archive::from_bytes(&fs::read(in_path)?).with_context(|| "The provided U8 archive could not be parsed, and is likely invalid.")?; + print_u8_info(u8_archive)?; + } None => { bail!("Information cannot be displayed for this file type."); } diff --git a/src/bin/rustii/title/fakesign.rs b/src/bin/rustii/title/fakesign.rs index 4034286..8bb30f4 100644 --- a/src/bin/rustii/title/fakesign.rs +++ b/src/bin/rustii/title/fakesign.rs @@ -57,7 +57,7 @@ pub fn fakesign(input: &str, output: &Option) -> Result<()> { fs::write(out_path, ticket.to_bytes()?).with_context(|| "Could not open output file for writing.")?; println!("Ticket fakesigned!"); }, - None => { + _ => { bail!("You can only fakesign TMDs, Tickets, and WADs!"); } }