From edfb17205e6db49385447f281a5b8bddabd816cf Mon Sep 17 00:00:00 2001 From: lifegpc Date: Tue, 20 Jan 2026 17:36:27 +0800 Subject: [PATCH] WIP: update csx deser --- msg_tool_macro/src/lib.rs | 36 +-- src/scripts/entis_gls/csx/v2/img.rs | 255 +++++++++++++++ src/scripts/entis_gls/csx/v2/types.rs | 435 ++++++++++++++++++++++++++ 3 files changed, 708 insertions(+), 18 deletions(-) diff --git a/msg_tool_macro/src/lib.rs b/msg_tool_macro/src/lib.rs index 4608e4f..e4bf61d 100644 --- a/msg_tool_macro/src/lib.rs +++ b/msg_tool_macro/src/lib.rs @@ -220,7 +220,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { cur = Some(quote::quote! { let encoded = crate::utils::encoding::encode_string(encoding, &self.#field_name, true)?; let len = encoded.len() as #pstring_type; - len.pack(writer, big, encoding, info)?; + len.pack(writer, big, encoding, __info)?; writer.write_all(&encoded)?; }); } @@ -234,15 +234,15 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { return Err(anyhow::anyhow!("Vector length was not equal to {}", #fixed_vec)); } for item in &self.#field_name { - item.pack(writer, big, encoding, info)?; + item.pack(writer, big, encoding, __info)?; } }); } else if let Some(pvec_type) = pvec_type { cur = Some(quote::quote! { let len = self.#field_name.len() as #pvec_type; - len.pack(writer, big, encoding, info)?; + len.pack(writer, big, encoding, __info)?; for item in &self.#field_name { - item.pack(writer, big, encoding, info)?; + item.pack(writer, big, encoding, __info)?; } }); } @@ -251,7 +251,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } let p = cur.unwrap_or_else(|| { quote::quote! { - self.#field_name.pack(writer, big, encoding, info)?; + self.#field_name.pack(writer, big, encoding, __info)?; } }); if let Some(skip_if) = skip_if { @@ -266,7 +266,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { }); let output = quote::quote! { impl StructPack for #name { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding, info: &Option>) -> Result<()> { + fn pack(&self, writer: &mut W, big: bool, encoding: Encoding, __info: &Option>) -> Result<()> { #(#fields)* Ok(()) } @@ -412,7 +412,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { cur = Some(quote::quote! { let encoded = crate::utils::encoding::encode_string(encoding, &#field_name, true)?; let len = encoded.len() as #pstring_type; - len.pack(writer, big, encoding, info)?; + len.pack(writer, big, encoding, __info)?; writer.write_all(&encoded)?; }); } @@ -426,15 +426,15 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { return Err(anyhow::anyhow!("Vector length was not equal to {}", #fixed_vec)); } for item in &#field_name { - item.pack(writer, big, encoding, info)?; + item.pack(writer, big, encoding, __info)?; } }); } else if let Some(pvec_type) = pvec_type { cur = Some(quote::quote! { let len = #field_name.len() as #pvec_type; - len.pack(writer, big, encoding, info)?; + len.pack(writer, big, encoding, __info)?; for item in &#field_name { - item.pack(writer, big, encoding, info)?; + item.pack(writer, big, encoding, __info)?; } }); } @@ -443,7 +443,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { } let p = cur.unwrap_or_else(|| { quote::quote! { - #field_name.pack(writer, big, encoding, info)?; + #field_name.pack(writer, big, encoding, __info)?; } }); if let Some(skip_if) = skip_if { @@ -469,7 +469,7 @@ pub fn struct_pack_derive(input: TokenStream) -> TokenStream { }); let output = quote::quote! { impl StructPack for #ident { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding, info: &Option>) -> Result<()> { + fn pack(&self, writer: &mut W, big: bool, encoding: Encoding, __info: &Option>) -> Result<()> { match self { #(#variants)* } @@ -625,7 +625,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { }); } else if let Some(pstring_type) = pstring_type { cur = Some(quote::quote! { - let len = <#pstring_type>::unpack(reader, big, encoding, info)? as usize; + let len = <#pstring_type>::unpack(reader, big, encoding, __info)? as usize; let #field_name = reader.read_exact_vec(len)?; let #field_name = crate::utils::encoding::decode_to_string(encoding, &#field_name, true)?; }); @@ -636,12 +636,12 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { if segment.ident == "Vec" { if let Some(fixed_vec) = fixed_vec { cur = Some(quote::quote! { - let #field_name = reader.read_struct_vec(#fixed_vec, big, encoding, info)?; + let #field_name = reader.read_struct_vec(#fixed_vec, big, encoding, __info)?; }); } else if let Some(pvec_type) = pvec_type { cur = Some(quote::quote! { - let len = <#pvec_type>::unpack(reader, big, encoding, info)? as usize; - let #field_name = reader.read_struct_vec(len, big, encoding, info)?; + let len = <#pvec_type>::unpack(reader, big, encoding, __info)? as usize; + let #field_name = reader.read_struct_vec(len, big, encoding, __info)?; }); } } @@ -649,7 +649,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { } let p = cur.unwrap_or_else(|| { quote::quote! { - let #field_name = <#field_type>::unpack(reader, big, encoding, info)?; + let #field_name = <#field_type>::unpack(reader, big, encoding, __info)?; } }); if let Some(skip_if) = skip_if { @@ -672,7 +672,7 @@ pub fn struct_unpack_derive(input: TokenStream) -> TokenStream { }; let output = quote::quote! { impl StructUnpack for #name { - fn unpack(reader: &mut R, big: bool, encoding: Encoding, info: &Option>) -> Result { + fn unpack(reader: &mut R, big: bool, encoding: Encoding, __info: &Option>) -> Result { #(#smts)* Ok(Self #fields) } diff --git a/src/scripts/entis_gls/csx/v2/img.rs b/src/scripts/entis_gls/csx/v2/img.rs index 3ee3f62..86b6b8c 100644 --- a/src/scripts/entis_gls/csx/v2/img.rs +++ b/src/scripts/entis_gls/csx/v2/img.rs @@ -6,6 +6,7 @@ use crate::types::*; use crate::utils::struct_pack::*; use anyhow::Result; use std::collections::HashMap; +use std::io::Seek; const ID_HEADER: u64 = 0x2020726564616568; // header const ID_IMAGE: u64 = 0x2020206567616D69; @@ -36,6 +37,20 @@ pub struct ECSExecutionImage { image_global: Option, image_const: Option, image_shared: Option, + section_class_info: SectionClassInfo, + section_function: SectionFunction, + section_init_naked_func: SectionInitNakedFunc, + section_func_info: SectionFuncInfo, + section_symbol_info: Option, + section_global: Option, + section_data: Option, + section_const_string: SectionConstString, + section_link_info: Option, + section_link_info_ex: Option, + section_ref_func: Option, + section_ref_code: Option, + section_ref_class: Option, + section_import_native_func: SectionImportNativeFunc, } impl ECSExecutionImage { @@ -53,6 +68,20 @@ impl ECSExecutionImage { let mut image_global = None; let mut image_const = None; let mut image_shared = None; + let mut section_class_info = None; + let mut section_function = None; + let mut section_init_naked_func = None; + let mut section_func_info = None; + let mut section_symbol_info = None; + let mut section_global = None; + let mut section_data = None; + let mut section_const_string = None; + let mut section_link_info = None; + let mut section_link_info_ex = None; + let mut section_ref_func = None; + let mut section_ref_code = None; + let mut section_ref_class = None; + let mut section_import_native_func = None; while reader.pos < len { if len - reader.pos < 16 { break; @@ -80,6 +109,212 @@ impl ECSExecutionImage { ID_IMAGE_SHARED => { image_shared = Some(MemReader::new(reader.read_exact_vec(size as usize)?)); } + ID_CLASS_INFO => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_class_info = Some(SectionClassInfo::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::CLASS_INFO" + ); + crate::COUNTER.inc_warning(); + } + } + ID_FUNCTION => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_function = Some(SectionFunction::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::FUNCTION" + ); + crate::COUNTER.inc_warning(); + } + } + ID_INIT_NAKED_FUNC => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_init_naked_func = Some(SectionInitNakedFunc::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::INIT_NAKED_FUNC" + ); + crate::COUNTER.inc_warning(); + } + } + ID_FUNC_INFO => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_func_info = Some(SectionFuncInfo::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::FUNC_INFO" + ); + crate::COUNTER.inc_warning(); + } + } + ID_SYMBOL_INFO => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_symbol_info = Some(SectionSymbolInfo::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::SYMBOL_INFO" + ); + crate::COUNTER.inc_warning(); + } + } + ID_GLOBAL => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_global = Some(SectionGlobal::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!("WARNING: Some data is not parsed in ECSExecutionImage::GLOBAL"); + crate::COUNTER.inc_warning(); + } + } + ID_DATA => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_data = Some(SectionData::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!("WARNING: Some data is not parsed in ECSExecutionImage::DATA"); + crate::COUNTER.inc_warning(); + } + } + ID_CONST_STRING => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_const_string = Some(SectionConstString::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::CONST_STRING" + ); + crate::COUNTER.inc_warning(); + } + } + ID_LINK_INFO => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_link_info = Some(SectionLinkInfo::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::LINK_INFO" + ); + crate::COUNTER.inc_warning(); + } + } + ID_LINK_INFO_EX => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_link_info_ex = Some(SectionLinkInfoEx::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::LINK_INFO_EX" + ); + crate::COUNTER.inc_warning(); + } + } + ID_REF_FUNC => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_ref_func = Some(SectionRefFunc::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::REF_FUNC" + ); + crate::COUNTER.inc_warning(); + } + } + ID_REF_CODE => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_ref_code = Some(SectionRefCode::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::REF_CODE" + ); + crate::COUNTER.inc_warning(); + } + } + ID_REF_CLASS => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_ref_class = Some(SectionRefClass::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::REF_CLASS" + ); + crate::COUNTER.inc_warning(); + } + } + ID_IMPORT_NATIVE_FUNC => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_import_native_func = Some(SectionImportNativeFunc::unpack( + &mut mem, + false, + Encoding::Utf8, + &Some(Box::new(section_header.clone())), + )?); + if mem.stream_position()? != size { + eprintln!( + "WARNING: Some data is not parsed in ECSExecutionImage::IMPORT_NATIVE_FUNC" + ); + crate::COUNTER.inc_warning(); + } + } 0 => { break; } @@ -99,6 +334,26 @@ impl ECSExecutionImage { image_global, image_const, image_shared, + section_class_info: section_class_info + .ok_or_else(|| anyhow::anyhow!("Missing class info section"))?, + section_function: section_function + .ok_or_else(|| anyhow::anyhow!("Missing function section"))?, + section_init_naked_func: section_init_naked_func + .ok_or_else(|| anyhow::anyhow!("Missing init naked func section"))?, + section_func_info: section_func_info + .ok_or_else(|| anyhow::anyhow!("Missing func info section"))?, + section_symbol_info, + section_global, + section_data, + section_const_string: section_const_string + .ok_or_else(|| anyhow::anyhow!("Missing const string section"))?, + section_link_info, + section_link_info_ex, + section_ref_func, + section_ref_code, + section_ref_class, + section_import_native_func: section_import_native_func + .ok_or_else(|| anyhow::anyhow!("Missing import native func section"))?, }) } } diff --git a/src/scripts/entis_gls/csx/v2/types.rs b/src/scripts/entis_gls/csx/v2/types.rs index 7f4c14c..453bc2c 100644 --- a/src/scripts/entis_gls/csx/v2/types.rs +++ b/src/scripts/entis_gls/csx/v2/types.rs @@ -6,6 +6,7 @@ use anyhow::Result; use int_enum::IntEnum; use msg_tool_macro::{StructPack, StructUnpack}; use std::io::{Read, Seek, Write}; +use std::ops::{Deref, DerefMut}; #[repr(u8)] #[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] @@ -771,3 +772,437 @@ impl StructPack for TypedObject { Ok(()) } } + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct FieldInfoEntry { + pub name: WideString, + pub flags: u32, + pub type_object: TypedObject, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct TypeInfoEntry { + pub flags: u32, + pub type_object: TypedObject, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct PrototypeInfoEntry { + pub flags: u32, + pub name: WideString, + pub global_name: WideString, + pub return_type: TypeInfoEntry, + #[pvec(u32)] + pub arguments: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct MethodInfoEntry { + pub prototype_info: PrototypeInfoEntry, + pub func_class: WideString, + pub pointer_data: [u8; 40], +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct ClassInfoEntry { + pub flags: u32, + pub name: WideString, + pub global_name: WideString, + #[pvec(u32)] + pub base_class_info: Vec, + #[pvec(u32)] + pub base_class_cast_info: Vec, + #[pvec(u32)] + pub field_info: Vec, + #[pvec(u32)] + pub method_info: Vec, + #[pvec(u32)] + pub extra_data: Vec, +} + +#[derive(Clone, Debug)] +pub struct SectionClassInfo { + names: Vec, + infos: Vec, +} + +impl StructUnpack for SectionClassInfo { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let count = u32::unpack(reader, big, encoding, info)? as usize; + let mut names = Vec::with_capacity(count); + for _ in 0..count { + let name = WideString::unpack(reader, big, encoding, info)?; + names.push(name); + } + let mut infos = Vec::with_capacity(count); + for _ in 0..count { + let class_info = ClassInfoEntry::unpack(reader, big, encoding, info)?; + infos.push(class_info); + } + Ok(SectionClassInfo { names, infos }) + } +} + +impl StructPack for SectionClassInfo { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + let count = self.names.len() as u32; + if count != self.infos.len() as u32 { + return Err(anyhow::anyhow!( + "SectionClassInfo pack error: names count {} does not match infos count {}", + count, + self.infos.len() + )); + } + count.pack(writer, big, encoding, info)?; + for name in &self.names { + name.pack(writer, big, encoding, info)?; + } + for class_info in &self.infos { + class_info.pack(writer, big, encoding, info)?; + } + Ok(()) + } +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct FuncNameEntry { + pub address: u32, + pub name: WideString, +} + +#[derive(Clone, Debug, Default, StructPack, StructUnpack)] +pub struct DWordArray { + #[pvec(u32)] + pub data: Vec, +} + +impl Deref for DWordArray { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl DerefMut for DWordArray { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.data + } +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionFunction { + pub prologue: DWordArray, + pub epilogue: DWordArray, + #[pvec(u32)] + pub func_names: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionInitNakedFunc { + pub naked_prologue: DWordArray, + pub naked_epilogue: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct FuncEntryHeader { + pub flags: u32, + pub address: u32, + pub bytes: u32, + pub reserved: u32, +} + +#[derive(Clone, Debug, StructPack)] +pub struct FuncInfoEntry { + pub header: FuncEntryHeader, + pub name: WideString, + pub reserved: Vec, +} + +impl StructUnpack for FuncInfoEntry { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let header = FuncEntryHeader::unpack(reader, big, encoding, info)?; + let name = WideString::unpack(reader, big, encoding, info)?; + let reserved_size = header.reserved as usize; + let reserved = reader.read_exact_vec(reserved_size)?; + Ok(Self { + header, + name, + reserved, + }) + } +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionFuncInfo { + #[pvec(u32)] + pub functions: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct NakedSymbolInfoEntry { + pub flags: u32, + pub reserved: u32, + pub address: u64, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SymbolInfoEntry { + pub info: NakedSymbolInfoEntry, + pub name: WideString, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionSymbolInfo { + #[pvec(u32)] + pub symbols: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct TagedObjectEntry { + pub tag: WideString, + pub object: TypedObject, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionGlobal { + #[pvec(u32)] + pub objects: Vec, +} + +#[derive(Clone, Debug)] +pub enum GlobalObjectEntryObj { + Object(TypedObject), + List(Vec), +} + +#[derive(Clone, Debug)] +pub struct GlobalObjectEntry { + pub name: WideString, + pub object: GlobalObjectEntryObj, +} + +impl StructUnpack for GlobalObjectEntry { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let name = WideString::unpack(reader, big, encoding, info)?; + let length = i32::unpack(reader, big, encoding, info)?; + if length >= 0 { + let obj = reader.read_struct_vec(length as usize, big, encoding, info)?; + Ok(Self { + name, + object: GlobalObjectEntryObj::List(obj), + }) + } else { + let obj = TypedObject::unpack(reader, big, encoding, info)?; + Ok(Self { + name, + object: GlobalObjectEntryObj::Object(obj), + }) + } + } +} + +impl StructPack for GlobalObjectEntry { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + self.name.pack(writer, big, encoding, info)?; + match &self.object { + GlobalObjectEntryObj::Object(obj) => { + (0x80000000u32).pack(writer, big, encoding, info)?; + obj.pack(writer, big, encoding, info)?; + } + GlobalObjectEntryObj::List(list) => { + let length = list.len() as i32; + length.pack(writer, big, encoding, info)?; + for item in list { + item.pack(writer, big, encoding, info)?; + } + } + } + Ok(()) + } +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionData { + #[pvec(u32)] + pub objects: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct ConstStringEntry { + pub string: WideString, + pub refs: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionConstString { + #[pvec(u32)] + pub strings: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct TagedDwordArrayEntry { + pub tag: WideString, + pub array: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct TagedDwordArray { + #[pvec(u32)] + pub elements: Vec, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionLinkInfo { + pub ext_global_ref: DWordArray, + pub ext_data_ref: DWordArray, + pub imp_global_ref: TagedDwordArray, + pub imp_data_ref: TagedDwordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionLinkInfoEx { + pub flags: u32, + pub ext_naked_global_ref: DWordArray, + pub ext_naked_const_ref: DWordArray, + pub ext_naked_shared_ref: DWordArray, + pub ext_naked_func_ref: DWordArray, + pub imp_naked_global_ref: TagedDwordArray, + pub imp_naked_const_ref: TagedDwordArray, + pub imp_naked_shared_ref: TagedDwordArray, + pub imp_naked_func_ref: TagedDwordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionRefFunc { + pub refs: TagedDwordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionRefCode { + pub refs: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionRefClass { + pub refs: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionNativeFunc { + #[pvec(u32)] + pub names: Vec, + pub addresses: DWordArray, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct SectionNakedFunc { + #[pvec(u32)] + pub names: Vec, + pub addresses: DWordArray, +} + +const ID_NATIVE_FUNC: u64 = 0x636E66766974616E; +const ID_NAKED_FUNC: u64 = 0x636E6664656B616E; + +#[derive(Clone, Debug)] +pub struct SectionImportNativeFunc { + pub native_func: SectionNativeFunc, + pub naked_func: SectionNakedFunc, +} + +impl StructUnpack for SectionImportNativeFunc { + fn unpack( + mut reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let len = reader.stream_length()?; + let mut native_func = None; + let mut naked_func = None; + while reader.stream_position()? < len { + let id = u64::unpack(reader, big, encoding, info)?; + let length = u64::unpack(reader, big, encoding, info)?; + match id { + ID_NATIVE_FUNC => { + let mut mem = StreamRegion::with_size(&mut reader, length)?; + let func = SectionNativeFunc::unpack(&mut mem, big, encoding, info)?; + native_func = Some(func); + } + ID_NAKED_FUNC => { + let mut mem = StreamRegion::with_size(&mut reader, length)?; + let func = SectionNakedFunc::unpack(&mut mem, big, encoding, info)?; + naked_func = Some(func); + } + _ => { + return Err(anyhow::anyhow!( + "Unknown SectionImportNativeFunc id: {:#X}", + id + )); + } + } + } + Ok(Self { + native_func: native_func + .ok_or_else(|| anyhow::anyhow!("Missing native_func in SectionImportNativeFunc"))?, + naked_func: naked_func + .ok_or_else(|| anyhow::anyhow!("Missing naked_func in SectionImportNativeFunc"))?, + }) + } +} + +impl StructPack for SectionImportNativeFunc { + fn pack( + &self, + mut writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + // Write native_func + ID_NATIVE_FUNC.pack(&mut writer, big, encoding, info)?; + let mut native_func_buf = Vec::new(); + self.native_func + .pack(&mut native_func_buf, big, encoding, info)?; + (native_func_buf.len() as u64).pack(&mut writer, big, encoding, info)?; + writer.write_all(&native_func_buf)?; + + // Write naked_func + ID_NAKED_FUNC.pack(&mut writer, big, encoding, info)?; + let mut naked_func_buf = Vec::new(); + self.naked_func + .pack(&mut naked_func_buf, big, encoding, info)?; + (naked_func_buf.len() as u64).pack(&mut writer, big, encoding, info)?; + writer.write_all(&naked_func_buf)?; + + Ok(()) + } +}