diff options
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/main.rs | 26 | ||||
-rw-r--r-- | src/object.rs | 4 | ||||
-rw-r--r-- | src/serialized_file.rs | 22 | ||||
-rw-r--r-- | src/unityfs.rs | 36 |
5 files changed, 74 insertions, 15 deletions
@@ -2,3 +2,4 @@ pub mod unityfs; pub mod helper; pub mod common_strings; pub mod serialized_file; +pub mod object; diff --git a/src/main.rs b/src/main.rs index beab8a1..450f4a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,8 @@ -use std::{env::args, fs::File, io::BufReader}; +use std::{ + env::args, + fs::File, + io::{BufReader, Read, Seek, SeekFrom}, +}; use unity_tools::{serialized_file::read_serialized_file, unityfs::UnityFS}; fn main() -> anyhow::Result<()> { @@ -10,12 +14,28 @@ fn main() -> anyhow::Result<()> { if node.name.ends_with(".resource") || node.name.ends_with(".resS") { continue; } - let cab = fs.read(&node)?; + let mut cab = fs.read(&node)?; // let mut writer = File::create(format!("/tmp/{}", node.name))?; // std::io::copy(&mut cab, &mut writer)?; // continue; - let file = read_serialized_file(cab)?; + let file = read_serialized_file(&mut cab)?; + + for ob in file.objects { + cab.seek(SeekFrom::Start(ob.data_offset))?; + let ob_data = cab.by_ref().take(ob.data_size as u64); + + eprintln!("{:#?}", ob); + let typetree = if ob.type_id < 0 { + unimplemented!() + } else { + file.types + .iter() + .find(|t| t.class_id == ob.type_id) + .expect("unknown type") + }; + } + // eprintln!("{:#?}", file.types); } Ok(()) diff --git a/src/object.rs b/src/object.rs new file mode 100644 index 0000000..9875517 --- /dev/null +++ b/src/object.rs @@ -0,0 +1,4 @@ +use crate::serialized_file::TypeTreeNode; +use std::io::Read; + +pub fn read_value(ty: TypeTreeNode, data: &mut impl Read) {} diff --git a/src/serialized_file.rs b/src/serialized_file.rs index f32b3a3..4b348e0 100644 --- a/src/serialized_file.rs +++ b/src/serialized_file.rs @@ -17,6 +17,8 @@ pub struct TypeTreeNode { pub index: i32, pub flags: i32, pub ref_type_hash: u64, + + pub children: Vec<TypeTreeNode>, } #[derive(Debug)] @@ -26,7 +28,7 @@ pub struct SeralizedType { pub script_type_index: i16, pub script_id: u128, - pub type_tree: Vec<TypeTreeNode>, + pub type_tree: Option<TypeTreeNode>, pub type_deps: Vec<u32>, } @@ -115,7 +117,7 @@ pub fn read_serialized_file(mut file: impl Read + Seek) -> Result<SerializedFile trace!("script_id={script_id}"); let mut type_deps = Vec::new(); - let mut type_tree = Vec::new(); + let mut type_tree = None; if has_type_trees { let num_nodes = file.read_u32(e)?; let size = file.read_u32(e)?; @@ -143,8 +145,9 @@ pub fn read_serialized_file(mut file: impl Read + Seek) -> Result<SerializedFile ) }; + let mut parents: Vec<TypeTreeNode> = vec![]; for _ in 0..num_nodes { - type_tree.push(TypeTreeNode { + let node = TypeTreeNode { version: node_data.read_u16(e)?, level: node_data.read_u8()?, type_flags: node_data.read_u8()?, @@ -154,8 +157,19 @@ pub fn read_serialized_file(mut file: impl Read + Seek) -> Result<SerializedFile index: node_data.read_i32(e)?, flags: node_data.read_i32(e)?, ref_type_hash: node_data.read_u64(e)?, - }); + children: vec![], + }; + while parents.len() > node.level as usize { + let n = parents.pop().unwrap(); + parents.last_mut().unwrap().children.push(n) + } + parents.push(node); + } + while parents.len() > 1 { + let n = parents.pop().unwrap(); + parents.last_mut().unwrap().children.push(n) } + type_tree = parents.pop(); if format >= 21 { let num_deps = file.read_u32(e)?; diff --git a/src/unityfs.rs b/src/unityfs.rs index d7659b8..bd0c7bb 100644 --- a/src/unityfs.rs +++ b/src/unityfs.rs @@ -1,7 +1,7 @@ use crate::helper::{AlignExt, ReadExt}; use anyhow::{Result, anyhow, bail}; use log::{debug, info, trace}; -use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Take}; +use std::io::{Cursor, Error, ErrorKind, Read, Seek, SeekFrom}; pub struct UnityFS<T> { nodes: Vec<NodeInfo>, @@ -23,7 +23,9 @@ struct BlockInfo { } pub struct NodeReader<'a, T> { - inner: Take<&'a mut BlocksReader<T>>, + inner: &'a mut BlocksReader<T>, + position: u64, + offset: u64, size: u64, } @@ -131,7 +133,9 @@ impl<T: Read + Seek> UnityFS<T> { self.reader.seek(SeekFrom::Start(node.offset))?; Ok(NodeReader { size: node.size, - inner: (&mut self.reader).take(node.size), + offset: node.offset, + position: 0, + inner: &mut self.reader, }) } } @@ -213,10 +217,14 @@ impl<T: Seek + Read> Seek for BlocksReader<T> { let block_off = pos - decomp_off; debug!("target is block={i} offset={block_off}"); - debug!("seek comp to {comp_off}"); self.inner.seek(SeekFrom::Start(comp_off))?; - self.nblock_index = i; - self.load_next_block()?; + if self.nblock_index == i + 1 { + debug!("intra-block seek") + } else { + debug!("seek comp to {comp_off}"); + self.nblock_index = i; + self.load_next_block()?; + } self.cblock_off = block_off as usize; Ok(pos) @@ -225,7 +233,11 @@ impl<T: Seek + Read> Seek for BlocksReader<T> { impl<T: Read> Read for NodeReader<'_, T> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { - self.inner.read(buf) + let bytes_left = self.size - self.position; + let end = buf.len().min(bytes_left as usize); + let size = self.inner.read(&mut buf[..end])?; + self.position += size as u64; + Ok(size) } } impl<T: Seek + Read> Seek for NodeReader<'_, T> { @@ -237,11 +249,19 @@ impl<T: Seek + Read> Seek for NodeReader<'_, T> { } Ok(self.stream_position()?) } + SeekFrom::Start(n) => { + debug!("seek node to {n} (off={})", self.offset); + if n > self.size { + return Err(Error::new(ErrorKind::NotSeekable, "seek out of bounds")); + } + self.position = n; + self.inner.seek(SeekFrom::Start(self.offset + n)) + } _ => unimplemented!(), } } fn stream_position(&mut self) -> std::io::Result<u64> { - Ok(self.size - self.inner.limit()) + Ok(self.position) } } |