use crate::helper::{AlignExt, Endianness, ReadExt}; use crate::serialized_file::TypeTreeNode; use anyhow::Result; use log::{debug, trace}; use std::io::Seek; use std::{collections::BTreeMap, io::Read}; #[derive(Debug)] pub enum Value { Bool(bool), U8(u8), U16(u16), I16(i16), U32(u32), I32(i32), F32(f32), I64(i64), F64(f64), Array(Vec), Object { class: String, fields: BTreeMap, }, String(String), } pub fn read_value( ty: &TypeTreeNode, e: Endianness, data: &mut (impl Read + Seek), ) -> Result { let r = match ty.type_string.as_str() { "char" => Ok(Value::U8(data.read_u8()?)), "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)?)), "SInt16" => Ok(Value::I16(data.read_i16(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| { if let Value::U8(x) = e { x } else { unreachable!() } }) .collect::>(); Ok(Value::String(String::from_utf8(bytes)?)) } "Array" => { 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)) } _ => { if ty.children.is_empty() && ty.byte_size != -1 { 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(), }) } }; if ty.post_align() { data.align(4)?; } r }