diff --git a/Cargo.lock b/Cargo.lock index 0dffca7..57db029 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,6 +319,7 @@ dependencies = [ "clap", "csv", "encoding_rs", + "flate2", "int-enum", "lazy_static", "msg_tool_macro", diff --git a/Cargo.toml b/Cargo.toml index 1b7e3a3..61d30bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ blowfish = { version = "0.9", optional = true } clap = { version = "4.5", features = ["derive"] } csv = "1.3" encoding_rs = "0.8" +flate2 = { version = "1.1", optional = true } int-enum = { version = "1.2", optional = true } lazy_static = "1.5.0" msg_tool_macro = { path = "./msg_tool_macro" } @@ -19,12 +20,13 @@ serde_json = "1" unicode-segmentation = "1.12" [features] -default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "circus", "escude", "escude-arc", "yaneurao", "yaneurao-itufuru"] +default = ["bgi", "bgi-arc", "bgi-img", "cat-system", "cat-system-arc", "cat-system-img", "circus", "escude", "escude-arc", "yaneurao", "yaneurao-itufuru"] bgi = [] bgi-arc = ["bgi", "utils-bit-stream"] bgi-img = ["bgi", "image", "utils-bit-stream"] cat-system = [] cat-system-arc = ["cat-system", "blowfish", "utils-crc32"] +cat-system-img = ["cat-system", "flate2"] circus = [] escude = ["int-enum"] escude-arc = ["escude", "rand", "utils-bit-stream"] diff --git a/src/ext/io.rs b/src/ext/io.rs index 3f51307..693a8d9 100644 --- a/src/ext/io.rs +++ b/src/ext/io.rs @@ -6,9 +6,9 @@ use std::sync::Mutex; pub trait Peek { fn peek(&mut self, buf: &mut [u8]) -> Result; - fn peek_extract(&mut self, buf: &mut [u8]) -> Result<()>; + fn peek_exact(&mut self, buf: &mut [u8]) -> Result<()>; fn peek_at(&mut self, offset: usize, buf: &mut [u8]) -> Result; - fn peek_extract_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<()>; + fn peek_exact_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<()>; fn peek_at_vec(&mut self, offset: usize, len: usize) -> Result> { let mut buf = vec![0u8; len]; let bytes_read = self.peek_at(offset, &mut buf)?; @@ -17,190 +17,190 @@ pub trait Peek { } Ok(buf) } - fn peek_extract_at_vec(&mut self, offset: usize, len: usize) -> Result> { + fn peek_exact_at_vec(&mut self, offset: usize, len: usize) -> Result> { let mut buf = vec![0u8; len]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(buf) } fn peek_u8(&mut self) -> Result { let mut buf = [0u8; 1]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(buf[0]) } fn peek_u16(&mut self) -> Result { let mut buf = [0u8; 2]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u16::from_le_bytes(buf)) } fn peek_u16_be(&mut self) -> Result { let mut buf = [0u8; 2]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u16::from_be_bytes(buf)) } fn peek_u32(&mut self) -> Result { let mut buf = [0u8; 4]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u32::from_le_bytes(buf)) } fn peek_u32_be(&mut self) -> Result { let mut buf = [0u8; 4]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u32::from_be_bytes(buf)) } fn peek_u64(&mut self) -> Result { let mut buf = [0u8; 8]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) } fn peek_u64_be(&mut self) -> Result { let mut buf = [0u8; 8]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } fn peek_u128(&mut self) -> Result { let mut buf = [0u8; 16]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u128::from_le_bytes(buf)) } fn peek_u128_be(&mut self) -> Result { let mut buf = [0u8; 16]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } fn peek_i8(&mut self) -> Result { let mut buf = [0u8; 1]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i8::from_le_bytes(buf)) } fn peek_i16(&mut self) -> Result { let mut buf = [0u8; 2]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i16::from_le_bytes(buf)) } fn peek_i16_be(&mut self) -> Result { let mut buf = [0u8; 2]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i16::from_be_bytes(buf)) } fn peek_i32(&mut self) -> Result { let mut buf = [0u8; 4]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i32::from_le_bytes(buf)) } fn peek_i32_be(&mut self) -> Result { let mut buf = [0u8; 4]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i32::from_be_bytes(buf)) } fn peek_i64(&mut self) -> Result { let mut buf = [0u8; 8]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } fn peek_i64_be(&mut self) -> Result { let mut buf = [0u8; 8]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) } fn peek_i128(&mut self) -> Result { let mut buf = [0u8; 16]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i128::from_le_bytes(buf)) } fn peek_i128_be(&mut self) -> Result { let mut buf = [0u8; 16]; - self.peek_extract(&mut buf)?; + self.peek_exact(&mut buf)?; Ok(i128::from_be_bytes(buf)) } fn peek_u8_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 1]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(buf[0]) } fn peek_u16_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u16::from_le_bytes(buf)) } fn peek_u16_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u16::from_be_bytes(buf)) } fn peek_u32_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u32::from_le_bytes(buf)) } fn peek_u32_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u32::from_be_bytes(buf)) } fn peek_u64_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u64::from_le_bytes(buf)) } fn peek_u64_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u64::from_be_bytes(buf)) } fn peek_u128_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u128::from_le_bytes(buf)) } fn peek_u128_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(u128::from_be_bytes(buf)) } fn peek_i8_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 1]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i8::from_le_bytes(buf)) } fn peek_i16_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i16::from_le_bytes(buf)) } fn peek_i16_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i16::from_be_bytes(buf)) } fn peek_i32_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i32::from_le_bytes(buf)) } fn peek_i32_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i32::from_be_bytes(buf)) } fn peek_i64_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i64::from_le_bytes(buf)) } fn peek_i64_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i64::from_be_bytes(buf)) } fn peek_i128_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i128::from_le_bytes(buf)) } fn peek_i128_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.peek_extract_at(offset, &mut buf)?; + self.peek_exact_at(offset, &mut buf)?; Ok(i128::from_be_bytes(buf)) } @@ -220,6 +220,29 @@ pub trait Peek { } Ok(vec) } + + fn peek_and_equal(&mut self, data: &[u8]) -> Result<()> { + let mut buf = vec![0u8; data.len()]; + self.peek_exact(&mut buf)?; + if buf != data { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Data does not match", + )); + } + Ok(()) + } + fn peek_and_equal_at(&mut self, offset: usize, data: &[u8]) -> Result<()> { + let mut buf = vec![0u8; data.len()]; + self.peek_exact_at(offset, &mut buf)?; + if buf != data { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Data does not match at offset", + )); + } + Ok(()) + } } impl Peek for T { @@ -230,7 +253,7 @@ impl Peek for T { Ok(bytes_read) } - fn peek_extract(&mut self, buf: &mut [u8]) -> Result<()> { + fn peek_exact(&mut self, buf: &mut [u8]) -> Result<()> { let current_pos = self.stream_position()?; self.read_exact(buf)?; self.seek(SeekFrom::Start(current_pos))?; @@ -245,7 +268,7 @@ impl Peek for T { Ok(bytes_read) } - fn peek_extract_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<()> { + fn peek_exact_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<()> { let current_pos = self.stream_position()?; self.seek(SeekFrom::Start(offset as u64))?; self.read_exact(buf)?; @@ -292,7 +315,7 @@ impl Peek for T { pub trait CPeek { fn cpeek(&self, buf: &mut [u8]) -> Result; - fn cpeek_extract(&self, buf: &mut [u8]) -> Result<()> { + fn cpeek_exact(&self, buf: &mut [u8]) -> Result<()> { let bytes_read = self.cpeek(buf)?; if bytes_read < buf.len() { return Err(std::io::Error::new( @@ -303,7 +326,7 @@ pub trait CPeek { Ok(()) } fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result; - fn cpeek_extract_at(&self, offset: usize, buf: &mut [u8]) -> Result<()> { + fn cpeek_exact_at(&self, offset: usize, buf: &mut [u8]) -> Result<()> { let bytes_read = self.cpeek_at(offset, buf)?; if bytes_read < buf.len() { return Err(std::io::Error::new( @@ -321,190 +344,190 @@ pub trait CPeek { } Ok(buf) } - fn cpeek_extract_at_vec(&self, offset: usize, len: usize) -> Result> { + fn cpeek_exact_at_vec(&self, offset: usize, len: usize) -> Result> { let mut buf = vec![0u8; len]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(buf) } fn cpeek_u8(&self) -> Result { let mut buf = [0u8; 1]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(buf[0]) } fn cpeek_u16(&self) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u16::from_le_bytes(buf)) } fn cpeek_u16_be(&self) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u16::from_be_bytes(buf)) } fn cpeek_u32(&self) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u32::from_le_bytes(buf)) } fn cpeek_u32_be(&self) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u32::from_be_bytes(buf)) } fn cpeek_u64(&self) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) } fn cpeek_u64_be(&self) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } fn cpeek_u128(&self) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u128::from_le_bytes(buf)) } fn cpeek_u128_be(&self) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } fn cpeek_i8(&self) -> Result { let mut buf = [0u8; 1]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i8::from_le_bytes(buf)) } fn cpeek_i16(&self) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i16::from_le_bytes(buf)) } fn cpeek_i16_be(&self) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i16::from_be_bytes(buf)) } fn cpeek_i32(&self) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i32::from_le_bytes(buf)) } fn cpeek_i32_be(&self) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i32::from_be_bytes(buf)) } fn cpeek_i64(&self) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } fn cpeek_i64_be(&self) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) } fn cpeek_i128(&self) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i128::from_le_bytes(buf)) } fn cpeek_i128_be(&self) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract(&mut buf)?; + self.cpeek_exact(&mut buf)?; Ok(i128::from_be_bytes(buf)) } fn cpeek_u8_at(&self, offset: usize) -> Result { let mut buf = [0u8; 1]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(buf[0]) } fn cpeek_u16_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u16::from_le_bytes(buf)) } fn cpeek_u16_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u16::from_be_bytes(buf)) } fn cpeek_u32_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u32::from_le_bytes(buf)) } fn cpeek_u32_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u32::from_be_bytes(buf)) } fn cpeek_u64_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u64::from_le_bytes(buf)) } fn cpeek_u64_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u64::from_be_bytes(buf)) } fn cpeek_u128_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u128::from_le_bytes(buf)) } fn cpeek_u128_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(u128::from_be_bytes(buf)) } fn cpeek_i8_at(&self, offset: usize) -> Result { let mut buf = [0u8; 1]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i8::from_le_bytes(buf)) } fn cpeek_i16_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i16::from_le_bytes(buf)) } fn cpeek_i16_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i16::from_be_bytes(buf)) } fn cpeek_i32_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i32::from_le_bytes(buf)) } fn cpeek_i32_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i32::from_be_bytes(buf)) } fn cpeek_i64_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i64::from_le_bytes(buf)) } fn cpeek_i64_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i64::from_be_bytes(buf)) } fn cpeek_i128_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i128::from_le_bytes(buf)) } fn cpeek_i128_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; - self.cpeek_extract_at(offset, &mut buf)?; + self.cpeek_exact_at(offset, &mut buf)?; Ok(i128::from_be_bytes(buf)) } @@ -518,6 +541,29 @@ pub trait CPeek { } CString::new(buf).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) } + + fn cpeek_and_equal(&self, data: &[u8]) -> Result<()> { + let mut buf = vec![0u8; data.len()]; + self.cpeek_exact(&mut buf)?; + if buf != data { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Data does not match", + )); + } + Ok(()) + } + fn cpeek_and_equal_at(&self, offset: usize, data: &[u8]) -> Result<()> { + let mut buf = vec![0u8; data.len()]; + self.cpeek_exact_at(offset, &mut buf)?; + if buf != data { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Data does not match at offset", + )); + } + Ok(()) + } } impl CPeek for Mutex { @@ -560,6 +606,8 @@ pub trait ReadExt { fn read_fstring(&mut self, len: usize, encoding: Encoding, trim: bool) -> Result; fn read_exact_vec(&mut self, len: usize) -> Result>; + + fn read_and_equal(&mut self, data: &[u8]) -> Result<()>; } impl ReadExt for T { @@ -685,6 +733,18 @@ impl ReadExt for T { self.read_exact(&mut buf)?; Ok(buf) } + + fn read_and_equal(&mut self, data: &[u8]) -> Result<()> { + let mut buf = vec![0u8; data.len()]; + self.read_exact(&mut buf)?; + if buf != data { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Data does not match", + )); + } + Ok(()) + } } pub trait WriteExt { @@ -1047,6 +1107,9 @@ impl<'a> CPeek for MemReaderRef<'a> { fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result { let len = self.data.len(); + if offset >= len { + return Ok(0); + } let bytes_to_read = std::cmp::min(buf.len(), len - offset); buf[..bytes_to_read].copy_from_slice(&self.data[offset..offset + bytes_to_read]); Ok(bytes_to_read) diff --git a/src/scripts/bgi/image/img.rs b/src/scripts/bgi/image/img.rs index df116b3..6c3e700 100644 --- a/src/scripts/bgi/image/img.rs +++ b/src/scripts/bgi/image/img.rs @@ -237,7 +237,7 @@ impl Script for BgiImage { } } } else { - self.data.cpeek_extract_at(0x10, &mut data)?; + self.data.cpeek_exact_at(0x10, &mut data)?; } Ok(ImageData { width: self.width, diff --git a/src/scripts/cat_system/archive/int.rs b/src/scripts/cat_system/archive/int.rs index c62f060..522120b 100644 --- a/src/scripts/cat_system/archive/int.rs +++ b/src/scripts/cat_system/archive/int.rs @@ -138,9 +138,7 @@ impl Read for Entry { format!("Failed to lock mutex: {}", e), ) })?; - reader.seek(SeekFrom::Start( - self.header.offset as u64 + self.pos as u64, - ))?; + reader.seek(SeekFrom::Start(self.header.offset as u64 + self.pos as u64))?; let bytes_read = buf.len().min(self.header.size as usize - self.pos); if bytes_read == 0 { return Ok(0); @@ -302,15 +300,15 @@ impl CSIntArc { let current_offset = reader.stream_position()?; let offset = reader.read_u32()?; let size = reader.read_u32()?; - if offset as u64 <= current_offset || !((offset as u64) < file_size && size as u64 <= file_size && offset as u64 <= file_size as u64 - size as u64) { + if offset as u64 <= current_offset + || !((offset as u64) < file_size + && size as u64 <= file_size + && offset as u64 <= file_size as u64 - size as u64) + { entries.clear(); break; } - let entry = CSIntFileHeader { - name, - offset, - size, - }; + let entry = CSIntFileHeader { name, offset, size }; entries.push(entry); } if !entries.is_empty() { @@ -378,14 +376,12 @@ impl Script for CSIntArc { } fn iter_archive<'a>(&'a mut self) -> Result> + 'a>> { - Ok(Box::new( - self.entries.iter().map(|e| Ok(e.name.clone())), - )) + Ok(Box::new(self.entries.iter().map(|e| Ok(e.name.clone())))) } fn iter_archive_mut<'a>( - &'a mut self, - ) -> Result>> + 'a>> { + &'a mut self, + ) -> Result>> + 'a>> { Ok(Box::new(CSIntArcIter { entries: self.entries.iter(), reader: self.reader.clone(), @@ -423,10 +419,12 @@ impl<'a, T: Iterator, R: Read + Seek + 'static> Iter entry.pos = 0; for i in 0..data.len() / 8 { let j = i * 8; - let l = data[j] as u32 | (data[j + 1] as u32) << 8 + let l = data[j] as u32 + | (data[j + 1] as u32) << 8 | (data[j + 2] as u32) << 16 | (data[j + 3] as u32) << 24; - let r = data[j + 4] as u32 | (data[j + 5] as u32) << 8 + let r = data[j + 4] as u32 + | (data[j + 5] as u32) << 8 | (data[j + 6] as u32) << 16 | (data[j + 7] as u32) << 24; let result = encrypt.decrypt([l, r]); diff --git a/src/scripts/cat_system/image/hg3.rs b/src/scripts/cat_system/image/hg3.rs new file mode 100644 index 0000000..fae8e23 --- /dev/null +++ b/src/scripts/cat_system/image/hg3.rs @@ -0,0 +1,309 @@ +use crate::ext::io::*; +use crate::scripts::base::*; +use crate::types::*; +use crate::utils::bit_stream::*; +use crate::utils::img::*; +use crate::utils::struct_pack::*; +use anyhow::Result; +use flate2::{Decompress, FlushDecompress}; +use msg_tool_macro::*; +use std::io::{Read, Seek, Write}; + +#[derive(Debug)] +pub struct Hg3ImageBuilder {} + +impl Hg3ImageBuilder { + pub const fn new() -> Self { + Hg3ImageBuilder {} + } +} + +impl ScriptBuilder for Hg3ImageBuilder { + fn default_encoding(&self) -> Encoding { + Encoding::Cp932 + } + + fn build_script( + &self, + data: Vec, + _filename: &str, + _encoding: Encoding, + _archive_encoding: Encoding, + config: &ExtraConfig, + ) -> Result> { + Ok(Box::new(Hg3Image::new(data, config)?)) + } + + fn extensions(&self) -> &'static [&'static str] { + &["hg3"] + } + + fn script_type(&self) -> &'static ScriptType { + &ScriptType::CatSystemHg3 + } + + fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option { + if buf_len >= 4 && &buf[0..4] == b"HG-3" { + return Some(255); + } + None + } +} + +#[derive(Debug, Clone, StructPack, StructUnpack)] +struct Hg3Entry { + header_size: u32, + _unk: u32, + width: u32, + height: u32, + bpp: u32, + offset_x: u32, + offset_y: u32, + canvas_width: u32, + canvas_height: u32, +} + +#[derive(Debug)] +pub struct Hg3Image { + data: MemReader, + entries: Vec<(Hg3Entry, usize, usize)>, +} + +impl Hg3Image { + pub fn new(buf: Vec, _config: &ExtraConfig) -> Result { + let mut reader = MemReader::new(buf); + let mut magic = [0u8; 4]; + reader.read_exact(&mut magic)?; + if &magic != b"HG-3" { + return Err(anyhow::anyhow!("Invalid HG-3 image format")); + } + let mut offset = 0xC; + let mut entries = Vec::new(); + let len = reader.data.len(); + while offset + 0x14 < len && reader.cpeek_and_equal_at(offset + 8, b"stdinfo").is_ok() { + let mut section_size = reader.cpeek_u32_at(offset)?; + if section_size == 0 { + section_size = (len - offset as usize) as u32; + } + let stdinfo_size = reader.cpeek_u32_at(offset + 0x10)?; + if reader + .cpeek_and_equal_at(offset + 8 + stdinfo_size as usize, b"img") + .is_ok() + { + reader.pos = offset + 16; + let entry = Hg3Entry::unpack(&mut reader, false, Encoding::Cp932)?; + entries.push((entry, offset + 8, section_size as usize - 8)); + } + offset += section_size as usize; + } + if entries.is_empty() { + return Err(anyhow::anyhow!("No valid entries found in HG-3 image")); + } + Ok(Hg3Image { + data: reader, + entries, + }) + } +} + +impl Script for Hg3Image { + fn default_output_script_type(&self) -> OutputScriptType { + OutputScriptType::Json + } + + fn default_format_type(&self) -> FormatOptions { + FormatOptions::None + } + + fn is_image(&self) -> bool { + true + } + + fn export_image(&self) -> Result { + if self.entries.len() > 1 { + eprintln!( + "WARN: There are multiple entries in the HG-3 image, only the first one will be exported." + ); + crate::COUNTER.inc_warning(); + } + let (entry, offset, size) = &self.entries[0]; + let data = &self.data.data[*offset..*offset + *size]; + let reader = Hg3Reader { + m_input: MemReaderRef::new(data), + m_info: entry.clone(), + m_pixel_size: entry.bpp / 8, + }; + Ok(reader.unpack()?) + } +} + +pub struct Hg3Reader<'a> { + m_input: MemReaderRef<'a>, + m_info: Hg3Entry, + m_pixel_size: u32, +} + +impl<'a> Hg3Reader<'a> { + pub fn unpack_stream( + &mut self, + data_offset: usize, + data_packed: usize, + data_unpacked: usize, + ctl_packed: usize, + ctl_unpacked: usize, + ) -> Result> { + let ctl_offset = data_offset + data_packed; + let mut data = Vec::with_capacity(data_unpacked); + data.resize(data_unpacked, 0); + let z = &self.m_input.data[data_offset..data_offset + data_packed]; + let mut decompressor = Decompress::new(true); + decompressor.decompress(z, &mut data, FlushDecompress::Finish)?; + let z = &self.m_input.data[ctl_offset..ctl_offset + ctl_packed]; + let mut ctl = Vec::with_capacity(ctl_unpacked); + ctl.resize(ctl_unpacked, 0); + let mut decompressor = Decompress::new(true); + decompressor.decompress(z, &mut ctl, FlushDecompress::Finish)?; + let mut bits = LsbBitStream::new(MemReaderRef::new(&ctl)); + let mut copy = bits.get_next_bit()?; + let output_size = Self::get_bit_count(&mut bits)? as usize; + let mut output = Vec::with_capacity(output_size); + output.resize(output_size, 0); + let mut src = 0; + let mut dst = 0; + while dst < output_size { + let count = Self::get_bit_count(&mut bits)? as usize; + if copy { + output[dst..dst + count].copy_from_slice(&data[src..src + count]); + src += count; + } + dst += count; + copy = !copy; + } + Ok(self.apply_delta(&output)) + } + + fn get_bit_count(bits: &mut LsbBitStream>) -> Result { + let mut n = 0; + while !bits.get_next_bit()? { + n += 1; + if n >= 0x20 { + return Err(anyhow::anyhow!("Overflow at HG-3 Reader.")); + } + } + let mut value = 1; + for _ in 0..n { + value = (value << 1) | (bits.get_next_bit()? as u32); + } + Ok(value) + } + + fn convert_value(mut val: u8) -> u8 { + let carry = val & 1 != 0; + val >>= 1; + if carry { val ^ 0xff } else { val } + } + + fn apply_delta(&self, pixels: &[u8]) -> Vec { + let mut table = [[0u32; 0x100]; 4]; + for i in 0..0x100u32 { + let mut val = i & 0xC0; + val <<= 6; + val |= i & 0x30; + val <<= 6; + val |= i & 0x0C; + val <<= 6; + val |= i & 0x03; + table[0][i as usize] = val << 6; + table[1][i as usize] = val << 4; + table[2][i as usize] = val << 2; + table[3][i as usize] = val; + } + let pxl_len = pixels.len(); + let plane_size = pxl_len / 4; + let mut plane0 = 0; + let mut plane1 = plane0 + plane_size; + let mut plane2 = plane1 + plane_size; + let mut plane3 = plane2 + plane_size; + let mut output = Vec::with_capacity(pxl_len); + output.resize(pxl_len, 0); + let mut dst = 0; + while dst < pxl_len { + let val = table[0][pixels[plane0] as usize] + | table[1][pixels[plane1] as usize] + | table[2][pixels[plane2] as usize] + | table[3][pixels[plane3] as usize]; + plane0 += 1; + plane1 += 1; + plane2 += 1; + plane3 += 1; + output[dst] = Self::convert_value(val as u8); + dst += 1; + output[dst] = Self::convert_value((val >> 8) as u8); + dst += 1; + output[dst] = Self::convert_value((val >> 16) as u8); + dst += 1; + output[dst] = Self::convert_value((val >> 24) as u8); + dst += 1; + } + let stride = self.m_info.width * self.m_pixel_size; + for x in self.m_pixel_size..stride { + output[x as usize] = + output[x as usize].wrapping_add(output[x as usize - self.m_pixel_size as usize]); + } + let mut prev = 0; + for _ in 1..self.m_info.height { + let line = prev + stride; + for x in 0..stride { + output[line as usize + x as usize] = output[line as usize + x as usize] + .wrapping_add(output[prev as usize + x as usize]); + } + prev = line; + } + output + } + + fn unpack(mut self) -> Result { + self.m_input.pos = self.m_info.header_size as usize; + let mut image_type = [0; 8]; + self.m_input.read_exact(&mut image_type)?; + if &image_type == b"img0000\0" { + return self.unpack_img0000(); + } else { + return Err(anyhow::anyhow!("Unsupported image type: {:?}", image_type)); + } + } + + fn unpack_img0000(&mut self) -> Result { + self.m_input.pos = self.m_info.header_size as usize + 0x18; + let packed_data_size = self.m_input.read_u32()?; + let data_size = self.m_input.read_u32()?; + let ctl_packed_size = self.m_input.read_u32()?; + let ctl_size = self.m_input.read_u32()?; + let data = self.unpack_stream( + self.m_info.header_size as usize + 0x28, + packed_data_size as usize, + data_size as usize, + ctl_packed_size as usize, + ctl_size as usize, + )?; + let fmt = match self.m_info.bpp { + 24 => ImageColorType::Bgr, + 32 => ImageColorType::Bgra, + _ => { + return Err(anyhow::anyhow!( + "Unsupported BPP: {} in HG-3 image", + self.m_info.bpp + )); + } + }; + let mut img = ImageData { + width: self.m_info.width, + height: self.m_info.height, + color_type: fmt, + depth: 8, + data, + }; + flip_image(&mut img)?; + Ok(img) + } +} diff --git a/src/scripts/cat_system/image/mod.rs b/src/scripts/cat_system/image/mod.rs new file mode 100644 index 0000000..8ec74ac --- /dev/null +++ b/src/scripts/cat_system/image/mod.rs @@ -0,0 +1 @@ +pub mod hg3; diff --git a/src/scripts/cat_system/mod.rs b/src/scripts/cat_system/mod.rs index d8aa5b7..07da0b8 100644 --- a/src/scripts/cat_system/mod.rs +++ b/src/scripts/cat_system/mod.rs @@ -1,2 +1,4 @@ #[cfg(feature = "cat-system-arc")] pub mod archive; +#[cfg(feature = "cat-system-img")] +pub mod image; diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index 5e41391..def004d 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -44,6 +44,8 @@ lazy_static::lazy_static! { Box::new(yaneurao::itufuru::archive::ItufuruArchiveBuilder::new()), #[cfg(feature = "cat-system-arc")] Box::new(cat_system::archive::int::CSIntArcBuilder::new()), + #[cfg(feature = "cat-system-img")] + Box::new(cat_system::image::hg3::Hg3ImageBuilder::new()), ]; pub static ref ALL_EXTS: Vec = BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect(); diff --git a/src/scripts/yaneurao/itufuru/archive.rs b/src/scripts/yaneurao/itufuru/archive.rs index 1268140..1752cdf 100644 --- a/src/scripts/yaneurao/itufuru/archive.rs +++ b/src/scripts/yaneurao/itufuru/archive.rs @@ -254,7 +254,7 @@ impl<'a, T: Iterator, R: Read + Seek> Iterator fn next(&mut self) -> Option { if let Some(entry) = self.entries.next() { let file_offset = entry.offset as usize; - match self.reader.peek_extract_at_vec( + match self.reader.peek_exact_at_vec( file_offset + self.first_file_offset as usize, entry.size as usize, ) { diff --git a/src/types.rs b/src/types.rs index fd49dc5..9a035fe 100644 --- a/src/types.rs +++ b/src/types.rs @@ -245,6 +245,9 @@ pub enum ScriptType { #[cfg(feature = "cat-system-arc")] /// CatSystem2 engine archive CatSystemInt, + #[cfg(feature = "cat-system-img")] + /// CatSystem2 engine image + CatSystemHg3, #[cfg(feature = "circus")] /// Circus MES script Circus, diff --git a/src/utils/bit_stream.rs b/src/utils/bit_stream.rs index ae015a1..98c360c 100644 --- a/src/utils/bit_stream.rs +++ b/src/utils/bit_stream.rs @@ -85,3 +85,51 @@ impl<'a, T: Write> MsbBitWriter<'a, T> { Ok(()) } } + +pub struct LsbBitStream { + pub m_input: T, + m_bits: u32, + pub m_cached_bits: u32, +} + +impl LsbBitStream { + pub fn new(input: T) -> Self { + LsbBitStream { + m_input: input, + m_bits: 0, + m_cached_bits: 0, + } + } + + pub fn get_bits(&mut self, mut count: u32) -> Result { + if self.m_cached_bits >= count { + let mask = (1 << count) - 1; + let value = self.m_bits & mask; + self.m_bits >>= count; + self.m_cached_bits -= count; + Ok(value) + } else { + let mut value = self.m_bits & ((1 << self.m_cached_bits) - 1); + count -= self.m_cached_bits; + let mut shift = self.m_cached_bits; + self.m_cached_bits = 0; + while count >= 8 { + let b = self.m_input.read_u8()?; + value |= (b as u32) << shift; + shift += 8; + count -= 8; + } + if count > 0 { + let b = self.m_input.read_u8()?; + value |= ((b as u32) & ((1 << count) - 1)) << shift; + self.m_bits = b as u32 >> count; + self.m_cached_bits = 8 - count; + } + Ok(value) + } + } + + pub fn get_next_bit(&mut self) -> Result { + Ok(self.get_bits(1)? == 1) + } +} diff --git a/src/utils/img.rs b/src/utils/img.rs index 20795a9..f2326d6 100644 --- a/src/utils/img.rs +++ b/src/utils/img.rs @@ -160,3 +160,26 @@ pub fn decode_img(typ: ImageOutputType, filename: &str) -> Result { } } } + +pub fn flip_image(data: &mut ImageData) -> Result<()> { + if data.height <= 1 { + return Ok(()); + } + let row_size = data.data.len() / data.height as usize; + if row_size == 0 { + return Ok(()); + } + + let mut i = 0; + let mut j = data.height as usize - 1; + while i < j { + let (top, bottom) = data.data.split_at_mut(j * row_size); + let top_row = &mut top[i * row_size..i * row_size + row_size]; + let bottom_row = &mut bottom[0..row_size]; + top_row.swap_with_slice(bottom_row); + i += 1; + j -= 1; + } + + Ok(()) +}