diff --git a/Cargo.lock b/Cargo.lock index 7b77e62..7977bad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1384,8 +1384,6 @@ dependencies = [ [[package]] name = "msg_tool_macro" version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7311dfe564f7812ce1a246b01169533cb4c089e3d91aca31f9675df1c57a20a2" dependencies = [ "quote", "syn 2.0.114", diff --git a/Cargo.toml b/Cargo.toml index 58f5d9e..ce753ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ markup5ever = { version = "0.36", optional = true } markup5ever_rcdom = { version = "0.36", optional = true } memchr = { version = "2.7", optional = true } mozjpeg = { version = "0.10", optional = true } -msg_tool_macro = { version = "0.2.12" } +msg_tool_macro = { path = "./msg_tool_macro" } num_cpus = "1.17" overf = "0.1" parse-size = { version = "1.1", optional = true } diff --git a/msg_tool_macro/src/lib.rs b/msg_tool_macro/src/lib.rs index c9fb42a..4608e4f 100644 --- a/msg_tool_macro/src/lib.rs +++ b/msg_tool_macro/src/lib.rs @@ -35,7 +35,7 @@ pub fn struct_unpack_impl_for_num(item: TokenStream) -> TokenStream { let i = syn::parse_macro_input!(item as syn::Ident); let output = quote::quote! { impl StructUnpack for #i { - fn unpack(reader: &mut R, big: bool, _encoding: Encoding) -> Result { + fn unpack(reader: &mut R, big: bool, _encoding: Encoding, _info: &Option>) -> Result { let mut buf = [0u8; std::mem::size_of::<#i>()]; reader.read_exact(&mut buf)?; Ok(if big { @@ -47,7 +47,7 @@ pub fn struct_unpack_impl_for_num(item: TokenStream) -> TokenStream { } impl StructPack for #i { - fn pack(&self, writer: &mut W, big: bool, _encoding: Encoding) -> Result<()> { + fn pack(&self, writer: &mut W, big: bool, _encoding: Encoding, _info: &Option>) -> Result<()> { let bytes = if big { self.to_be_bytes() } else { @@ -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)?; + 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)?; + 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)?; + len.pack(writer, big, encoding, info)?; for item in &self.#field_name { - item.pack(writer, big, encoding)?; + 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)?; + 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) -> 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)?; + 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)?; + 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)?; + len.pack(writer, big, encoding, info)?; for item in &#field_name { - item.pack(writer, big, encoding)?; + 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)?; + #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) -> 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)? 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)?; + 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)? as usize; - let #field_name = reader.read_struct_vec(len, big, encoding)?; + 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)?; + 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) -> Result { + fn unpack(reader: &mut R, big: bool, encoding: Encoding, info: &Option>) -> Result { #(#smts)* Ok(Self #fields) } diff --git a/src/ext/io.rs b/src/ext/io.rs index 62d2769..7ec07a6 100644 --- a/src/ext/io.rs +++ b/src/ext/io.rs @@ -308,7 +308,12 @@ pub trait Peek { /// * `big` indicates whether the struct is in big-endian format. /// * `encoding` specifies the encoding to use for string fields in the struct. /// Returns the unpacked struct. - fn read_struct(&mut self, big: bool, encoding: Encoding) -> Result; + fn read_struct( + &mut self, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result; /// Reads a vector of structs from the reader. /// The structs must implement the `StructUnpack` trait. /// @@ -321,10 +326,11 @@ pub trait Peek { count: usize, big: bool, encoding: Encoding, + info: &Option>, ) -> Result> { let mut vec = Vec::with_capacity(count); for _ in 0..count { - vec.push(self.read_struct(big, encoding)?); + vec.push(self.read_struct(big, encoding, info)?); } Ok(vec) } @@ -448,8 +454,13 @@ impl Peek for T { Ok(buf) } - fn read_struct(&mut self, big: bool, encoding: Encoding) -> Result { - S::unpack(self, big, encoding) + fn read_struct( + &mut self, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + S::unpack(self, big, encoding, info) .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) } } @@ -1133,11 +1144,12 @@ pub trait WriteExt { /// Writes a C-style string (null-terminated) to the writer. fn write_cstring(&mut self, value: &CString) -> Result<()>; /// Write a struct to the writer. - fn write_struct( + fn write_struct( &mut self, - value: &T, + value: &V, big: bool, encoding: Encoding, + info: &Option>, ) -> Result<()>; /// Writes data from a reader to the writer. fn write_from(&mut self, reader: &mut R, offset: u64, len: u64) -> Result<()>; @@ -1220,9 +1232,10 @@ impl WriteExt for T { value: &V, big: bool, encoding: Encoding, + info: &Option>, ) -> Result<()> { value - .pack(self, big, encoding) + .pack(self, big, encoding, info) .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) } diff --git a/src/scripts/artemis/archive/pf2.rs b/src/scripts/artemis/archive/pf2.rs index 7c3c78b..5968acf 100644 --- a/src/scripts/artemis/archive/pf2.rs +++ b/src/scripts/artemis/archive/pf2.rs @@ -171,7 +171,7 @@ impl ArtemisPf2 { let file_count = reader.read_u32()?; let mut entries = Vec::with_capacity(file_count as usize); for _ in 0..file_count { - let header = reader.read_struct(false, archive_encoding)?; + let header = reader.read_struct(false, archive_encoding, &None)?; entries.push(header); } let output_ext = std::path::Path::new(filename) @@ -346,7 +346,7 @@ impl ArtemisPf2Writer { offset: 0, size: 0, }; - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; headers.insert(file.to_string(), header); } let size = writer.stream_position()?; @@ -390,7 +390,7 @@ impl Archive for ArtemisPf2Writer { let mut files = self.headers.values().collect::>(); files.sort_by_key(|d| d.offset); for file in files.iter() { - file.pack(&mut self.writer, false, self.encoding)?; + file.pack(&mut self.writer, false, self.encoding, &None)?; } self.writer.write_u32_at(3, self.index_size)?; self.writer.write_u32_at(7, 0)?; diff --git a/src/scripts/artemis/archive/pfs.rs b/src/scripts/artemis/archive/pfs.rs index e696e31..faa1016 100644 --- a/src/scripts/artemis/archive/pfs.rs +++ b/src/scripts/artemis/archive/pfs.rs @@ -169,7 +169,7 @@ impl ArtemisArc { let file_count = reader.read_u32()?; let mut entries = Vec::with_capacity(file_count as usize); for _ in 0..file_count { - let header = reader.read_struct(false, archive_encoding)?; + let header = reader.read_struct(false, archive_encoding, &None)?; entries.push(header); } let xor_key = if version == b'8' { @@ -374,7 +374,7 @@ impl ArtemisArcWriter { offset: 0, size: 0, }; - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; headers.insert(file.to_string(), header); } let size = writer.stream_position()?; @@ -418,7 +418,7 @@ impl Archive for ArtemisArcWriter { let mut files = self.headers.values().collect::>(); files.sort_by_key(|d| d.offset); for file in files.iter() { - file.pack(&mut self.writer, false, self.encoding)?; + file.pack(&mut self.writer, false, self.encoding, &None)?; } if !self.disable_xor { self.writer.seek(SeekFrom::Start(7))?; diff --git a/src/scripts/bgi/archive/v1.rs b/src/scripts/bgi/archive/v1.rs index 853d64d..74e4f5c 100644 --- a/src/scripts/bgi/archive/v1.rs +++ b/src/scripts/bgi/archive/v1.rs @@ -249,7 +249,7 @@ impl BgiArchive { let file_count = reader.read_u32()?; let mut entries = Vec::with_capacity(file_count as usize); for _ in 0..file_count { - let entry = BgiFileHeader::unpack(&mut reader, false, archive_encoding)?; + let entry = BgiFileHeader::unpack(&mut reader, false, archive_encoding, &None)?; entries.push(entry); } @@ -554,7 +554,7 @@ impl BgiArchiveWriter { size: 0, _padding: vec![0; 8], }; - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; headers.insert(file.to_string(), header); } Ok(BgiArchiveWriter { @@ -601,7 +601,7 @@ impl Archive for BgiArchiveWriter { files.sort_by_key(|f| f.offset); for file in files { file.offset -= base_offset; - file.pack(&mut self.writer, false, self.encoding)?; + file.pack(&mut self.writer, false, self.encoding, &None)?; } Ok(()) } diff --git a/src/scripts/bgi/archive/v2.rs b/src/scripts/bgi/archive/v2.rs index 0423350..eff7022 100644 --- a/src/scripts/bgi/archive/v2.rs +++ b/src/scripts/bgi/archive/v2.rs @@ -281,7 +281,7 @@ impl BgiArchive { let file_count = reader.read_u32()?; let mut entries = Vec::with_capacity(file_count as usize); for _ in 0..file_count { - let entry = BgiFileHeader::unpack(&mut reader, false, archive_encoding)?; + let entry = BgiFileHeader::unpack(&mut reader, false, archive_encoding, &None)?; entries.push(entry); } @@ -557,7 +557,7 @@ impl BgiArchiveWriter { _unk: vec![0; 8], _padding: vec![0; 16], }; - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; headers.insert(file.to_string(), header); } Ok(BgiArchiveWriter { @@ -604,7 +604,7 @@ impl Archive for BgiArchiveWriter { files.sort_by_key(|f| f.offset); for file in files { file.offset -= base_offset; - file.pack(&mut self.writer, false, self.encoding)?; + file.pack(&mut self.writer, false, self.encoding, &None)?; } Ok(()) } diff --git a/src/scripts/bgi/image/cbg.rs b/src/scripts/bgi/image/cbg.rs index a3bc54b..b73033e 100644 --- a/src/scripts/bgi/image/cbg.rs +++ b/src/scripts/bgi/image/cbg.rs @@ -149,7 +149,7 @@ impl BgiCBG { if !magic.starts_with(b"CompressedBG___") { return Err(anyhow::anyhow!("Invalid magic: {:?}", magic)); } - let header = BgiCBGHeader::unpack(&mut reader, false, Encoding::Cp932)?; + let header = BgiCBGHeader::unpack(&mut reader, false, Encoding::Cp932, &None)?; if header.version > 2 { return Err(anyhow::anyhow!("Unsupported version: {}", header.version)); } @@ -1129,7 +1129,8 @@ impl CbgEncoder { let final_pos = self.stream.pos; self.stream.pos = header_pos; - self.header.pack(&mut self.stream, false, Encoding::Cp932)?; + self.header + .pack(&mut self.stream, false, Encoding::Cp932, &None)?; self.stream.pos = final_pos; Ok(self.stream.into_inner()) diff --git a/src/scripts/cat_system/image/hg3.rs b/src/scripts/cat_system/image/hg3.rs index 124bdca..a36ddce 100644 --- a/src/scripts/cat_system/image/hg3.rs +++ b/src/scripts/cat_system/image/hg3.rs @@ -103,7 +103,7 @@ impl Hg3Image { .is_ok() { reader.pos = (offset + 16) as usize; - let entry = Hg3Entry::unpack(&mut reader, false, Encoding::Cp932)?; + let entry = Hg3Entry::unpack(&mut reader, false, Encoding::Cp932, &None)?; entries.push((entry, (offset + 8) as usize, section_size as usize - 8)); } offset += section_size as u64; diff --git a/src/scripts/circus/archive/pck.rs b/src/scripts/circus/archive/pck.rs index e22f514..73515bc 100644 --- a/src/scripts/circus/archive/pck.rs +++ b/src/scripts/circus/archive/pck.rs @@ -231,7 +231,7 @@ impl PckArchive { } let mut entries = Vec::with_capacity(file_count as usize); for (i, (offset, size)) in offset_list.into_iter().enumerate() { - let header: PckFileHeader = reader.read_struct(false, archive_encoding)?; + let header: PckFileHeader = reader.read_struct(false, archive_encoding, &None)?; if header.offset != offset { return Err(anyhow::anyhow!( "PckArchive: Header offset mismatch at entry {}: expected {}, got {}", @@ -357,7 +357,7 @@ impl PckArchiveWriter { offset: 0, size: 0, }; - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; headers.insert(file.to_string(), header); } Ok(PckArchiveWriter { @@ -400,7 +400,7 @@ impl Archive for PckArchiveWriter { self.writer.write_u32(file.size)?; } for file in files { - file.pack(&mut self.writer, false, self.encoding)?; + file.pack(&mut self.writer, false, self.encoding, &None)?; } Ok(()) } diff --git a/src/scripts/circus/audio/pcm.rs b/src/scripts/circus/audio/pcm.rs index 2ff7a2b..7a7fa88 100644 --- a/src/scripts/circus/audio/pcm.rs +++ b/src/scripts/circus/audio/pcm.rs @@ -132,7 +132,7 @@ impl Pcm { if &magic != b"XPCM" { return Err(anyhow::anyhow!("Invalid PCM header magic: {:?}", magic)); } - let header = Header::unpack(&mut reader, false, Encoding::Utf8)?; + let header = Header::unpack(&mut reader, false, Encoding::Utf8, &None)?; let mode = Mode::try_from(header.mode()) .map_err(|_| anyhow::anyhow!("Unsupported PCM mode: {}", header.mode()))?; let data = match mode { diff --git a/src/scripts/circus/image/crx.rs b/src/scripts/circus/image/crx.rs index 0657149..1107977 100644 --- a/src/scripts/circus/image/crx.rs +++ b/src/scripts/circus/image/crx.rs @@ -239,7 +239,7 @@ impl CrxImage { if magic != *b"CRXG" { return Err(anyhow::anyhow!("Invalid CRX image magic")); } - let header: Header = reader.read_struct(false, Encoding::Utf8)?; + let header: Header = reader.read_struct(false, Encoding::Utf8, &None)?; if header.version == 0 || header.version > 3 { return Err(anyhow::anyhow!( "Unsupported CRX version: {}", @@ -1014,7 +1014,7 @@ impl CrxImage { compressed_data.into_inner() }; writer.write_all(b"CRXG")?; - header.pack(&mut writer, false, Encoding::Utf8)?; + header.pack(&mut writer, false, Encoding::Utf8, &None)?; writer.write_u32(compressed.len() as u32)?; writer.write_all(&compressed)?; Ok(()) @@ -1336,7 +1336,7 @@ impl Script for CrxImage { compressed_data.into_inner() }; file.write_all(b"CRXG")?; - new_header.pack(&mut file, false, Encoding::Utf8)?; + new_header.pack(&mut file, false, Encoding::Utf8, &None)?; file.write_u32(compressed.len() as u32)?; file.write_all(&compressed)?; Ok(()) diff --git a/src/scripts/entis_gls/csx/mod.rs b/src/scripts/entis_gls/csx/mod.rs index 80ae84b..03906f2 100644 --- a/src/scripts/entis_gls/csx/mod.rs +++ b/src/scripts/entis_gls/csx/mod.rs @@ -4,6 +4,7 @@ //! Original license: GPL-3.0 mod base; mod v1; +mod v2; use crate::ext::io::*; use crate::scripts::base::*; @@ -12,6 +13,7 @@ use crate::utils::encoding::*; use anyhow::Result; use base::ECSImage; use v1::ECSExecutionImageV1; +use v2::ECSExecutionImageV2; #[derive(Debug)] pub struct CSXScriptBuilder {} @@ -66,9 +68,15 @@ pub struct CSXScript { impl CSXScript { pub fn new(buf: Vec, config: &ExtraConfig) -> Result { let reader = MemReader::new(buf); - let img = ECSExecutionImageV1::new(reader.to_ref(), config)?; + let img = { + match ECSExecutionImageV1::new(reader.to_ref(), config) { + Ok(img) => Box::new(img), + Err(_) => Box::new(ECSExecutionImageV2::new(reader.to_ref(), config)?) + as Box, + } + }; Ok(Self { - img: Box::new(img), + img, disasm: config.entis_gls_csx_disasm, custom_yaml: config.custom_yaml, }) diff --git a/src/scripts/entis_gls/csx/v1/disasm.rs b/src/scripts/entis_gls/csx/v1/disasm.rs index e7c4d4c..1511fd7 100644 --- a/src/scripts/entis_gls/csx/v1/disasm.rs +++ b/src/scripts/entis_gls/csx/v1/disasm.rs @@ -128,7 +128,7 @@ impl<'a> ECSExecutionImageDisassembler<'a> { let length = self.stream.read_u32()?; if length != 0x80000000 { self.stream.seek_relative(-4)?; - let s = WideString::unpack(&mut self.stream, false, Encoding::Utf16LE)?.0; + let s = WideString::unpack(&mut self.stream, false, Encoding::Utf16LE, &None)?.0; Ok((None, s)) } else if let Some(conststr) = &self.conststr { let index = self.stream.read_u32()? as usize; diff --git a/src/scripts/entis_gls/csx/v1/img.rs b/src/scripts/entis_gls/csx/v1/img.rs index e6d8030..f6c79b9 100644 --- a/src/scripts/entis_gls/csx/v1/img.rs +++ b/src/scripts/entis_gls/csx/v1/img.rs @@ -36,10 +36,10 @@ pub struct ECSExecutionImage { impl ECSExecutionImage { pub fn new(mut reader: MemReaderRef<'_>, config: &ExtraConfig) -> Result { - let file_header = EMCFileHeader::unpack(&mut reader, false, Encoding::Utf8)?; - // if file_header.signagure != *b"Entis\x1a\0\0" { - // return Err(anyhow::anyhow!("Invalid EMC file signature")); - // } + let file_header = EMCFileHeader::unpack(&mut reader, false, Encoding::Utf8, &None)?; + if file_header.signagure != *b"Entis\x1a\0\0" { + return Err(anyhow::anyhow!("Invalid EMC file signature")); + } let len = reader.data.len(); let mut exi_header = None; let mut header = None; @@ -70,7 +70,7 @@ impl ECSExecutionImage { let buf = reader.read_exact_vec(size as usize)?; { let mut sread = MemReaderRef::new(&buf); - header = Some(EXIHeader::unpack(&mut sread, false, Encoding::Utf8)?); + header = Some(EXIHeader::unpack(&mut sread, false, Encoding::Utf8, &None)?); } exi_header = Some(buf); if let Some(hdr) = &header { @@ -85,12 +85,23 @@ impl ECSExecutionImage { } // function 0x6E6F6974636E7566 => { - pif_prologue = Some(DWordArray::unpack(&mut reader, false, Encoding::Utf8)?); - pif_epilogue = Some(DWordArray::unpack(&mut reader, false, Encoding::Utf8)?); + pif_prologue = Some(DWordArray::unpack( + &mut reader, + false, + Encoding::Utf8, + &None, + )?); + pif_epilogue = Some(DWordArray::unpack( + &mut reader, + false, + Encoding::Utf8, + &None, + )?); function_list = Some(FunctionNameList::unpack( &mut reader, false, Encoding::Utf8, + &None, )?); } // global @@ -98,7 +109,8 @@ impl ECSExecutionImage { let count = reader.read_u32()?; let mut items = Vec::with_capacity(count as usize); for _ in 0..count { - let name = WideString::unpack(&mut reader, false, Encoding::Utf16LE)?.0; + let name = + WideString::unpack(&mut reader, false, Encoding::Utf16LE, &None)?.0; let obj = ECSObject::read_from(&mut reader, int64)?; items.push(ECSObjectItem { name, obj }); } @@ -109,13 +121,19 @@ impl ECSExecutionImage { let count = reader.read_u32()?; let mut items = Vec::with_capacity(count as usize); for _ in 0..count { - let name = WideString::unpack(&mut reader, false, Encoding::Utf16LE)?.0; + let name = + WideString::unpack(&mut reader, false, Encoding::Utf16LE, &None)?.0; let length = reader.read_i32()?; let obj = if length >= 0 { let mut datas = Vec::with_capacity(length as usize); for _ in 0..length { - let name = - WideString::unpack(&mut reader, false, Encoding::Utf16LE)?.0; + let name = WideString::unpack( + &mut reader, + false, + Encoding::Utf16LE, + &None, + )? + .0; let obj = ECSObject::read_from(&mut reader, int64)?; datas.push(ECSObjectItem { name, obj }); } @@ -133,16 +151,17 @@ impl ECSExecutionImage { &mut reader, false, Encoding::Utf8, + &None, )?); } // linkinf 0x20666E696B6E696C => { - ext_global_ref = DWordArray::unpack(&mut reader, false, Encoding::Utf8)?; - ext_data_ref = DWordArray::unpack(&mut reader, false, Encoding::Utf8)?; + ext_global_ref = DWordArray::unpack(&mut reader, false, Encoding::Utf8, &None)?; + ext_data_ref = DWordArray::unpack(&mut reader, false, Encoding::Utf8, &None)?; imp_global_ref = - TaggedRefAddressList::unpack(&mut reader, false, Encoding::Utf8)?; + TaggedRefAddressList::unpack(&mut reader, false, Encoding::Utf8, &None)?; imp_data_ref = - TaggedRefAddressList::unpack(&mut reader, false, Encoding::Utf8)?; + TaggedRefAddressList::unpack(&mut reader, false, Encoding::Utf8, &None)?; if !ext_global_ref.is_empty() || !ext_data_ref.is_empty() || !imp_global_ref.is_empty() @@ -286,7 +305,8 @@ impl ECSExecutionImage { } fn save<'a>(&self, mut writer: Box) -> Result<()> { - self.file_header.pack(&mut writer, false, Encoding::Utf8)?; + self.file_header + .pack(&mut writer, false, Encoding::Utf8, &None)?; if let Some(exi_header) = &self.exi_header { writer.write_u64(0x2020726564616568)?; // header writer.write_u64(exi_header.len() as u64)?; @@ -297,9 +317,12 @@ impl ECSExecutionImage { writer.write_all(&self.image.data)?; writer.write_u64(0x6E6F6974636E7566)?; // function let mut mem = MemWriter::new(); - self.pif_prologue.pack(&mut mem, false, Encoding::Utf8)?; - self.pif_epilogue.pack(&mut mem, false, Encoding::Utf8)?; - self.function_list.pack(&mut mem, false, Encoding::Utf8)?; + self.pif_prologue + .pack(&mut mem, false, Encoding::Utf8, &None)?; + self.pif_epilogue + .pack(&mut mem, false, Encoding::Utf8, &None)?; + self.function_list + .pack(&mut mem, false, Encoding::Utf8, &None)?; let data = mem.into_inner(); writer.write_u64(data.len() as u64)?; writer.write_all(&data)?; @@ -312,7 +335,7 @@ impl ECSExecutionImage { }; mem.write_u32(self.csg_global.len() as u32)?; for item in self.csg_global.iter() { - WideString(item.name.clone()).pack(&mut mem, false, Encoding::Utf16LE)?; + WideString(item.name.clone()).pack(&mut mem, false, Encoding::Utf16LE, &None)?; item.obj.write_to(&mut mem, int64)?; } let data = mem.into_inner(); @@ -322,7 +345,7 @@ impl ECSExecutionImage { let mut mem = MemWriter::new(); mem.write_u32(self.csg_data.len() as u32)?; for item in self.csg_data.iter() { - WideString(item.name.clone()).pack(&mut mem, false, Encoding::Utf16LE)?; + WideString(item.name.clone()).pack(&mut mem, false, Encoding::Utf16LE, &None)?; match &item.obj { ECSObject::Global(g) => { mem.write_i32(g.len() as i32)?; @@ -331,6 +354,7 @@ impl ECSExecutionImage { &mut mem, false, Encoding::Utf16LE, + &None, )?; data_item.obj.write_to(&mut mem, int64)?; } @@ -347,17 +371,21 @@ impl ECSExecutionImage { if let Some(ext_const_str) = &self.ext_const_str { writer.write_u64(0x72747374736E6F63)?; // conststr let mut mem = MemWriter::new(); - ext_const_str.pack(&mut mem, false, Encoding::Utf8)?; + ext_const_str.pack(&mut mem, false, Encoding::Utf8, &None)?; let data = mem.into_inner(); writer.write_u64(data.len() as u64)?; writer.write_all(&data)?; } writer.write_u64(0x20666E696B6E696C)?; // linkinf let mut mem = MemWriter::new(); - self.ext_global_ref.pack(&mut mem, false, Encoding::Utf8)?; - self.ext_data_ref.pack(&mut mem, false, Encoding::Utf8)?; - self.imp_global_ref.pack(&mut mem, false, Encoding::Utf8)?; - self.imp_data_ref.pack(&mut mem, false, Encoding::Utf8)?; + self.ext_global_ref + .pack(&mut mem, false, Encoding::Utf8, &None)?; + self.ext_data_ref + .pack(&mut mem, false, Encoding::Utf8, &None)?; + self.imp_global_ref + .pack(&mut mem, false, Encoding::Utf8, &None)?; + self.imp_data_ref + .pack(&mut mem, false, Encoding::Utf8, &None)?; let data = mem.into_inner(); writer.write_u64(data.len() as u64)?; writer.write_all(&data)?; @@ -402,7 +430,8 @@ impl ECSImage for ECSExecutionImage { disasm.stream.pos = cmd.addr as usize + 1; let _csom = disasm.read_csom()?; let num_args = disasm.stream.read_i32()?; - let func_name = WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + let func_name = + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let mut is_mess = false; if num_args == 1 { if func_name == "SceneTitle" { @@ -492,7 +521,8 @@ impl ECSImage for ECSExecutionImage { disasm.stream.pos = cmd.addr as usize + 1; let csom = disasm.read_csom()?; let num_args = disasm.stream.read_i32()?; - let func_name = WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + let func_name = + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let mut is_mess = false; if num_args == 1 { if func_name == "SceneTitle" { @@ -568,7 +598,8 @@ impl ECSImage for ECSExecutionImage { string_stack.clear(); } else if is_enter { disasm.stream.pos = cmd.addr as usize + 1; - let name = WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + let name = + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let num_args = disasm.stream.read_i32()?; if num_args == 0 { pre_enter_name = name.clone(); @@ -630,7 +661,8 @@ impl ECSImage for ECSExecutionImage { disasm.stream.pos = cmd.addr as usize + 1; let csom = disasm.read_csom()?; let num_args = disasm.stream.read_i32()?; - let func_name = WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + let func_name = + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let mut is_mess = false; if csom == CsomAuto && num_args == 1 && func_name == "Mess" { is_mess = true; @@ -718,7 +750,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(CsomImmediate.into())?; new_image.write_u8(CsvtString.into())?; - WideString(mes).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(mes).pack(&mut new_image, false, Encoding::Utf8, &None)?; new_assembly.push(tcmd); let mut tcmd = if tmp_index <= post_index { let data = assembly[tmp_index].clone(); @@ -746,6 +778,7 @@ impl ECSImage for ECSExecutionImage { &mut new_image, false, Encoding::Utf16LE, + &None, )?; new_assembly.push(tcmd); let mut tcmd = if tmp_index <= post_index { @@ -825,7 +858,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(name).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(name).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -886,7 +919,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(message).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(message).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -947,7 +980,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(message).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(message).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -1014,7 +1047,8 @@ impl ECSImage for ECSExecutionImage { disasm.stream.pos = cmd.addr as usize + 1; let csom = disasm.read_csom()?; let num_args = disasm.stream.read_i32()?; - let func_name = WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + let func_name = + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let mut is_mess = false; if csom == CsomAuto && num_args == 1 && func_name == "Mess" { is_mess = true; @@ -1103,7 +1137,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(CsomImmediate.into())?; new_image.write_u8(CsvtString.into())?; - WideString(mes).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(mes).pack(&mut new_image, false, Encoding::Utf8, &None)?; new_assembly.push(tcmd); let mut tcmd = if tmp_index <= post_index { let data = assembly[tmp_index].clone(); @@ -1131,6 +1165,7 @@ impl ECSImage for ECSExecutionImage { &mut new_image, false, Encoding::Utf16LE, + &None, )?; new_assembly.push(tcmd); let mut tcmd = if tmp_index <= post_index { @@ -1215,7 +1250,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(name).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(name).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -1274,7 +1309,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(message).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(message).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -1339,7 +1374,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(CsicLoad.into())?; new_image.write_u8(lcsom.into())?; new_image.write_u8(lcsvt.into())?; - WideString(message).pack(&mut new_image, false, Encoding::Utf8)?; + WideString(message).pack(&mut new_image, false, Encoding::Utf8, &None)?; dumped_index += 1; while dumped_index <= index { let tcmd = &mut assembly[dumped_index]; @@ -1357,7 +1392,7 @@ impl ECSImage for ECSExecutionImage { } else if is_enter { disasm.stream.pos = cmd.addr as usize + 1; let original_name = - WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE)?.0; + WideString::unpack(&mut disasm.stream, false, Encoding::Utf16LE, &None)?.0; let num_args = disasm.stream.read_i32()?; if num_args == 0 { pre_enter_name = original_name.clone(); @@ -1426,7 +1461,7 @@ impl ECSImage for ECSExecutionImage { new_image.write_u8(code)?; new_image.write_u8(csom)?; new_image.write_u8(csvt)?; - s.pack(&mut new_image, false, Encoding::Utf8)?; + s.pack(&mut new_image, false, Encoding::Utf8, &None)?; continue; } } diff --git a/src/scripts/entis_gls/csx/v1/mod.rs b/src/scripts/entis_gls/csx/v1/mod.rs index 4c97edb..c730679 100644 --- a/src/scripts/entis_gls/csx/v1/mod.rs +++ b/src/scripts/entis_gls/csx/v1/mod.rs @@ -1,4 +1,4 @@ -//! Ported from CSXTools C# project +//! Ported from CSXTool C# project //! See parent module documentation for more details. mod disasm; mod img; diff --git a/src/scripts/entis_gls/csx/v1/types.rs b/src/scripts/entis_gls/csx/v1/types.rs index 5eff37f..94c8105 100644 --- a/src/scripts/entis_gls/csx/v1/types.rs +++ b/src/scripts/entis_gls/csx/v1/types.rs @@ -129,8 +129,13 @@ impl DerefMut for DWordArray { pub struct WideString(pub String); impl StructUnpack for WideString { - fn unpack(reader: &mut R, big: bool, encoding: Encoding) -> Result { - let length = u32::unpack(reader, big, encoding)? as usize; + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let length = u32::unpack(reader, big, encoding, info)? as usize; let to_read = length * 2; let buf = reader.read_exact_vec(to_read)?; let enc = if big { @@ -144,7 +149,13 @@ impl StructUnpack for WideString { } impl StructPack for WideString { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { let enc = if big { Encoding::Utf16BE } else { @@ -152,7 +163,7 @@ impl StructPack for WideString { }; let encoded = encode_string(enc, &self.0, false)?; let length = (encoded.len() / 2) as u32; - length.pack(writer, big, encoding)?; + length.pack(writer, big, encoding, info)?; writer.write_all(&encoded)?; Ok(()) } @@ -204,7 +215,7 @@ impl ECSObject { .map_err(|typ| anyhow::anyhow!("Invalid CSVariableType: {}", typ))?; match obj_typ { CSVariableType::CsvtObject => { - let class_name = WideString::unpack(reader, false, Encoding::Utf8)?.0; + let class_name = WideString::unpack(reader, false, Encoding::Utf8, &None)?.0; return Ok(ECSObject::ClassInfoObject(class_name)); } CSVariableType::CsvtReference => { @@ -236,7 +247,7 @@ impl ECSObject { return Ok(ECSObject::Real(val)); } CSVariableType::CsvtString => { - let s = WideString::unpack(reader, false, Encoding::Utf8)?.0; + let s = WideString::unpack(reader, false, Encoding::Utf8, &None)?.0; return Ok(ECSObject::String(s)); } _ => { @@ -250,7 +261,7 @@ impl ECSObject { ECSObject::ClassInfoObject(name) => { let obj_type: u8 = CSVariableType::CsvtObject.into(); writer.write_i32(obj_type as i32)?; - WideString(name.clone()).pack(writer, false, Encoding::Utf8)?; + WideString(name.clone()).pack(writer, false, Encoding::Utf8, &None)?; } ECSObject::Reference => { let obj_type: u8 = CSVariableType::CsvtReference.into(); @@ -285,7 +296,7 @@ impl ECSObject { ECSObject::String(s) => { let obj_type: u8 = CSVariableType::CsvtString.into(); writer.write_i32(obj_type as i32)?; - WideString(s.clone()).pack(writer, false, Encoding::Utf8)?; + WideString(s.clone()).pack(writer, false, Encoding::Utf8, &None)?; } _ => { return Err(anyhow::anyhow!( @@ -380,7 +391,7 @@ impl DerefMut for ECSExecutionImageAssembly { fn test_exi_header_unpack() { let data = b"\x01\x00\x00\x00"; let mut cursor = MemReaderRef::new(data); - let header = EXIHeader::unpack(&mut cursor, false, Encoding::Utf8).unwrap(); + let header = EXIHeader::unpack(&mut cursor, false, Encoding::Utf8, &None).unwrap(); assert_eq!(header.version, 1); assert_eq!(header.int_base, 0); } diff --git a/src/scripts/entis_gls/csx/v2/img.rs b/src/scripts/entis_gls/csx/v2/img.rs new file mode 100644 index 0000000..3ee3f62 --- /dev/null +++ b/src/scripts/entis_gls/csx/v2/img.rs @@ -0,0 +1,144 @@ +use super::super::base::*; +use super::types::*; +use crate::ext::io::*; +use crate::scripts::base::*; +use crate::types::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use std::collections::HashMap; + +const ID_HEADER: u64 = 0x2020726564616568; // header +const ID_IMAGE: u64 = 0x2020206567616D69; +const ID_IMAGE_GLOBAL: u64 = 0x6C626F6C67676D69; +const ID_IMAGE_CONST: u64 = 0x74736E6F63676D69; +const ID_IMAGE_SHARED: u64 = 0x6572616873676D69; +const ID_CLASS_INFO: u64 = 0x666E697373616C63; +const ID_FUNCTION: u64 = 0x6E6F6974636E7566; +const ID_INIT_NAKED_FUNC: u64 = 0x636E666E74696E69; +const ID_FUNC_INFO: u64 = 0x6F666E69636E7566; +const ID_SYMBOL_INFO: u64 = 0x666E696C626D7973; +const ID_GLOBAL: u64 = 0x20206C61626F6C67; +const ID_DATA: u64 = 0x2020202061746164; +const ID_CONST_STRING: u64 = 0x72747374736E6F63; +const ID_LINK_INFO: u64 = 0x20666E696B6E696C; +const ID_LINK_INFO_EX: u64 = 0x343678656B6E696C; +const ID_REF_FUNC: u64 = 0x20636E7566666572; +const ID_REF_CODE: u64 = 0x2065646F63666572; +const ID_REF_CLASS: u64 = 0x7373616C63666572; +const ID_IMPORT_NATIVE_FUNC: u64 = 0x766974616E706D69; + +#[derive(Clone, Debug)] +#[allow(unused)] +pub struct ECSExecutionImage { + file_header: FileHeader, + section_header: SectionHeader, + image: MemReader, + image_global: Option, + image_const: Option, + image_shared: Option, +} + +impl ECSExecutionImage { + pub fn new(mut reader: MemReaderRef<'_>, _config: &ExtraConfig) -> Result { + let file_header = FileHeader::unpack(&mut reader, false, Encoding::Utf8, &None)?; + if file_header.signagure != *b"Entis\x1a\0\0" { + return Err(anyhow::anyhow!("Invalid EMC file signature")); + } + if !file_header.format_desc.starts_with(b"Cotopha Image file") { + return Err(anyhow::anyhow!("Invalid EMC file format description")); + } + let mut section_header = SectionHeader::default(); + let len = reader.data.len(); + let mut image = None; + let mut image_global = None; + let mut image_const = None; + let mut image_shared = None; + while reader.pos < len { + if len - reader.pos < 16 { + break; + } + let id = reader.read_u64()?; + if id == 0 { + break; + } + let size = reader.read_u64()?; + let pos = reader.pos; + match id { + ID_HEADER => { + let mut mem = StreamRegion::with_size(&mut reader, size)?; + section_header = SectionHeader::unpack(&mut mem, false, Encoding::Utf8, &None)?; + } + ID_IMAGE => { + image = Some(MemReader::new(reader.read_exact_vec(size as usize)?)); + } + ID_IMAGE_GLOBAL => { + image_global = Some(MemReader::new(reader.read_exact_vec(size as usize)?)); + } + ID_IMAGE_CONST => { + image_const = Some(MemReader::new(reader.read_exact_vec(size as usize)?)); + } + ID_IMAGE_SHARED => { + image_shared = Some(MemReader::new(reader.read_exact_vec(size as usize)?)); + } + 0 => { + break; + } + _ => { + return Err(anyhow::anyhow!( + "Unknown ECSExecutionImage section ID: 0x{:016X}", + id + )); + } + } + reader.pos = pos + size as usize; + } + Ok(Self { + file_header, + section_header, + image: image.ok_or_else(|| anyhow::anyhow!("Missing image data"))?, + image_global, + image_const, + image_shared, + }) + } +} + +impl ECSImage for ECSExecutionImage { + fn disasm<'a>(&self, _writer: Box) -> Result<()> { + Err(anyhow::anyhow!("Disassembly not implemented for CSX v2")) + } + + fn export(&self) -> Result> { + Err(anyhow::anyhow!("Export not implemented for CSX v2")) + } + + fn export_multi(&self) -> Result>> { + Err(anyhow::anyhow!("Export multi not implemented for CSX v2")) + } + + fn export_all(&self) -> Result> { + Err(anyhow::anyhow!("Export all not implemented for CSX v2")) + } + + fn import<'a>( + &self, + _messages: Vec, + _file: Box, + _replacement: Option<&'a ReplacementTable>, + ) -> Result<()> { + Err(anyhow::anyhow!("Import not implemented for CSX v2")) + } + + fn import_multi<'a>( + &self, + _messages: HashMap>, + _file: Box, + _replacement: Option<&'a ReplacementTable>, + ) -> Result<()> { + Err(anyhow::anyhow!("Import multi not implemented for CSX v2")) + } + + fn import_all<'a>(&self, _messages: Vec, _file: Box) -> Result<()> { + Err(anyhow::anyhow!("Import all not implemented for CSX v2")) + } +} diff --git a/src/scripts/entis_gls/csx/v2/mod.rs b/src/scripts/entis_gls/csx/v2/mod.rs new file mode 100644 index 0000000..726d7f3 --- /dev/null +++ b/src/scripts/entis_gls/csx/v2/mod.rs @@ -0,0 +1,6 @@ +//! Ported from CSXToolPlus C# project +//! See parent module documentation for more details. +mod img; +mod types; + +pub use img::ECSExecutionImage as ECSExecutionImageV2; diff --git a/src/scripts/entis_gls/csx/v2/types.rs b/src/scripts/entis_gls/csx/v2/types.rs new file mode 100644 index 0000000..d31c9b3 --- /dev/null +++ b/src/scripts/entis_gls/csx/v2/types.rs @@ -0,0 +1,448 @@ +use crate::ext::io::*; +use crate::types::*; +use crate::utils::encoding::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use int_enum::IntEnum; +use msg_tool_macro::{StructPack, StructUnpack}; +use std::io::{Read, Seek, Write}; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSCompareType { + CsctNotEqual, + CsctEqual, + CsctLessThan, + CsctLessEqual, + CsctGreaterThan, + CsctGreaterEqual, + CsctNotEqualPointer, + CsctEqualPointer, +} + +pub use CSCompareType::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSExtraOperatorType { + CsxotArrayDim, + CsxotHashContainer, + CsxotMoveReference, +} + +pub use CSExtraOperatorType::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSExtraUniOperatorType { + CsxuotDeselect, + CsxuotBoolean, + CsxuotSizeOf, + CsxuotTypeOf, + CsxuotStaticCast, + CsxuotDynamicCast, + CsxuotDuplicate, + CsxuotDelete, + CsxuotDeleteArray, + CsxuotLoadAddress, + CsxuotRefAddress, +} + +pub use CSExtraUniOperatorType::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSInstructionCode { + CsicNew = 0, + CsicFree = 1, + CsicLoad = 2, + CsicStore = 3, + CsicEnter = 4, + CsicLeave = 5, + CsicJump = 6, + CsicCJump = 7, + CsicCall = 8, + CsicReturn = 9, + CsicElement = 10, + CsicElementIndirect = 11, + CsicOperate = 12, + CsicUniOperate = 13, + CsicCompare = 14, + CsicExOperate = 15, + CsicExUniOperate = 16, + CsicExCall = 17, + CsicExReturn = 18, + CsicCallMember = 19, + CsicCallNativeMember = 20, + CsicSwap = 21, + CsicCreateBufferVSize = 23, + CsicPointerToObject = 24, + CsicReferenceForPointer = 26, + CsicCallNativeFunction = 29, + // Shell + CodeLoadMem = 0x80, + CodeLoadMemBaseImm32, + CodeLoadMemBaseIndex, + CodeLoadMemBaseIndexImm32, + CodeStoreMem = 0x84, + CodeStoreMemBaseImm32, + CodeStoreMemBaseIndex, + CodeStoreMemBaseIndexImm32, + CodeLoadLocal = 0x88, + CodeLoadLocalIndexImm32, + CodeStoreLocal = 0x8A, + CodeStoreLocalIndexImm32, + CodeMoveReg = 0x90, + CodeCvtFloat2Int = 0x92, + CodeCvtInt2Float = 0x93, + CodeSrlImm8 = 0x94, + CodeSraImm8, + CodeSllImm8, + CodeMaskMove, + CodeAddImm32 = 0x98, + CodeMulImm32, + CodeAddSPImm32 = 0x9A, + CodeLoadImm64 = 0x9B, + CodeNegInt = 0x9C, + CodeNotInt, + CodeNegFloat, + CodeAddReg = 0xA0, + CodeSubReg, + CodeMulReg, + CodeDivReg, + CodeModReg, + CodeAndReg, + CodeOrReg, + CodeXorReg, + CodeSrlReg, + CodeSraReg, + CodeSllReg, + CodeMoveSx32Reg = 0xAB, + CodeMoveSx16Reg, + CodeMoveSx8Reg, + CodeFAddReg = 0xB0, + CodeFSubReg, + CodeFMulReg, + CodeFDivReg, + CodeMul32Reg = 0xB8, + CodeIMul32Reg, + CodeDiv32Reg, + CodeIDiv32Reg, + CodeMod32Reg, + CodeIMod32Reg, + CodeCmpNeReg = 0xC0, + CodeCmpEqReg, + CodeCmpLtReg, + CodeCmpLeReg, + CodeCmpGtReg, + CodeCmpGeReg, + CodeCmpCReg, + CodeCmpCZReg, + CodeFCmpNeReg = 0xC8, + CodeFCmpEqReg, + CodeFCmpLtReg, + CodeFCmpLeReg, + CodeFCmpGtReg, + CodeFCmpGeReg, + CodeJumpOffset32 = 0xD0, + CodeJumpReg = 0xD1, + CodeCNJumpOffset32 = 0xD2, + CodeCJumpOffset32, + CodeCallImm32 = 0xD4, + CodeCallReg = 0xD5, + CodeSysCallImm32 = 0xD6, + CodeSysCallReg = 0xD7, + CodeReturn = 0xD8, + CodePushReg = 0xDC, + CodePopReg, + CodePushRegs, + CodePopRegs, + CodeMemoryHint = 0xE0, + CodeFloatExtension, + CodeSIMD64Extension2Op, + CodeSIMD64Extension3Op, + CodeSIMD128Extension2Op, + CodeSIMD128Extension3Op, + CodeEscape = 0xFD, + CodeNoOperation = 0xFE, + CodeSystemReserved = 0xFF, +} + +pub use CSInstructionCode::*; +pub use CodeLoadLocal as CodeLoadLocalImm32; +pub use CodeLoadMem as CodeLoadMemBase; +pub use CodeStoreLocal as CodeStoreLocalImm32; +pub use CodeStoreMem as CodeStoreMemBase; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSObjectMode { + CsomImmediate, + CsomStack, + CsomThis, + CsomGlobal, + CsomData, + CsomAuto, +} + +pub use CSObjectMode::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSOperatorType { + CsotNop = 0xFF, + CsotAdd = 0, + CsotSub, + CsotMul, + CsotDiv, + CsotMod, + CsotAnd, + CsotOr, + CsotXor, + CsotLogicalAnd, + CsotLogicalOr, + CsotShiftRight, + CsotShiftLeft, +} + +pub use CSOperatorType::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSUnaryOperatorType { + CsuotPlus, + CsuotNegate, + CsuotBitnot, + CsuotLogicalNot, +} + +pub use CSUnaryOperatorType::*; + +#[repr(u8)] +#[derive(Debug, IntEnum, PartialEq, Eq, Clone, Copy)] +pub enum CSVariableType { + CsvtObject, + CsvtReference, + CsvtArray, + CsvtHash, + CsvtInteger, + CsvtReal, + CsvtString, + CsvtInteger64, + CsvtPointer, + CsvtClassObject, + CsvtBoolean, + CsvtInt8, + CsvtUint8, + CsvtInt16, + CsvtUint16, + CsvtInt32, + CsvtUint32, + CsvtArrayDimension, + CsvtHashContainer, + CsvtReal32, + CsvtReal64, + CsvtPointerReference, + CsvtBuffer, + CsvtFunction, +} + +pub use CSVariableType::*; + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct FileHeader { + pub signagure: [u8; 8], + pub file_id: u32, + pub _reserved: u32, + pub format_desc: [u8; 48], +} + +#[derive(Clone, Debug, msg_tool_macro::Default)] +pub struct SectionHeader { + #[default(3)] + pub full_ver: u32, + pub header_size: u32, + pub version: u32, + pub int_base: u32, + pub container_flags: u32, + pub _reserved: u32, + pub stack_size: u32, + pub heap_size: u32, + pub entry_point: u32, + pub static_initialize: u32, + pub resume_prepare: u32, +} + +impl StructUnpack for SectionHeader { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let full_ver = 3; + let header_size = reader.stream_length()? as u32; + let version = if header_size >= 4 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let int_base = if header_size >= 8 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let container_flags = if header_size >= 12 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let _reserved = if header_size >= 16 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let stack_size = if header_size >= 20 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let heap_size = if header_size >= 24 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let entry_point = if header_size >= 28 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let static_initialize = if header_size >= 32 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + let resume_prepare = if header_size >= 36 { + u32::unpack(reader, big, encoding, info)? + } else { + 0 + }; + Ok(Self { + full_ver, + header_size, + version, + int_base, + container_flags, + _reserved, + stack_size, + heap_size, + entry_point, + static_initialize, + resume_prepare, + }) + } +} + +impl StructPack for SectionHeader { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + if self.header_size >= 4 { + self.version.pack(writer, big, encoding, info)?; + } + if self.header_size >= 8 { + self.int_base.pack(writer, big, encoding, info)?; + } + if self.header_size >= 12 { + self.container_flags.pack(writer, big, encoding, info)?; + } + if self.header_size >= 16 { + self._reserved.pack(writer, big, encoding, info)?; + } + if self.header_size >= 20 { + self.stack_size.pack(writer, big, encoding, info)?; + } + if self.header_size >= 24 { + self.heap_size.pack(writer, big, encoding, info)?; + } + if self.header_size >= 28 { + self.entry_point.pack(writer, big, encoding, info)?; + } + if self.header_size >= 32 { + self.static_initialize.pack(writer, big, encoding, info)?; + } + if self.header_size >= 36 { + self.resume_prepare.pack(writer, big, encoding, info)?; + } + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub struct WideString(pub String); + +impl StructUnpack for WideString { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let length = u32::unpack(reader, big, encoding, info)? as usize; + let to_read = length * 2; + let buf = reader.read_exact_vec(to_read)?; + let enc = if big { + Encoding::Utf16BE + } else { + Encoding::Utf16LE + }; + let s = decode_to_string(enc, &buf, true)?; + Ok(Self(s)) + } +} + +impl StructPack for WideString { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + let enc = if big { + Encoding::Utf16BE + } else { + Encoding::Utf16LE + }; + let encoded = encode_string(enc, &self.0, false)?; + let length = (encoded.len() / 2) as u32; + length.pack(writer, big, encoding, info)?; + writer.write_all(&encoded)?; + Ok(()) + } +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct BaseClassInfoEntry { + pub flags: u32, + pub name: WideString, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct ECSCastInterface { + pub cast_object: i32, + pub var_offset: i32, + pub var_bounds: i32, + pub func_offset: i32, +} + +#[derive(Clone, Debug, StructPack, StructUnpack)] +pub struct BaseClassCastInfoEntry { + pub name: WideString, + pub pci: ECSCastInterface, + pub flags: u32, +} diff --git a/src/scripts/escude/list.rs b/src/scripts/escude/list.rs index 94997a4..d5f6a43 100644 --- a/src/scripts/escude/list.rs +++ b/src/scripts/escude/list.rs @@ -176,24 +176,26 @@ impl EscudeBinList { 0 => { if script_old { ListData::Scr(EnumScr::Scripts2( - reader - .read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::( + count, false, encoding, &None, + )?, )) } else { ListData::Scr(EnumScr::Scripts( - reader - .read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::( + count, false, encoding, &None, + )?, )) } } 1 => ListData::Scr(EnumScr::Names( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 2 => ListData::Scr(EnumScr::Vars( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 3 => ListData::Scr(EnumScr::Scenes( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 9999 => { // Special case for unknown enum source ID @@ -235,19 +237,19 @@ impl EscudeBinList { let count = len / element_size; let data_entry = match id { 0 => ListData::Gfx(EnumGfx::Bgs( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 1 => ListData::Gfx(EnumGfx::Evs( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 2 => ListData::Gfx(EnumGfx::Sts( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 3 => ListData::Gfx(EnumGfx::Efxs( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 4 => ListData::Gfx(EnumGfx::Locs( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 9999 => { // Special case for unknown enum gfx ID @@ -287,16 +289,16 @@ impl EscudeBinList { let count = len / element_size; let data_entry = match id { 0 => ListData::Snd(EnumSnd::Bgm( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 1 => ListData::Snd(EnumSnd::Amb( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 2 => ListData::Snd(EnumSnd::Se( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 3 => ListData::Snd(EnumSnd::Sfx( - reader.read_struct_vec::(count, false, encoding)?, + reader.read_struct_vec::(count, false, encoding, &None)?, )), 9999 => { // Special case for unknown enum sound ID @@ -334,7 +336,7 @@ fn create_file<'a>( let cur_pos = writer.stream_position()?; writer.write_u32(entry.id)?; writer.write_u32(0)?; // Placeholder for size - entry.data.pack(&mut writer, false, encoding)?; + entry.data.pack(&mut writer, false, encoding, &None)?; let end_pos = writer.stream_position()?; let size = (end_pos - cur_pos - 8) as u32; // 8 bytes for id and size writer.seek(std::io::SeekFrom::Start(cur_pos + 4))?; // Seek to size position diff --git a/src/scripts/escude/script.rs b/src/scripts/escude/script.rs index f8e2b37..b819e00 100644 --- a/src/scripts/escude/script.rs +++ b/src/scripts/escude/script.rs @@ -276,7 +276,7 @@ impl Script for EscudeBinScript { strs.push(CString::new(encoded)?); } writer.write_u32(offsets.len() as u32)?; - offsets.pack(&mut writer, false, encoding)?; + offsets.pack(&mut writer, false, encoding, &None)?; writer.write_u32(self.vms.len() as u32)?; writer.write_all(&self.vms)?; writer.write_u32(self.unk1)?; diff --git a/src/scripts/ex_hibit/rld.rs b/src/scripts/ex_hibit/rld.rs index 9784cc9..c4f5c37 100644 --- a/src/scripts/ex_hibit/rld.rs +++ b/src/scripts/ex_hibit/rld.rs @@ -136,14 +136,20 @@ impl Serialize for OpExt { } impl StructPack for OpExt { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { - self.op.op.pack(writer, big, encoding)?; + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { + self.op.op.pack(writer, big, encoding, info)?; let init_count = self.ints.len() as u8; - init_count.pack(writer, big, encoding)?; + init_count.pack(writer, big, encoding, info)?; let unk = (self.op.unk & 0xF0) | (self.strs.len() as u8 & 0xF); - unk.pack(writer, big, encoding)?; + unk.pack(writer, big, encoding, info)?; for i in &self.ints { - i.pack(writer, big, encoding)?; + i.pack(writer, big, encoding, info)?; } for s in &self.strs { let encoded = encode_string(encoding, s, true)?; @@ -155,11 +161,16 @@ impl StructPack for OpExt { } impl StructUnpack for OpExt { - fn unpack(reader: &mut R, big: bool, encoding: Encoding) -> Result { - let op = Op::unpack(reader, big, encoding)?; + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let op = Op::unpack(reader, big, encoding, info)?; let mut ints = Vec::with_capacity(op.init_count as usize); for _ in 0..op.init_count { - let i = u32::unpack(reader, big, encoding)?; + let i = u32::unpack(reader, big, encoding, info)?; ints.push(i); } let mut strs = Vec::with_capacity(op.str_count() as usize); @@ -243,7 +254,7 @@ impl RldScript { None } }; - let header = Header::unpack(&mut reader, false, encoding)?; + let header = Header::unpack(&mut reader, false, encoding, &None)?; let mut decrypted = false; if let Some(key) = &xor_key { Self::xor(&mut reader.data, key); @@ -259,7 +270,7 @@ impl RldScript { reader.pos = header.offset as usize; let mut ops = Vec::with_capacity(header.count as usize); for _ in 0..header.count { - let op = OpExt::unpack(&mut reader, false, encoding)?; + let op = OpExt::unpack(&mut reader, false, encoding, &None)?; ops.push(op); } let name_table = if is_def_chara { @@ -348,7 +359,7 @@ impl RldScript { writer.write_u32_at(12, op_count)?; } for op in ops { - op.pack(&mut writer, false, encoding)?; + op.pack(&mut writer, false, encoding, &None)?; } if self.data.data.len() > self.data.pos { writer.write_all(&self.data.data[self.data.pos..])?; diff --git a/src/scripts/kirikiri/tjs2.rs b/src/scripts/kirikiri/tjs2.rs index 5ce49f0..3a7dc1f 100644 --- a/src/scripts/kirikiri/tjs2.rs +++ b/src/scripts/kirikiri/tjs2.rs @@ -65,7 +65,12 @@ struct DataArea { } impl StructUnpack for DataArea { - fn unpack(reader: &mut R, big: bool, encoding: Encoding) -> Result { + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { reader.align(4)?; let start_loc = reader.stream_position()?; let mut data_tag = [0; 4]; @@ -73,23 +78,23 @@ impl StructUnpack for DataArea { if &data_tag != b"DATA" { return Err(anyhow::anyhow!("Invalid DATA tag")); } - let data_size = u32::unpack(reader, big, encoding)?; - let count = u32::unpack(reader, big, encoding)? as usize; + let data_size = u32::unpack(reader, big, encoding, info)?; + let count = u32::unpack(reader, big, encoding, info)? as usize; let byte_array = reader.read_exact_vec(count)?; reader.align(4)?; - let short_count = u32::unpack(reader, big, encoding)? as usize; - let short_array = reader.read_struct_vec(short_count, big, encoding)?; + let short_count = u32::unpack(reader, big, encoding, info)? as usize; + let short_array = reader.read_struct_vec(short_count, big, encoding, info)?; reader.align(4)?; - let long_count = u32::unpack(reader, big, encoding)? as usize; - let long_array = reader.read_struct_vec(long_count, big, encoding)?; - let longlong_count = u32::unpack(reader, big, encoding)? as usize; - let longlong_array = reader.read_struct_vec(longlong_count, big, encoding)?; - let double_count = u32::unpack(reader, big, encoding)? as usize; - let double_array = reader.read_struct_vec(double_count, big, encoding)?; - let str_count = u32::unpack(reader, big, encoding)? as usize; + let long_count = u32::unpack(reader, big, encoding, info)? as usize; + let long_array = reader.read_struct_vec(long_count, big, encoding, info)?; + let longlong_count = u32::unpack(reader, big, encoding, info)? as usize; + let longlong_array = reader.read_struct_vec(longlong_count, big, encoding, info)?; + let double_count = u32::unpack(reader, big, encoding, info)? as usize; + let double_array = reader.read_struct_vec(double_count, big, encoding, info)?; + let str_count = u32::unpack(reader, big, encoding, info)? as usize; let mut string_array = Vec::with_capacity(str_count); for _ in 0..str_count { - let str_len = u32::unpack(reader, big, encoding)? as usize; + let str_len = u32::unpack(reader, big, encoding, info)? as usize; let str_bytes = reader.read_exact_vec(if encoding.is_utf16le() { str_len * 2 } else { @@ -99,10 +104,10 @@ impl StructUnpack for DataArea { reader.align(4)?; string_array.push(s); } - let octet_count = u32::unpack(reader, big, encoding)? as usize; + let octet_count = u32::unpack(reader, big, encoding, info)? as usize; let mut octet_array = Vec::with_capacity(octet_count); for _ in 0..octet_count { - let octet_len = u32::unpack(reader, big, encoding)? as usize; + let octet_len = u32::unpack(reader, big, encoding, info)? as usize; let octet_bytes = reader.read_exact_vec(octet_len)?; reader.align(4)?; octet_array.push(octet_bytes); @@ -128,30 +133,36 @@ impl StructUnpack for DataArea { } impl StructPack for DataArea { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { writer.write_all(b"DATA")?; let mut tmp = MemWriter::new(); - tmp.write_struct(&(self.byte_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.byte_array.len() as u32), big, encoding, info)?; tmp.write_all(&self.byte_array)?; tmp.align(4)?; - tmp.write_struct(&(self.short_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.short_array.len() as u32), big, encoding, info)?; for v in &self.short_array { - tmp.write_struct(v, big, encoding)?; + tmp.write_struct(v, big, encoding, info)?; } tmp.align(4)?; - tmp.write_struct(&(self.long_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.long_array.len() as u32), big, encoding, info)?; for v in &self.long_array { - tmp.write_struct(v, big, encoding)?; + tmp.write_struct(v, big, encoding, info)?; } - tmp.write_struct(&(self.longlong_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.longlong_array.len() as u32), big, encoding, info)?; for v in &self.longlong_array { - tmp.write_struct(v, big, encoding)?; + tmp.write_struct(v, big, encoding, info)?; } - tmp.write_struct(&(self.double_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.double_array.len() as u32), big, encoding, info)?; for v in &self.double_array { - tmp.write_struct(v, big, encoding)?; + tmp.write_struct(v, big, encoding, info)?; } - tmp.write_struct(&(self.string_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.string_array.len() as u32), big, encoding, info)?; for s in &self.string_array { let encoded = encode_string(encoding, s, false)?; let str_len = if encoding.is_utf16le() { @@ -159,20 +170,20 @@ impl StructPack for DataArea { } else { encoded.len() }; - tmp.write_struct(&(str_len as u32), big, encoding)?; + tmp.write_struct(&(str_len as u32), big, encoding, info)?; tmp.write_all(&encoded)?; tmp.align(4)?; } - tmp.write_struct(&(self.octet_array.len() as u32), big, encoding)?; + tmp.write_struct(&(self.octet_array.len() as u32), big, encoding, info)?; for o in &self.octet_array { - tmp.write_struct(&(o.len() as u32), big, encoding)?; + tmp.write_struct(&(o.len() as u32), big, encoding, info)?; tmp.write_all(o)?; tmp.align(4)?; } // make sure final size is aligned to 4 bytes tmp.data.resize(tmp.pos, 0); let data = tmp.into_inner(); - writer.write_struct(&(data.len() as u32 + 8), big, encoding)?; + writer.write_struct(&(data.len() as u32 + 8), big, encoding, info)?; writer.write_all(&data)?; Ok(()) } @@ -200,7 +211,7 @@ impl Tjs2 { return Err(anyhow::anyhow!("Invalid TJS2 header: {:?}", &header)); } let _file_size = reader.read_u32()?; - let data_area = DataArea::unpack(&mut reader, false, encoding)?; + let data_area = DataArea::unpack(&mut reader, false, encoding, &None)?; let mut remaing = Vec::new(); reader.read_to_end(&mut remaing)?; Ok(Self { @@ -262,7 +273,7 @@ impl Script for Tjs2 { .collect(); file.write_all(b"TJS2100\0")?; file.write_u32(0)?; // placeholder for file size - data_area.pack(&mut file, false, encoding)?; + data_area.pack(&mut file, false, encoding, &None)?; file.write_all(&self.remaing)?; let file_size = file.stream_length()?; file.write_u32_at(8, file_size as u32)?; // write actual file size @@ -297,7 +308,7 @@ impl Script for Tjs2 { }; file.write_all(b"TJS2100\0")?; file.write_u32(0)?; // placeholder for file size - data_area.pack(&mut file, false, encoding)?; + data_area.pack(&mut file, false, encoding, &None)?; file.write_all(&self.remaing)?; let file_size = file.stream_length()?; file.write_u32_at(8, file_size as u32)?; // write actual file size diff --git a/src/scripts/kirikiri/tjs_ns0.rs b/src/scripts/kirikiri/tjs_ns0.rs index 7d53961..41d93b0 100644 --- a/src/scripts/kirikiri/tjs_ns0.rs +++ b/src/scripts/kirikiri/tjs_ns0.rs @@ -81,7 +81,7 @@ impl ScriptBuilder for TjsNs0Builder { iv_len: 0, }; let mut checker = ByteChecker::new(header.seed); - header.pack(&mut writer, false, encoding)?; + header.pack(&mut writer, false, encoding, &None)?; data.pack(&mut checker, &mut writer, false, encoding)?; let checksum = checker.final_check(); writer.write_u32(checksum)?; @@ -102,7 +102,7 @@ enum TjsValue { } fn unpack_string(reader: &mut R, big: bool, encoding: Encoding) -> Result { - let len = u32::unpack(reader, big, encoding)? as usize; + let len = u32::unpack(reader, big, encoding, &None)? as usize; let tlen = if encoding.is_utf16le() { len * 2 } else { len }; let mut buf = vec![0u8; tlen]; reader.read_exact(&mut buf)?; @@ -117,7 +117,7 @@ fn pack_string(s: &str, writer: &mut W, big: bool, encoding: Encoding) } else { encoded.len() as u32 }; - len.pack(writer, big, encoding)?; + len.pack(writer, big, encoding, &None)?; writer.write_all(&encoded)?; Ok(()) } @@ -135,36 +135,36 @@ impl TjsValue { let typ_byte = 0; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; } Self::Str(s) => { let typ_byte = 2; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; pack_string(s, writer, big, encoding)?; } Self::Int(i) => { let typ_byte = 4; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; - i.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; + i.pack(writer, big, encoding, &None)?; } Self::Double(f) => { let typ_byte = 5; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; - f.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; + f.pack(writer, big, encoding, &None)?; } Self::Array(arr) => { let typ_byte = 0x81; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; let arr_len = arr.len() as u32; - arr_len.pack(writer, big, encoding)?; + arr_len.pack(writer, big, encoding, &None)?; for item in arr { item.pack(checker, writer, big, encoding)?; } @@ -173,9 +173,9 @@ impl TjsValue { let typ_byte = 0xC1; let check_byte = checker.get_seed(typ_byte); let typ = ((check_byte as u16) << 8) | (typ_byte as u16); - typ.pack(writer, big, encoding)?; + typ.pack(writer, big, encoding, &None)?; let dict_len = dict.len() as u32; - dict_len.pack(writer, big, encoding)?; + dict_len.pack(writer, big, encoding, &None)?; for (key, value) in dict { pack_string(key, writer, big, encoding)?; value.pack(checker, writer, big, encoding)?; @@ -191,7 +191,7 @@ impl TjsValue { big: bool, encoding: Encoding, ) -> Result { - let typ = u16::unpack(reader, big, encoding)?; + let typ = u16::unpack(reader, big, encoding, &None)?; let typ_byte = (typ & 0xff) as u8; let check_byte = (typ >> 8) as u8; let expected_check = checker.get_seed(typ_byte); @@ -206,10 +206,10 @@ impl TjsValue { Ok(match typ_byte { 0 => TjsValue::Void(()), 2 => TjsValue::Str(unpack_string(reader, big, encoding)?), - 4 => TjsValue::Int(i64::unpack(reader, big, encoding)?), - 5 => TjsValue::Double(f64::unpack(reader, big, encoding)?), + 4 => TjsValue::Int(i64::unpack(reader, big, encoding, &None)?), + 5 => TjsValue::Double(f64::unpack(reader, big, encoding, &None)?), 0x81 => { - let arr_len = u32::unpack(reader, big, encoding)? as usize; + let arr_len = u32::unpack(reader, big, encoding, &None)? as usize; let mut arr = Vec::with_capacity(arr_len); for _ in 0..arr_len { arr.push(TjsValue::unpack(checker, reader, big, encoding)?); @@ -217,7 +217,7 @@ impl TjsValue { TjsValue::Array(arr) } 0xC1 => { - let kv_len = u32::unpack(reader, big, encoding)? as usize; + let kv_len = u32::unpack(reader, big, encoding, &None)? as usize; let mut dict = BTreeMap::new(); for _ in 0..kv_len { let key = unpack_string(reader, big, encoding)?; @@ -315,7 +315,7 @@ impl TjsNs0 { config: &ExtraConfig, ) -> Result { let mut reader = MemReader::new(buf); - let header = Header::unpack(&mut reader, false, encoding)?; + let header = Header::unpack(&mut reader, false, encoding, &None)?; if &header.magic != b"TJS/" { return Err(anyhow::anyhow!("Not a valid TJS/ns0 file")); } @@ -405,7 +405,7 @@ impl Script for TjsNs0 { let mut header = self.header.clone(); header.check = *b"ns0\0"; let mut checker = ByteChecker::new(header.seed); - header.pack(&mut file, false, encoding)?; + header.pack(&mut file, false, encoding, &None)?; data.pack(&mut checker, &mut file, false, encoding)?; let checksum = checker.final_check(); file.write_u32(checksum)?; diff --git a/src/scripts/musica/archive/paz.rs b/src/scripts/musica/archive/paz.rs index 5b199ab..62d4f6f 100644 --- a/src/scripts/musica/archive/paz.rs +++ b/src/scripts/musica/archive/paz.rs @@ -371,7 +371,7 @@ impl PazArc { } let mut entries = Vec::with_capacity(count as usize); for _ in 0..count { - let entry: PazEntry = index_stream.read_struct(false, archive_encoding)?; + let entry: PazEntry = index_stream.read_struct(false, archive_encoding, &None)?; entries.push(entry); } entries @@ -694,7 +694,7 @@ impl PazArcWriter { index_stream.write_all(mov_data)?; } for entry in entries.values() { - index_stream.write_struct(entry, false, encoding)?; + index_stream.write_struct(entry, false, encoding, &None)?; } } let index_end = writer.stream_position()?; @@ -912,7 +912,7 @@ impl Archive for PazArcWriter { index_stream.write_all(mov_data)?; } for entry in self.headers.values() { - index_stream.write_struct(entry, false, self.encoding)?; + index_stream.write_struct(entry, false, self.encoding, &None)?; } } Ok(()) diff --git a/src/scripts/softpal/img/pgd/ge.rs b/src/scripts/softpal/img/pgd/ge.rs index 952c31e..981d339 100644 --- a/src/scripts/softpal/img/pgd/ge.rs +++ b/src/scripts/softpal/img/pgd/ge.rs @@ -72,7 +72,7 @@ impl ScriptBuilder for PgdGeBuilder { _unk: 0, }; writer.write_all(b"GE \0")?; - header.pack(&mut writer, false, Encoding::Utf8)?; + header.pack(&mut writer, false, Encoding::Utf8, &None)?; PgdWriter::new(data, options.pgd_fake_compress) .with_method(3) .pack_ge(&mut writer)?; @@ -94,7 +94,7 @@ impl PgdGe { if &magic != b"GE \0" { return Err(anyhow::anyhow!("Not a valid PGD GE image")); } - let header = PgdGeHeader::unpack(&mut input, false, Encoding::Utf8)?; + let header = PgdGeHeader::unpack(&mut input, false, Encoding::Utf8, &None)?; let reader = PgdReader::with_ge_header(input, &header)?; let data = reader.unpack_ge()?; Ok(Self { @@ -144,7 +144,7 @@ impl Script for PgdGe { } header.mode = 3; file.write_all(b"GE \0")?; - header.pack(&mut file, false, Encoding::Utf8)?; + header.pack(&mut file, false, Encoding::Utf8, &None)?; PgdWriter::new(data, self.fake_compress) .with_method(3) .pack_ge(&mut file)?; diff --git a/src/scripts/softpal/img/pgd/pgd3.rs b/src/scripts/softpal/img/pgd/pgd3.rs index fa64568..e7b1282 100644 --- a/src/scripts/softpal/img/pgd/pgd3.rs +++ b/src/scripts/softpal/img/pgd/pgd3.rs @@ -81,7 +81,7 @@ impl Pgd3 { if &sig != b"PGD3" && &sig != b"PGD2" { return Err(anyhow::anyhow!("Not a valid PGD3/PGD2 file")); } - let header = PgdDiffHeader::unpack(&mut reader, false, encoding)?; + let header = PgdDiffHeader::unpack(&mut reader, false, encoding, &None)?; let diff = PgdReader::with_diff_header(reader, &header)?.unpack_overlay()?; let base: Vec = if let Some(archive) = archive { let mut file = archive.open_file_by_name(&header.base_name, true)?; @@ -104,7 +104,7 @@ impl Pgd3 { header.base_name )); } - let base_header = PgdGeHeader::unpack(&mut reader, false, encoding)?; + let base_header = PgdGeHeader::unpack(&mut reader, false, encoding, &None)?; let base = PgdReader::with_ge_header(reader, &base_header)?.unpack_ge()?; Ok(Self { header, @@ -181,7 +181,7 @@ impl Script for Pgd3 { } header.mode = 3; file.write_all(b"GE \0")?; - header.pack(&mut file, false, Encoding::Utf8)?; + header.pack(&mut file, false, Encoding::Utf8, &None)?; PgdWriter::new(data, self.fake_compress) .with_method(3) .pack_ge(&mut file)?; diff --git a/src/scripts/will_plus/img/wip.rs b/src/scripts/will_plus/img/wip.rs index 1b0712a..926e52f 100644 --- a/src/scripts/will_plus/img/wip.rs +++ b/src/scripts/will_plus/img/wip.rs @@ -123,7 +123,7 @@ impl WillPlusWipImage { for frame_index in 0..frame_count { let header_offset = 8 + frame_index * 0x18; data.seek(SeekFrom::Start(header_offset as u64))?; - let header = FrameHeader::unpack(&mut data, false, Encoding::Utf8) + let header = FrameHeader::unpack(&mut data, false, Encoding::Utf8, &None) .with_context(|| format!("Failed to read header for frame {}", frame_index))?; let frame_size = usize::try_from(header.frame_size) .map_err(|_| anyhow!("Frame {} data size too large", frame_index))?; diff --git a/src/scripts/yaneurao/itufuru/archive.rs b/src/scripts/yaneurao/itufuru/archive.rs index c9eba88..04552b1 100644 --- a/src/scripts/yaneurao/itufuru/archive.rs +++ b/src/scripts/yaneurao/itufuru/archive.rs @@ -194,7 +194,7 @@ impl ItufuruArchive { let mut reader = Crypto::new(reader, 0xA5); let mut tfiles = Vec::with_capacity(file_count as usize); for _ in 0..file_count { - let file = ItufuruFileHeader::unpack(&mut reader, false, archive_encoding)?; + let file = ItufuruFileHeader::unpack(&mut reader, false, archive_encoding, &None)?; tfiles.push(file); } let mut files = Vec::with_capacity(tfiles.len()); @@ -318,7 +318,7 @@ impl ItufuruArchiveWriter { } let mut crypto = Crypto::new(&mut writer, 0xA5); for (_, header) in headers.iter() { - header.pack(&mut crypto, false, encoding)?; + header.pack(&mut crypto, false, encoding, &None)?; } Ok(ItufuruArchiveWriter { writer, @@ -355,7 +355,7 @@ impl Archive for ItufuruArchiveWriter { entries.sort_by_key(|h| h.offset); crypto.seek(SeekFrom::Start(16))?; for entry in entries.iter() { - entry.pack(&mut crypto, false, self.encoding)?; + entry.pack(&mut crypto, false, self.encoding, &None)?; } Ok(()) } diff --git a/src/utils/pcm.rs b/src/utils/pcm.rs index 9804535..3fa2402 100644 --- a/src/utils/pcm.rs +++ b/src/utils/pcm.rs @@ -39,7 +39,7 @@ pub fn write_pcm( writer.write_all(b"WAVE")?; writer.write_all(b"fmt ")?; writer.write_u32(16)?; // Size of fmt chunk - format.pack(&mut writer, false, Encoding::Utf8)?; + format.pack(&mut writer, false, Encoding::Utf8, &None)?; writer.write_all(b"data")?; let mut data_size = 0u32; writer.write_u32(0)?; // Placeholder for data size diff --git a/src/utils/struct_pack.rs b/src/utils/struct_pack.rs index 3d74702..9d31ad3 100644 --- a/src/utils/struct_pack.rs +++ b/src/utils/struct_pack.rs @@ -2,6 +2,7 @@ use crate::types::Encoding; use anyhow::Result; use msg_tool_macro::struct_unpack_impl_for_num; +use std::any::Any; use std::io::{Read, Seek, Write}; /// Trait for unpacking a struct from a binary stream. @@ -11,7 +12,13 @@ pub trait StructUnpack: Sized { /// * `reader` - The reader to read the binary data from. /// * `big` - Whether the data is in big-endian format. /// * `encoding` - The encoding to use for string fields. - fn unpack(reader: &mut R, big: bool, encoding: Encoding) -> Result; + /// * `info` - Additional information that may be needed for unpacking. + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result; } /// Trait for packing a struct into a binary stream. @@ -21,13 +28,26 @@ pub trait StructPack: Sized { /// * `writer` - The writer to write the binary data to. /// * `big` - Whether to use big-endian format. /// * `encoding` - The encoding to use for string fields. - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()>; + /// * `info` - Additional information that may be needed for packing. + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()>; } impl StructPack for Vec { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { for item in self { - item.pack(writer, big, encoding)?; + item.pack(writer, big, encoding, info)?; } Ok(()) } @@ -47,7 +67,12 @@ struct_unpack_impl_for_num!(f32); struct_unpack_impl_for_num!(f64); impl StructUnpack for bool { - fn unpack(reader: &mut R, _big: bool, _encoding: Encoding) -> Result { + fn unpack( + reader: &mut R, + _big: bool, + _encoding: Encoding, + _info: &Option>, + ) -> Result { let mut buf = [0u8; 1]; reader.read_exact(&mut buf)?; Ok(buf[0] != 0) @@ -55,37 +80,65 @@ impl StructUnpack for bool { } impl StructPack for bool { - fn pack(&self, writer: &mut W, _big: bool, _encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + _big: bool, + _encoding: Encoding, + _info: &Option>, + ) -> Result<()> { writer.write_all(&[if *self { 1 } else { 0 }])?; Ok(()) } } impl StructPack for Option { - fn pack(&self, writer: &mut W, big: bool, encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result<()> { if let Some(value) = self { - value.pack(writer, big, encoding)?; + value.pack(writer, big, encoding, info)?; } Ok(()) } } impl StructUnpack for Option { - fn unpack(reader: &mut R, big: bool, encoding: Encoding) -> Result { - let value = T::unpack(reader, big, encoding)?; + fn unpack( + reader: &mut R, + big: bool, + encoding: Encoding, + info: &Option>, + ) -> Result { + let value = T::unpack(reader, big, encoding, info)?; Ok(Some(value)) } } impl StructPack for [u8; T] { - fn pack(&self, writer: &mut W, _big: bool, _encoding: Encoding) -> Result<()> { + fn pack( + &self, + writer: &mut W, + _big: bool, + _encoding: Encoding, + _info: &Option>, + ) -> Result<()> { writer.write_all(self)?; Ok(()) } } impl StructUnpack for [u8; T] { - fn unpack(reader: &mut R, _big: bool, _encoding: Encoding) -> Result { + fn unpack( + reader: &mut R, + _big: bool, + _encoding: Encoding, + _info: &Option>, + ) -> Result { let mut buf = [0u8; T]; reader.read_exact(&mut buf)?; Ok(buf)