diff options
author | metamuffin <metamuffin@disroot.org> | 2025-03-13 20:10:32 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2025-03-13 20:10:32 +0100 |
commit | 8f80baff4d18b67859eded67b8c5097324693862 (patch) | |
tree | 380c5a9bfbd427c8363032a231b1da1fb30db960 /src/object/read.rs | |
parent | d3006b6d05f7995c6a49d67401293f1266b3ea1f (diff) | |
download | unity-tools-8f80baff4d18b67859eded67b8c5097324693862.tar unity-tools-8f80baff4d18b67859eded67b8c5097324693862.tar.bz2 unity-tools-8f80baff4d18b67859eded67b8c5097324693862.tar.zst |
read object abstraction
Diffstat (limited to 'src/object/read.rs')
-rw-r--r-- | src/object/read.rs | 170 |
1 files changed, 84 insertions, 86 deletions
diff --git a/src/object/read.rs b/src/object/read.rs index 5adbe3f..641bdcc 100644 --- a/src/object/read.rs +++ b/src/object/read.rs @@ -6,95 +6,93 @@ 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)?); +impl Value { + pub fn read(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()?)) } - 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); + "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)?)) } - let mut fields = BTreeMap::new(); - for c in &ty.children { - fields.insert(c.name_string.clone(), read_value(&c, e, data)?); + "double" => { + data.align(4)?; + Ok(Value::F64(data.read_f64(e)?)) } - Ok(Value::Object { - fields, - class: ty.type_string.clone(), - }) + "string" => { + let Value::Array(arr) = Value::read(&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) = Value::read(&ty.children[0], e, data)? else { + unreachable!() + }; + trace!("array of size {size}"); + let mut elems = Vec::new(); + for _ in 0..size { + elems.push(Value::read(&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(), Value::read(&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 + ); } - }; - 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)?; + if align || ty.post_align() { + trace!("post align"); + data.align(4)?; + } + r } - r } |