diff options
author | metamuffin <metamuffin@disroot.org> | 2025-03-12 22:39:58 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-03-12 22:39:58 +0100 |
commit | 5555c8bbefb4f52f5002603eb91b6c95cbdd97e4 (patch) | |
tree | 208e88359deb3cf5f7e2a4135693f12d76ad97e1 /src/object/read.rs | |
parent | 4906844cbfd2717a29b434fb7d8f90c5117fddd5 (diff) | |
download | unity-tools-5555c8bbefb4f52f5002603eb91b6c95cbdd97e4.tar unity-tools-5555c8bbefb4f52f5002603eb91b6c95cbdd97e4.tar.bz2 unity-tools-5555c8bbefb4f52f5002603eb91b6c95cbdd97e4.tar.zst |
more parsing helpers
Diffstat (limited to 'src/object/read.rs')
-rw-r--r-- | src/object/read.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/src/object/read.rs b/src/object/read.rs new file mode 100644 index 0000000..5adbe3f --- /dev/null +++ b/src/object/read.rs @@ -0,0 +1,100 @@ +use super::Value; +use crate::helper::{AlignExt, Endianness, ReadExt}; +use crate::serialized_file::TypeTreeNode; +use anyhow::{Result, bail}; +use log::trace; +use std::io::Seek; +use std::{collections::BTreeMap, io::Read}; + +pub fn read_value( + ty: &TypeTreeNode, + e: Endianness, + data: &mut (impl Read + Seek), +) -> Result<Value> { + let mut align = false; + let pos_before = data.stream_position()?; + let r = match ty.type_string.as_str() { + "char" => { + assert_eq!(ty.byte_size, 1); + Ok(Value::U8(data.read_u8()?)) + } + "Type*" => Ok(Value::U32(data.read_u32(e)?)), + "int" => Ok(Value::I32(data.read_i32(e)?)), + "unsigned int" => Ok(Value::U32(data.read_u32(e)?)), + "UInt8" => Ok(Value::U8(data.read_u8()?)), + "UInt16" => Ok(Value::U16(data.read_u16(e)?)), + "UInt32" => Ok(Value::U32(data.read_u32(e)?)), + "UInt64" => Ok(Value::U64(data.read_u64(e)?)), + "SInt8" => Ok(Value::I8(data.read_i8()?)), + "SInt16" => Ok(Value::I16(data.read_i16(e)?)), + "SInt32" => Ok(Value::I32(data.read_i32(e)?)), + "SInt64" => Ok(Value::I64(data.read_i64(e)?)), + "bool" => Ok(Value::Bool(data.read_u8()? != 0)), + "float" => { + data.align(4)?; + Ok(Value::F32(data.read_f32(e)?)) + } + "double" => { + data.align(4)?; + Ok(Value::F64(data.read_f64(e)?)) + } + "string" => { + let Value::Array(arr) = read_value(&ty.children[0], e, data)? else { + unreachable!() + }; + let bytes = arr + .into_iter() + .map(|e| match e { + Value::U8(x) => x, + _ => unreachable!(), + }) + .collect::<Vec<_>>(); + Ok(Value::String(String::from_utf8(bytes)?)) + } + "Array" => { + align |= ty.children[0].post_align(); + assert_eq!(ty.byte_size, -1); + let Value::I32(size) = read_value(&ty.children[0], e, data)? else { + unreachable!() + }; + trace!("array of size {size}"); + let mut elems = Vec::new(); + for _ in 0..size { + elems.push(read_value(&ty.children[1], e, data)?); + } + Ok(Value::Array(elems)) + } + "TypelessData" => { + let len = data.read_u32(e)?; + let mut buf = vec![0u8; len as usize]; + data.read_exact(&mut buf)?; + Ok(Value::Typeless(buf)) + } + _ => { + if ty.children.is_empty() && ty.byte_size != 0 { + todo!("need type {:?}", ty.type_string); + } + let mut fields = BTreeMap::new(); + for c in &ty.children { + fields.insert(c.name_string.clone(), read_value(&c, e, data)?); + } + Ok(Value::Object { + fields, + class: ty.type_string.clone(), + }) + } + }; + let pos_after = data.stream_position()?; + if ty.byte_size != -1 && pos_after - pos_before < ty.byte_size as u64 { + bail!( + "did not read enough data ({} expected, {} actual)", + ty.byte_size, + pos_after - pos_before + ); + } + if align || ty.post_align() { + trace!("post align"); + data.align(4)?; + } + r +} |