From 5533e901f7206a204ee1788ccf3771d9d4d52b36 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Sat, 7 Jun 2025 15:17:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=20CPeek=20=E7=89=B9=E6=80=A7?= =?UTF-8?q?=E5=B9=B6=E5=9C=A8=20MemReader=20=E5=92=8C=20MemWriter=20?= =?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E6=94=AF=E6=8C=81=EF=BC=9B=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20V1Parser=20=E5=92=8C=20BGIScript=20=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E5=AD=97=E7=AC=A6=E4=B8=B2=E8=AF=BB=E5=8F=96=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ext/io.rs | 293 +++++++++++++++++++++++++++++++++++++- src/scripts/bgi/parser.rs | 6 +- src/scripts/bgi/script.rs | 11 +- 3 files changed, 296 insertions(+), 14 deletions(-) diff --git a/src/ext/io.rs b/src/ext/io.rs index 2fa5c6e..1ff590a 100644 --- a/src/ext/io.rs +++ b/src/ext/io.rs @@ -1,6 +1,8 @@ use crate::utils::encoding::decode_to_string; use crate::{types::Encoding, utils::struct_pack::StructUnpack}; -use std::{ffi::CString, io::*}; +use std::ffi::CString; +use std::io::*; +use std::sync::Mutex; pub trait Peek { fn peek(&mut self, buf: &mut [u8]) -> Result; @@ -288,6 +290,252 @@ impl Peek for T { } } +pub trait CPeek { + fn cpeek(&self, buf: &mut [u8]) -> Result; + fn cpeek_extract(&self, buf: &mut [u8]) -> Result<()> { + let bytes_read = self.cpeek(buf)?; + if bytes_read < buf.len() { + return Err(std::io::Error::new( + std::io::ErrorKind::UnexpectedEof, + "Not enough data to read", + )); + } + Ok(()) + } + fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result; + fn cpeek_extract_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( + std::io::ErrorKind::UnexpectedEof, + "Not enough data to read", + )); + } + Ok(()) + } + fn cpeek_at_vec(&self, offset: usize, len: usize) -> Result> { + let mut buf = vec![0u8; len]; + let bytes_read = self.cpeek_at(offset, &mut buf)?; + if bytes_read < len { + buf.truncate(bytes_read); + } + Ok(buf) + } + fn cpeek_extract_at_vec(&self, offset: usize, len: usize) -> Result> { + let mut buf = vec![0u8; len]; + self.cpeek_extract_at(offset, &mut buf)?; + Ok(buf) + } + + fn cpeek_u8(&self) -> Result { + let mut buf = [0u8; 1]; + self.cpeek_extract(&mut buf)?; + Ok(buf[0]) + } + fn cpeek_u16(&self) -> Result { + let mut buf = [0u8; 2]; + self.cpeek_extract(&mut buf)?; + Ok(u16::from_le_bytes(buf)) + } + fn cpeek_u16_be(&self) -> Result { + let mut buf = [0u8; 2]; + self.cpeek_extract(&mut buf)?; + Ok(u16::from_be_bytes(buf)) + } + fn cpeek_u32(&self) -> Result { + let mut buf = [0u8; 4]; + self.cpeek_extract(&mut buf)?; + Ok(u32::from_le_bytes(buf)) + } + fn cpeek_u32_be(&self) -> Result { + let mut buf = [0u8; 4]; + self.cpeek_extract(&mut buf)?; + Ok(u32::from_be_bytes(buf)) + } + fn cpeek_u64(&self) -> Result { + let mut buf = [0u8; 8]; + self.cpeek_extract(&mut buf)?; + Ok(u64::from_le_bytes(buf)) + } + fn cpeek_u64_be(&self) -> Result { + let mut buf = [0u8; 8]; + self.cpeek_extract(&mut buf)?; + Ok(u64::from_be_bytes(buf)) + } + fn cpeek_u128(&self) -> Result { + let mut buf = [0u8; 16]; + self.cpeek_extract(&mut buf)?; + Ok(u128::from_le_bytes(buf)) + } + fn cpeek_u128_be(&self) -> Result { + let mut buf = [0u8; 16]; + self.cpeek_extract(&mut buf)?; + Ok(u128::from_be_bytes(buf)) + } + fn cpeek_i8(&self) -> Result { + let mut buf = [0u8; 1]; + self.cpeek_extract(&mut buf)?; + Ok(i8::from_le_bytes(buf)) + } + fn cpeek_i16(&self) -> Result { + let mut buf = [0u8; 2]; + self.cpeek_extract(&mut buf)?; + Ok(i16::from_le_bytes(buf)) + } + fn cpeek_i16_be(&self) -> Result { + let mut buf = [0u8; 2]; + self.cpeek_extract(&mut buf)?; + Ok(i16::from_be_bytes(buf)) + } + fn cpeek_i32(&self) -> Result { + let mut buf = [0u8; 4]; + self.cpeek_extract(&mut buf)?; + Ok(i32::from_le_bytes(buf)) + } + fn cpeek_i32_be(&self) -> Result { + let mut buf = [0u8; 4]; + self.cpeek_extract(&mut buf)?; + Ok(i32::from_be_bytes(buf)) + } + fn cpeek_i64(&self) -> Result { + let mut buf = [0u8; 8]; + self.cpeek_extract(&mut buf)?; + Ok(i64::from_le_bytes(buf)) + } + fn cpeek_i64_be(&self) -> Result { + let mut buf = [0u8; 8]; + self.cpeek_extract(&mut buf)?; + Ok(i64::from_be_bytes(buf)) + } + fn cpeek_i128(&self) -> Result { + let mut buf = [0u8; 16]; + self.cpeek_extract(&mut buf)?; + Ok(i128::from_le_bytes(buf)) + } + fn cpeek_i128_be(&self) -> Result { + let mut buf = [0u8; 16]; + self.cpeek_extract(&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)?; + Ok(buf[0]) + } + fn cpeek_u16_at(&self, offset: usize) -> Result { + let mut buf = [0u8; 2]; + self.cpeek_extract_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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + 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)?; + Ok(i128::from_be_bytes(buf)) + } + + fn cpeek_cstring_at(&self, offset: usize) -> Result { + let mut buf = Vec::new(); + let mut byte = [0u8; 1]; + self.cpeek_at(offset, &mut byte)?; + while byte[0] != 0 { + buf.push(byte[0]); + self.cpeek_at(offset + buf.len(), &mut byte)?; + } + CString::new(buf).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) + } +} + +impl CPeek for Mutex { + fn cpeek(&self, buf: &mut [u8]) -> Result { + let mut lock = self.lock().map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Failed to lock the mutex") + })?; + lock.peek(buf) + } + + fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result { + let mut lock = self.lock().map_err(|_| { + std::io::Error::new(std::io::ErrorKind::Other, "Failed to lock the mutex") + })?; + lock.peek_at(offset, buf) + } +} + pub trait ReadExt { fn read_u8(&mut self) -> Result; fn read_u16(&mut self) -> Result; @@ -637,6 +885,16 @@ impl Seek for MemReader { } } +impl CPeek for MemReader { + fn cpeek(&self, buf: &mut [u8]) -> Result { + self.to_ref().cpeek(buf) + } + + fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result { + self.to_ref().cpeek_at(offset, buf) + } +} + impl<'a> Read for MemReaderRef<'a> { fn read(&mut self, buf: &mut [u8]) -> Result { if self.pos >= self.data.len() { @@ -696,6 +954,22 @@ impl<'a> Seek for MemReaderRef<'a> { } } +impl<'a> CPeek for MemReaderRef<'a> { + fn cpeek(&self, buf: &mut [u8]) -> Result { + let len = self.data.len(); + let bytes_to_read = std::cmp::min(buf.len(), len - self.pos); + buf.copy_from_slice(&self.data[self.pos..self.pos + bytes_to_read]); + Ok(bytes_to_read) + } + + fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result { + let len = self.data.len(); + let bytes_to_read = std::cmp::min(buf.len(), len - offset); + buf.copy_from_slice(&self.data[offset..offset + bytes_to_read]); + Ok(bytes_to_read) + } +} + pub struct MemWriter { data: Vec, pos: usize, @@ -716,6 +990,13 @@ impl MemWriter { pub fn as_slice(&self) -> &[u8] { &self.data } + + pub fn to_ref(&self) -> MemReaderRef { + MemReaderRef { + data: &self.data, + pos: self.pos, + } + } } impl std::fmt::Debug for MemWriter { @@ -782,3 +1063,13 @@ impl Seek for MemWriter { Ok(()) } } + +impl CPeek for MemWriter { + fn cpeek(&self, buf: &mut [u8]) -> Result { + self.to_ref().cpeek(buf) + } + + fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result { + self.to_ref().cpeek_at(offset, buf) + } +} diff --git a/src/scripts/bgi/parser.rs b/src/scripts/bgi/parser.rs index 8016d34..56d607d 100644 --- a/src/scripts/bgi/parser.rs +++ b/src/scripts/bgi/parser.rs @@ -441,10 +441,8 @@ impl<'a> V1Parser<'a> { pub fn is_empty_string(&self, address: usize) -> Result { let start = self.offset + address; - if start >= self.buf.data.len() { - return Err(anyhow::anyhow!("Address out of bounds")); - } - Ok(self.buf.data[start] == 0) + let data = self.buf.cpeek_u8_at(start)?; + Ok(data == 0) } pub fn read_string_at_address(&mut self, address: usize) -> Result { diff --git a/src/scripts/bgi/script.rs b/src/scripts/bgi/script.rs index ad1da42..5c78fd5 100644 --- a/src/scripts/bgi/script.rs +++ b/src/scripts/bgi/script.rs @@ -93,15 +93,8 @@ impl BGIScript { fn read_string(&self, offset: usize) -> Result { let start = self.offset + offset; - let mut end = start; - while self.data.data[end] != 0 { - end += 1; - if end >= self.data.data.len() { - return Err(anyhow::anyhow!("String not null-terminated")); - } - } - let string_data = &self.data.data[start..end]; - let string = decode_to_string(self.encoding, string_data)?; + let string_data = self.data.cpeek_cstring_at(start)?; + let string = decode_to_string(self.encoding, string_data.as_bytes())?; Ok(string) } }