From 7cef25d8f0245c5e8969f0524a434f726ff02d2f Mon Sep 17 00:00:00 2001 From: NinjaCheetah <58050615+NinjaCheetah@users.noreply.github.com> Date: Wed, 9 Apr 2025 09:18:29 -0400 Subject: [PATCH] U8 archive unpacking command now functional --- src/archive/u8.rs | 16 +++++----- src/bin/rustii/archive/u8.rs | 57 ++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/archive/u8.rs b/src/archive/u8.rs index 5040793..15a1e26 100644 --- a/src/archive/u8.rs +++ b/src/archive/u8.rs @@ -19,18 +19,18 @@ pub enum U8Error { } #[derive(Clone, Debug)] -struct U8Node { - node_type: u8, - name_offset: u32, // This is really type u24, so the most significant byte will be ignored. - data_offset: u32, - size: u32, +pub struct U8Node { + pub node_type: u8, + pub name_offset: u32, // This is really type u24, so the most significant byte will be ignored. + pub data_offset: u32, + pub size: u32, } #[derive(Debug)] pub struct U8Archive { - u8_nodes: Vec, - file_names: Vec, - file_data: Vec>, + pub u8_nodes: Vec, + pub file_names: Vec, + pub file_data: Vec>, root_node_offset: u32, header_size: u32, data_offset: u32, diff --git a/src/bin/rustii/archive/u8.rs b/src/bin/rustii/archive/u8.rs index 8a51675..bfa9188 100644 --- a/src/bin/rustii/archive/u8.rs +++ b/src/bin/rustii/archive/u8.rs @@ -37,8 +37,59 @@ pub fn unpack_u8_archive(input: &str, output: &str) -> Result<()> { if !in_path.exists() { bail!("Source U8 archive \"{}\" could not be found.", input); } - let u8_data = u8::U8Archive::from_bytes(&fs::read(in_path)?)?; - println!("{:?}", u8_data); - fs::write(Path::new(output), u8_data.to_bytes()?)?; + let out_path = PathBuf::from(output); + if out_path.exists() { + if !out_path.is_dir() { + bail!("A file already exists with the specified directory name!"); + } + } else { + fs::create_dir(&out_path).with_context(|| format!("The output directory \"{}\" could not be created.", out_path.display()))?; + } + let u8_archive = u8::U8Archive::from_bytes(&fs::read(in_path).with_context(|| format!("Failed to open U8 archive \"{}\" for reading.", in_path.display()))?)?; + // This stores the path we're actively writing files to. + let mut current_dir = out_path.clone(); + // This is the order of directory nodes we've traversed down. + let mut parent_dirs: Vec = Vec::from([0]); + for i in 0..u8_archive.u8_nodes.len() { + match u8_archive.u8_nodes[i].node_type { + 1 => { + // Code for a directory node. + if u8_archive.u8_nodes[i].name_offset != 0 { + // If we're already at the correct level, make a new directory and push it to + // the parent_dirs vec. + if u8_archive.u8_nodes[i].data_offset == *parent_dirs.last().unwrap() { + current_dir = current_dir.join(&u8_archive.file_names[i]); + if !current_dir.exists() { + fs::create_dir(¤t_dir).with_context(|| format!("Failed to create directory \"{}\".", current_dir.display()))?; + } + parent_dirs.push(i as u32); + } + // Otherwise, go back up the path until we're at the correct level. + else { + while u8_archive.u8_nodes[i].data_offset != *parent_dirs.last().unwrap() { + parent_dirs.pop(); + } + parent_dirs.push(i as u32); + current_dir = out_path.clone(); + // Rebuild current working directory, and make sure all directories in the + // path exist. + for dir in &parent_dirs { + current_dir = current_dir.join(&u8_archive.file_names[*dir as usize]); + if !current_dir.exists() { + fs::create_dir(¤t_dir).with_context(|| format!("Failed to create directory \"{}\".", current_dir.display()))?; + } + } + } + } + }, + 0 => { + // Code for a file node. + fs::write(current_dir.join(&u8_archive.file_names[i]), &u8_archive.file_data[i]) + .with_context(|| format!("Failed to write file \"{}\" in directory \"{}\".", u8_archive.file_names[i], current_dir.display()))?; + }, + _ => bail!("Node at index {} has an invalid type! U8 archive cannot be unpacked.", i) + } + } + println!("Successfully unpacked U8 archive to directory \"{}\"!", out_path.display()); Ok(()) }