From d3006b6d05f7995c6a49d67401293f1266b3ea1f Mon Sep 17 00:00:00 2001 From: metamuffin Date: Thu, 13 Mar 2025 19:56:15 +0100 Subject: move SerializedFile functions to impl --- src/serialized_file.rs | 409 +++++++++++++++++++++++++------------------------ 1 file changed, 206 insertions(+), 203 deletions(-) (limited to 'src/serialized_file.rs') diff --git a/src/serialized_file.rs b/src/serialized_file.rs index 3570a91..b56fa3a 100644 --- a/src/serialized_file.rs +++ b/src/serialized_file.rs @@ -76,229 +76,232 @@ pub struct SerializedFileHeader { pub target_platform: u32, } -pub fn read_serialized_file_header(mut file: impl Read + Seek) -> Result { - let mut metadata_size = file.read_u32_be()?; - let mut file_size = file.read_u32_be()? as u64; - let format = file.read_u32_be()?; - let mut data_offset = file.read_u32_be()? as u64; - - if format >= 1000 { - bail!("bad format version {format:x}") - } - info!("File format version: {format}"); - - assert!(format >= 9); - let e = match file.read_u32_be()? { - 0 => Endianness::Little, - _ => Endianness::Big, - }; - debug!("endianess={e:?}"); - - if format >= 22 { - metadata_size = file.read_u32_be()?; - file_size = file.read_u64_be()?; - data_offset = file.read_u64_be()?; - file.read_u64_be()?; +impl SerializedFileHeader { + pub fn read(mut file: impl Read + Seek) -> Result { + let mut metadata_size = file.read_u32_be()?; + let mut file_size = file.read_u32_be()? as u64; + let format = file.read_u32_be()?; + let mut data_offset = file.read_u32_be()? as u64; + + if format >= 1000 { + bail!("bad format version {format:x}") + } + info!("File format version: {format}"); + + assert!(format >= 9); + let e = match file.read_u32_be()? { + 0 => Endianness::Little, + _ => Endianness::Big, + }; + debug!("endianess={e:?}"); + + if format >= 22 { + metadata_size = file.read_u32_be()?; + file_size = file.read_u64_be()?; + data_offset = file.read_u64_be()?; + file.read_u64_be()?; + } + debug!("metadata_size={metadata_size}"); + debug!("file_size={file_size}"); + debug!("data_offset={data_offset}"); + + let generator_version = file.read_cstr()?; + let target_platform = file.read_u32_le()?; + info!("Generator version: {generator_version:?}"); + debug!("target_platform={target_platform}"); + Ok(Self { + data_offset, + _file_size: file_size, + endianness: e, + format, + _metadata_size: metadata_size, + target_platform, + generator_version, + }) } - debug!("metadata_size={metadata_size}"); - debug!("file_size={file_size}"); - debug!("data_offset={data_offset}"); - - let generator_version = file.read_cstr()?; - let target_platform = file.read_u32_le()?; - info!("Generator version: {generator_version:?}"); - debug!("target_platform={target_platform}"); - Ok(SerializedFileHeader { - data_offset, - _file_size: file_size, - endianness: e, - format, - _metadata_size: metadata_size, - target_platform, - generator_version, - }) } - -pub fn read_serialized_file(mut file: impl Read + Seek) -> Result { - let h = read_serialized_file_header(&mut file)?; - let e = h.endianness; - - let has_type_trees = file.read_u8()? != 0; - let num_types = file.read_u32(e)?; - debug!("has_type_trees={has_type_trees:?}"); - debug!("num_types={num_types}"); - - let mut types = Vec::new(); - - for _ in 0..num_types { - let class_id = file.read_i32(e)?; - let stripped_type = file.read_u8()? != 0; - let script_type_index = file.read_i16(e)?; - let mut script_id = 0; - // TODO reftype - if class_id == 114 { - script_id = file.read_u128_be()?; - } - let _old_hash = file.read_u128_be()?; - - trace!("class_id={class_id}"); - trace!("stripped_type={stripped_type}"); - trace!("script_type_index={script_type_index}"); - trace!("script_id={script_id}"); - - let mut type_deps = Vec::new(); - let mut type_tree = None; - if has_type_trees { - let num_nodes = file.read_u32(e)?; - let size = file.read_u32(e)?; - trace!("tree:num_nodes={num_nodes}"); - trace!("tree:size={size}"); - - let mut node_data = vec![0u8; num_nodes as usize * 32]; - file.read_exact(&mut node_data)?; - let mut node_data = Cursor::new(node_data); - let mut string_data = vec![0u8; size as usize]; - file.read_exact(&mut string_data)?; - - let get_string = |off: u32| { - let data = if off & 0x80000000 != 0 { - let off = off & 0x7fffffff; - if off as usize > COMMON_STRINGS.len() { - warn!("common strings missing index {off:08x}"); - b"" +impl SerializedFile { + pub fn read(mut file: impl Read + Seek) -> Result { + let h = SerializedFileHeader::read(&mut file)?; + let e = h.endianness; + + let has_type_trees = file.read_u8()? != 0; + let num_types = file.read_u32(e)?; + debug!("has_type_trees={has_type_trees:?}"); + debug!("num_types={num_types}"); + + let mut types = Vec::new(); + + for _ in 0..num_types { + let class_id = file.read_i32(e)?; + let stripped_type = file.read_u8()? != 0; + let script_type_index = file.read_i16(e)?; + let mut script_id = 0; + // TODO reftype + if class_id == 114 { + script_id = file.read_u128_be()?; + } + let _old_hash = file.read_u128_be()?; + + trace!("class_id={class_id}"); + trace!("stripped_type={stripped_type}"); + trace!("script_type_index={script_type_index}"); + trace!("script_id={script_id}"); + + let mut type_deps = Vec::new(); + let mut type_tree = None; + if has_type_trees { + let num_nodes = file.read_u32(e)?; + let size = file.read_u32(e)?; + trace!("tree:num_nodes={num_nodes}"); + trace!("tree:size={size}"); + + let mut node_data = vec![0u8; num_nodes as usize * 32]; + file.read_exact(&mut node_data)?; + let mut node_data = Cursor::new(node_data); + let mut string_data = vec![0u8; size as usize]; + file.read_exact(&mut string_data)?; + + let get_string = |off: u32| { + let data = if off & 0x80000000 != 0 { + let off = off & 0x7fffffff; + if off as usize > COMMON_STRINGS.len() { + warn!("common strings missing index {off:08x}"); + b"" + } else { + &COMMON_STRINGS[off as usize..] + } } else { - &COMMON_STRINGS[off as usize..] - } - } else { - &string_data[off as usize..] + &string_data[off as usize..] + }; + String::from_utf8( + data.iter() + .copied() + .take_while(|e| *e != 0) + .collect::>(), + ) }; - String::from_utf8( - data.iter() - .copied() - .take_while(|e| *e != 0) - .collect::>(), - ) - }; - let mut parents: Vec = vec![]; - for _ in 0..num_nodes { - let node = TypeTreeNode { - version: node_data.read_u16(e)?, - level: node_data.read_u8()?, - type_flags: node_data.read_u8()?, - type_string: get_string(node_data.read_u32(e)?)?, - name_string: get_string(node_data.read_u32(e)?)?, - byte_size: node_data.read_i32(e)?, - index: node_data.read_i32(e)?, - flags: node_data.read_i32(e)?, - ref_type_hash: node_data.read_u64(e)?, - children: vec![], - }; - if node.level == 0 && !parents.is_empty() { - warn!("unexpected toplevel typetree node"); - parents.clear(); + let mut parents: Vec = vec![]; + for _ in 0..num_nodes { + let node = TypeTreeNode { + version: node_data.read_u16(e)?, + level: node_data.read_u8()?, + type_flags: node_data.read_u8()?, + type_string: get_string(node_data.read_u32(e)?)?, + name_string: get_string(node_data.read_u32(e)?)?, + byte_size: node_data.read_i32(e)?, + index: node_data.read_i32(e)?, + flags: node_data.read_i32(e)?, + ref_type_hash: node_data.read_u64(e)?, + children: vec![], + }; + if node.level == 0 && !parents.is_empty() { + warn!("unexpected toplevel typetree node"); + parents.clear(); + } + 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() > node.level as usize { + while parents.len() > 1 { 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(); + type_tree = parents.pop(); - if h.format >= 21 { - let num_deps = file.read_u32(e)?; - trace!("num_deps={num_deps}"); - for _ in 0..num_deps { - type_deps.push(file.read_u32(e)?); + if h.format >= 21 { + let num_deps = file.read_u32(e)?; + trace!("num_deps={num_deps}"); + for _ in 0..num_deps { + type_deps.push(file.read_u32(e)?); + } } } - } - types.push(SeralizedType { - class_id, - script_id, - script_type_index, - stripped_type, - type_deps, - type_tree, - }) - } + types.push(SeralizedType { + class_id, + script_id, + script_type_index, + stripped_type, + type_deps, + type_tree, + }) + } - let num_objects = file.read_u32(e)?; - debug!("num_objects={num_objects}"); - let mut objects = Vec::new(); - for _ in 0..num_objects { - file.align(4)?; - let path_id = file.read_i64(e)?; - let data_offset = if h.format >= 22 { - file.read_u64(e)? - } else { - file.read_u32(e)? as u64 - } + h.data_offset; - let data_size = file.read_u32(e)?; - let type_id = file.read_i32(e)?; - objects.push(ObjectInfo { - data_offset, - data_size, - path_id, - type_id, - }) - } + let num_objects = file.read_u32(e)?; + debug!("num_objects={num_objects}"); + let mut objects = Vec::new(); + for _ in 0..num_objects { + file.align(4)?; + let path_id = file.read_i64(e)?; + let data_offset = if h.format >= 22 { + file.read_u64(e)? + } else { + file.read_u32(e)? as u64 + } + h.data_offset; + let data_size = file.read_u32(e)?; + let type_id = file.read_i32(e)?; + objects.push(ObjectInfo { + data_offset, + data_size, + path_id, + type_id, + }) + } - let num_scripts = file.read_u32(e)?; - debug!("num_scripts={num_scripts}"); - let mut scripts = Vec::new(); - for _ in 0..num_scripts { - let file_index = file.read_u32(e)?; - file.align(4)?; - let identifier = file.read_i64(e)?; - scripts.push(Script { - file_index, - identifier, - }) - } + let num_scripts = file.read_u32(e)?; + debug!("num_scripts={num_scripts}"); + let mut scripts = Vec::new(); + for _ in 0..num_scripts { + let file_index = file.read_u32(e)?; + file.align(4)?; + let identifier = file.read_i64(e)?; + scripts.push(Script { + file_index, + identifier, + }) + } - let num_externals = file.read_u32(e)?; - debug!("num_externals={num_externals}"); - let mut externals = Vec::new(); - for _ in 0..num_externals { - let something = file.read_cstr()?; - let guid = file.read_u128_be()?; - let r#type = file.read_i32(e)?; - let path_name = file.read_cstr()?; - externals.push(External { - guid, - path_name, - something, - r#type, - }) - } + let num_externals = file.read_u32(e)?; + debug!("num_externals={num_externals}"); + let mut externals = Vec::new(); + for _ in 0..num_externals { + let something = file.read_cstr()?; + let guid = file.read_u128_be()?; + let r#type = file.read_i32(e)?; + let path_name = file.read_cstr()?; + externals.push(External { + guid, + path_name, + something, + r#type, + }) + } - if h.format >= 20 { - let num_ref_types = file.read_i32(e)?; - debug!("num_ref_types={num_ref_types}"); - // let mut ref_types = Vec::new(); - for _ in 0..num_ref_types { - todo!() + if h.format >= 20 { + let num_ref_types = file.read_i32(e)?; + debug!("num_ref_types={num_ref_types}"); + // let mut ref_types = Vec::new(); + for _ in 0..num_ref_types { + todo!() + } } - } - let user_string = file.read_cstr()?; + let user_string = file.read_cstr()?; - Ok(SerializedFile { - header: h, - types, - externals, - endianness: e, - objects, - scripts, - user_string, - }) + Ok(SerializedFile { + header: h, + types, + externals, + endianness: e, + objects, + scripts, + user_string, + }) + } } impl TypeTreeNode { -- cgit v1.2.3-70-g09d2