U8 archive unpacking command now functional

This commit is contained in:
Campbell 2025-04-09 09:18:29 -04:00
parent 884657268b
commit 7cef25d8f0
Signed by: NinjaCheetah
GPG Key ID: 39C2500E1778B156
2 changed files with 62 additions and 11 deletions

View File

@ -19,18 +19,18 @@ pub enum U8Error {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct U8Node { pub struct U8Node {
node_type: u8, pub node_type: u8,
name_offset: u32, // This is really type u24, so the most significant byte will be ignored. pub name_offset: u32, // This is really type u24, so the most significant byte will be ignored.
data_offset: u32, pub data_offset: u32,
size: u32, pub size: u32,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct U8Archive { pub struct U8Archive {
u8_nodes: Vec<U8Node>, pub u8_nodes: Vec<U8Node>,
file_names: Vec<String>, pub file_names: Vec<String>,
file_data: Vec<Vec<u8>>, pub file_data: Vec<Vec<u8>>,
root_node_offset: u32, root_node_offset: u32,
header_size: u32, header_size: u32,
data_offset: u32, data_offset: u32,

View File

@ -37,8 +37,59 @@ pub fn unpack_u8_archive(input: &str, output: &str) -> Result<()> {
if !in_path.exists() { if !in_path.exists() {
bail!("Source U8 archive \"{}\" could not be found.", input); bail!("Source U8 archive \"{}\" could not be found.", input);
} }
let u8_data = u8::U8Archive::from_bytes(&fs::read(in_path)?)?; let out_path = PathBuf::from(output);
println!("{:?}", u8_data); if out_path.exists() {
fs::write(Path::new(output), u8_data.to_bytes()?)?; 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<u32> = 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(&current_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(&current_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(()) Ok(())
} }