diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index bf38d1e..a3a1f31 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -52,7 +52,7 @@ jobs: submodules: true - name: Document run: | - cargo doc -vv || exit 1 + cargo doc --bins -vv || exit 1 - name: Add index files run: | echo 'Content Moved' > target/doc/index.html diff --git a/README.md b/README.md index abd3a74..18e09e6 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ msg-tool create -t ## Supported Output Script Types - `json` - [GalTransl](https://github.com/GalTransl/GalTransl)'s JSON format - `m3t` - A simple text format that supports both original/llm/translated messages. +- `yaml` - Same as `json`, but in YAML format. ## Supported Image Types | Image Type | Feature Name | diff --git a/src/args.rs b/src/args.rs index 73e52b3..a8d4861 100644 --- a/src/args.rs +++ b/src/args.rs @@ -413,3 +413,43 @@ pub enum Command { pub fn parse_args() -> Arg { Arg::parse() } + +#[cfg(feature = "ex-hibit")] +pub fn load_ex_hibit_rld_xor_key(arg: &Arg) -> anyhow::Result> { + if let Some(key) = &arg.ex_hibit_rld_xor_key { + if key.starts_with("0x") { + return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); + } else { + return Ok(Some(u32::from_str_radix(key, 16)?)); + } + } + if let Some(file) = &arg.ex_hibit_rld_xor_key_file { + let key = std::fs::read_to_string(file)?.trim().to_string(); + if key.starts_with("0x") { + return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); + } else { + return Ok(Some(u32::from_str_radix(&key, 16)?)); + } + } + Ok(None) +} + +#[cfg(feature = "ex-hibit")] +pub fn load_ex_hibit_rld_def_xor_key(arg: &crate::args::Arg) -> anyhow::Result> { + if let Some(key) = &arg.ex_hibit_rld_def_xor_key { + if key.starts_with("0x") { + return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); + } else { + return Ok(Some(u32::from_str_radix(key, 16)?)); + } + } + if let Some(file) = &arg.ex_hibit_rld_def_xor_key_file { + let key = std::fs::read_to_string(file)?.trim().to_string(); + if key.starts_with("0x") { + return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); + } else { + return Ok(Some(u32::from_str_radix(&key, 16)?)); + } + } + Ok(None) +} diff --git a/src/ext/atomic.rs b/src/ext/atomic.rs index 683c602..a98c24a 100644 --- a/src/ext/atomic.rs +++ b/src/ext/atomic.rs @@ -1,3 +1,4 @@ +//!Extensions for atomic operations. use std::sync::atomic::Ordering; /// A trait to help to load and store atomic value quickly. diff --git a/src/ext/fancy_regex.rs b/src/ext/fancy_regex.rs index 5a9bba8..7c7cf0c 100644 --- a/src/ext/fancy_regex.rs +++ b/src/ext/fancy_regex.rs @@ -1,12 +1,15 @@ +//!Extensions for fancy_regex crate. use anyhow::Result; use fancy_regex::Regex; +/// Extension trait for [fancy_regex::Regex] to provide more convenient methods. pub trait FancyRegexExt { /// Splits the input string by the regex pattern. /// Like python's `re.split()`, but returns an iterator. fn py_split<'a>(&'a self, input: &'a str) -> Result>; } +/// An iterator that splits a string by a regex pattern, similar to Python's `re.split()`. pub struct PySplit<'a> { str: &'a str, pos: Vec<(usize, usize)>, diff --git a/src/ext/io.rs b/src/ext/io.rs index f1662fb..d5d5faa 100644 --- a/src/ext/io.rs +++ b/src/ext/io.rs @@ -1,14 +1,26 @@ +//!Extensions for IO operations. use crate::utils::encoding::decode_to_string; use crate::{types::Encoding, utils::struct_pack::StructUnpack}; use std::ffi::CString; use std::io::*; use std::sync::Mutex; +/// A trait to help to peek data from a reader. pub trait Peek { + /// Peeks data from the reader into the provided buffer. + /// Returns the number of bytes read. fn peek(&mut self, buf: &mut [u8]) -> Result; + /// Peeks data from the reader into the provided buffer. + /// Returns an error if the buffer is not filled completely. fn peek_exact(&mut self, buf: &mut [u8]) -> Result<()>; + /// Peeks data from the reader at a specific offset into the provided buffer. + /// Returns the number of bytes read. fn peek_at(&mut self, offset: usize, buf: &mut [u8]) -> Result; + /// Peeks data from the reader at a specific offset into the provided buffer. + /// Returns an error if the buffer is not filled completely. fn peek_exact_at(&mut self, offset: usize, buf: &mut [u8]) -> Result<()>; + /// Peeks data from the reader at a specific offset into a vector. + /// Returns the vector containing the data read. 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,197 +29,250 @@ pub trait Peek { } Ok(buf) } + /// Peeks data from the reader at a specific offset into a vector. + /// Returns an error if the buffer is not filled completely. fn peek_exact_at_vec(&mut self, offset: usize, len: usize) -> Result> { let mut buf = vec![0u8; len]; self.peek_exact_at(offset, &mut buf)?; Ok(buf) } + /// Peeks a [u8] from the reader. fn peek_u8(&mut self) -> Result { let mut buf = [0u8; 1]; self.peek_exact(&mut buf)?; Ok(buf[0]) } + /// Peeks a [u16] from the reader in little-endian order. fn peek_u16(&mut self) -> Result { let mut buf = [0u8; 2]; self.peek_exact(&mut buf)?; Ok(u16::from_le_bytes(buf)) } + /// Peeks a [u16] from the reader in big-endian order. fn peek_u16_be(&mut self) -> Result { let mut buf = [0u8; 2]; self.peek_exact(&mut buf)?; Ok(u16::from_be_bytes(buf)) } + /// Peeks a [u32] from the reader in little-endian order. fn peek_u32(&mut self) -> Result { let mut buf = [0u8; 4]; self.peek_exact(&mut buf)?; Ok(u32::from_le_bytes(buf)) } + /// Peeks a [u32] from the reader in big-endian order. fn peek_u32_be(&mut self) -> Result { let mut buf = [0u8; 4]; self.peek_exact(&mut buf)?; Ok(u32::from_be_bytes(buf)) } + /// Peeks a [u64] from the reader in little-endian order. fn peek_u64(&mut self) -> Result { let mut buf = [0u8; 8]; self.peek_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) } + /// Peeks a [u64] from the reader in big-endian order. fn peek_u64_be(&mut self) -> Result { let mut buf = [0u8; 8]; self.peek_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } + /// Peeks a [u128] from the reader in little-endian order. fn peek_u128(&mut self) -> Result { let mut buf = [0u8; 16]; self.peek_exact(&mut buf)?; Ok(u128::from_le_bytes(buf)) } + /// Peeks a [u128] from the reader in big-endian order. fn peek_u128_be(&mut self) -> Result { let mut buf = [0u8; 16]; self.peek_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } + /// Peeks an [i8] from the reader. fn peek_i8(&mut self) -> Result { let mut buf = [0u8; 1]; self.peek_exact(&mut buf)?; Ok(i8::from_le_bytes(buf)) } + /// Peeks an [i16] from the reader in little-endian order. fn peek_i16(&mut self) -> Result { let mut buf = [0u8; 2]; self.peek_exact(&mut buf)?; Ok(i16::from_le_bytes(buf)) } + /// Peeks an [i16] from the reader in big-endian order. fn peek_i16_be(&mut self) -> Result { let mut buf = [0u8; 2]; self.peek_exact(&mut buf)?; Ok(i16::from_be_bytes(buf)) } + /// Peeks an [i32] from the reader in little-endian order. fn peek_i32(&mut self) -> Result { let mut buf = [0u8; 4]; self.peek_exact(&mut buf)?; Ok(i32::from_le_bytes(buf)) } + /// Peeks an [i32] from the reader in big-endian order. fn peek_i32_be(&mut self) -> Result { let mut buf = [0u8; 4]; self.peek_exact(&mut buf)?; Ok(i32::from_be_bytes(buf)) } + /// Peeks an [i64] from the reader in little-endian order. fn peek_i64(&mut self) -> Result { let mut buf = [0u8; 8]; self.peek_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } + /// Peeks an [i64] from the reader in big-endian order. fn peek_i64_be(&mut self) -> Result { let mut buf = [0u8; 8]; self.peek_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) } + /// Peeks an [i128] from the reader in little-endian order. fn peek_i128(&mut self) -> Result { let mut buf = [0u8; 16]; self.peek_exact(&mut buf)?; Ok(i128::from_le_bytes(buf)) } + /// Peeks an [i128] from the reader in big-endian order. fn peek_i128_be(&mut self) -> Result { let mut buf = [0u8; 16]; self.peek_exact(&mut buf)?; Ok(i128::from_be_bytes(buf)) } + /// Peeks a [u8] at a specific offset from the reader. fn peek_u8_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 1]; self.peek_exact_at(offset, &mut buf)?; Ok(buf[0]) } + /// Peeks a [u16] at a specific offset from the reader in little-endian order. fn peek_u16_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.peek_exact_at(offset, &mut buf)?; Ok(u16::from_le_bytes(buf)) } + /// Peeks a [u16] at a specific offset from the reader in big-endian order. fn peek_u16_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.peek_exact_at(offset, &mut buf)?; Ok(u16::from_be_bytes(buf)) } + /// Peeks a [u32] at a specific offset from the reader in little-endian order. fn peek_u32_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.peek_exact_at(offset, &mut buf)?; Ok(u32::from_le_bytes(buf)) } + /// Peeks a [u32] at a specific offset from the reader in big-endian order. fn peek_u32_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.peek_exact_at(offset, &mut buf)?; Ok(u32::from_be_bytes(buf)) } + /// Peeks a [u64] at a specific offset from the reader in little-endian order. fn peek_u64_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.peek_exact_at(offset, &mut buf)?; Ok(u64::from_le_bytes(buf)) } + /// Peeks a [u64] at a specific offset from the reader in big-endian order. fn peek_u64_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.peek_exact_at(offset, &mut buf)?; Ok(u64::from_be_bytes(buf)) } + /// Peeks a [u128] at a specific offset from the reader in little-endian order. fn peek_u128_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.peek_exact_at(offset, &mut buf)?; Ok(u128::from_le_bytes(buf)) } + /// Peeks a [u128] at a specific offset from the reader in big-endian order. fn peek_u128_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.peek_exact_at(offset, &mut buf)?; Ok(u128::from_be_bytes(buf)) } + /// Peeks an [i8] at a specific offset from the reader. fn peek_i8_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 1]; self.peek_exact_at(offset, &mut buf)?; Ok(i8::from_le_bytes(buf)) } + /// Peeks an [i16] at a specific offset from the reader in little-endian order. fn peek_i16_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.peek_exact_at(offset, &mut buf)?; Ok(i16::from_le_bytes(buf)) } + /// Peeks an [i16] at a specific offset from the reader in big-endian order. fn peek_i16_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.peek_exact_at(offset, &mut buf)?; Ok(i16::from_be_bytes(buf)) } + /// Peeks an [i32] at a specific offset from the reader in little-endian order. fn peek_i32_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.peek_exact_at(offset, &mut buf)?; Ok(i32::from_le_bytes(buf)) } + /// Peeks an [i32] at a specific offset from the reader in big-endian order. fn peek_i32_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.peek_exact_at(offset, &mut buf)?; Ok(i32::from_be_bytes(buf)) } + /// Peeks an [i64] at a specific offset from the reader in little-endian order. fn peek_i64_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.peek_exact_at(offset, &mut buf)?; Ok(i64::from_le_bytes(buf)) } + /// Peeks an [i64] at a specific offset from the reader in big-endian order. fn peek_i64_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.peek_exact_at(offset, &mut buf)?; Ok(i64::from_be_bytes(buf)) } + /// Peeks an [i128] at a specific offset from the reader in little-endian order. fn peek_i128_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.peek_exact_at(offset, &mut buf)?; Ok(i128::from_le_bytes(buf)) } + /// Peeks an [i128] at a specific offset from the reader in big-endian order. fn peek_i128_be_at(&mut self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.peek_exact_at(offset, &mut buf)?; Ok(i128::from_be_bytes(buf)) } + /// Peeks a C-style string (null-terminated) from the reader. fn peek_cstring(&mut self) -> Result; + /// Peeks a C-style string (null-terminated) from the reader at a specific offset. fn peek_cstring_at(&mut self, offset: usize) -> Result; + /// Reads a struct from the reader. + /// The struct must implement the `StructUnpack` trait. + /// + /// * `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; + /// Reads a vector of structs from the reader. + /// The structs must implement the `StructUnpack` trait. + /// + /// * `count` is the number of structs to read. + /// * `big` indicates whether the structs are in big-endian format. + /// * `encoding` specifies the encoding to use for string fields in the structs. + /// Returns a vector of unpacked structs. fn read_struct_vec( &mut self, count: usize, @@ -221,6 +286,7 @@ pub trait Peek { Ok(vec) } + /// Peeks data and checks if it matches the provided data. fn peek_and_equal(&mut self, data: &[u8]) -> Result<()> { let mut buf = vec![0u8; data.len()]; self.peek_exact(&mut buf)?; @@ -232,6 +298,7 @@ pub trait Peek { } Ok(()) } + /// Peeks data at a specific offset and checks if it matches the provided data. 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)?; @@ -313,8 +380,13 @@ impl Peek for T { } } +/// A trait to help to peek data from a reader in a thread-safe manner. pub trait CPeek { + /// Peeks data from the reader into the provided buffer. + /// Returns the number of bytes read. fn cpeek(&self, buf: &mut [u8]) -> Result; + /// Peeks data from the reader into the provided buffer. + /// Returns an error if the buffer is not filled completely. fn cpeek_exact(&self, buf: &mut [u8]) -> Result<()> { let bytes_read = self.cpeek(buf)?; if bytes_read < buf.len() { @@ -325,7 +397,11 @@ pub trait CPeek { } Ok(()) } + /// Peeks data from the reader at a specific offset into the provided buffer. + /// Returns the number of bytes read. fn cpeek_at(&self, offset: usize, buf: &mut [u8]) -> Result; + /// Peeks data from the reader at a specific offset into the provided buffer. + /// Returns an error if the buffer is not filled completely. fn cpeek_exact_at(&self, offset: usize, buf: &mut [u8]) -> Result<()> { let bytes_read = self.cpeek_at(offset, buf)?; if bytes_read < buf.len() { @@ -336,6 +412,8 @@ pub trait CPeek { } Ok(()) } + /// Peeks data from the reader at a specific offset into a vector. + /// Returns the vector containing the data read. 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)?; @@ -344,195 +422,235 @@ pub trait CPeek { } Ok(buf) } + /// Peeks data from the reader at a specific offset into a vector. + /// Returns an error if the buffer is not filled completely. fn cpeek_exact_at_vec(&self, offset: usize, len: usize) -> Result> { let mut buf = vec![0u8; len]; self.cpeek_exact_at(offset, &mut buf)?; Ok(buf) } + /// Peeks a [u8] from the reader. fn cpeek_u8(&self) -> Result { let mut buf = [0u8; 1]; self.cpeek_exact(&mut buf)?; Ok(buf[0]) } + /// Peeks a [u16] from the reader in little-endian order. fn cpeek_u16(&self) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact(&mut buf)?; Ok(u16::from_le_bytes(buf)) } + /// Peeks a [u16] from the reader in big-endian order. fn cpeek_u16_be(&self) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact(&mut buf)?; Ok(u16::from_be_bytes(buf)) } + /// Peeks a [u32] from the reader in little-endian order. fn cpeek_u32(&self) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact(&mut buf)?; Ok(u32::from_le_bytes(buf)) } + /// Peeks a [u32] from the reader in big-endian order. fn cpeek_u32_be(&self) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact(&mut buf)?; Ok(u32::from_be_bytes(buf)) } + /// Peeks a [u64] from the reader in little-endian order. fn cpeek_u64(&self) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) } + /// Peeks a [u64] from the reader in big-endian order. fn cpeek_u64_be(&self) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) } + /// Peeks a [u128] from the reader in little-endian order. fn cpeek_u128(&self) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact(&mut buf)?; Ok(u128::from_le_bytes(buf)) } + /// Peeks a [u128] from the reader in big-endian order. fn cpeek_u128_be(&self) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact(&mut buf)?; Ok(u128::from_be_bytes(buf)) } + /// Peeks an [i8] from the reader. fn cpeek_i8(&self) -> Result { let mut buf = [0u8; 1]; self.cpeek_exact(&mut buf)?; Ok(i8::from_le_bytes(buf)) } + /// Peeks an [i16] from the reader in little-endian order. fn cpeek_i16(&self) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact(&mut buf)?; Ok(i16::from_le_bytes(buf)) } + /// Peeks an [i16] from the reader in big-endian order. fn cpeek_i16_be(&self) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact(&mut buf)?; Ok(i16::from_be_bytes(buf)) } + /// Peeks an [i32] from the reader in little-endian order. fn cpeek_i32(&self) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact(&mut buf)?; Ok(i32::from_le_bytes(buf)) } + /// Peeks an [i32] from the reader in big-endian order. fn cpeek_i32_be(&self) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact(&mut buf)?; Ok(i32::from_be_bytes(buf)) } + /// Peeks an [i64] from the reader in little-endian order. fn cpeek_i64(&self) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) } + /// Peeks an [i64] from the reader in big-endian order. fn cpeek_i64_be(&self) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) } + /// Peeks an [i128] from the reader in little-endian order. fn cpeek_i128(&self) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact(&mut buf)?; Ok(i128::from_le_bytes(buf)) } + /// Peeks an [i128] from the reader in big-endian order. fn cpeek_i128_be(&self) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact(&mut buf)?; Ok(i128::from_be_bytes(buf)) } + /// Peeks a [u8] at a specific offset from the reader. fn cpeek_u8_at(&self, offset: usize) -> Result { let mut buf = [0u8; 1]; self.cpeek_exact_at(offset, &mut buf)?; Ok(buf[0]) } + /// Peeks a [u16] at a specific offset from the reader in little-endian order. fn cpeek_u16_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u16::from_le_bytes(buf)) } + /// Peeks a [u16] at a specific offset from the reader in big-endian order. fn cpeek_u16_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u16::from_be_bytes(buf)) } + /// Peeks a [u32] at a specific offset from the reader in little-endian order. fn cpeek_u32_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u32::from_le_bytes(buf)) } + /// Peeks a [u32] at a specific offset from the reader in big-endian order. fn cpeek_u32_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u32::from_be_bytes(buf)) } + /// Peeks a [u64] at a specific offset from the reader in little-endian order. fn cpeek_u64_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u64::from_le_bytes(buf)) } + /// Peeks a [u64] at a specific offset from the reader in big-endian order. fn cpeek_u64_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u64::from_be_bytes(buf)) } + /// Peeks a [u128] at a specific offset from the reader in little-endian order. fn cpeek_u128_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u128::from_le_bytes(buf)) } + /// Peeks a [u128] at a specific offset from the reader in big-endian order. fn cpeek_u128_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact_at(offset, &mut buf)?; Ok(u128::from_be_bytes(buf)) } + /// Peeks an [i8] at a specific offset from the reader. fn cpeek_i8_at(&self, offset: usize) -> Result { let mut buf = [0u8; 1]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i8::from_le_bytes(buf)) } + /// Peeks an [i16] at a specific offset from the reader in little-endian order. fn cpeek_i16_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i16::from_le_bytes(buf)) } + /// Peeks an [i16] at a specific offset from the reader in big-endian order. fn cpeek_i16_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 2]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i16::from_be_bytes(buf)) } + /// Peeks an [i32] at a specific offset from the reader in little-endian order. fn cpeek_i32_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i32::from_le_bytes(buf)) } + /// Peeks an [i32] at a specific offset from the reader in big-endian order. fn cpeek_i32_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 4]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i32::from_be_bytes(buf)) } + /// Peeks an [i64] at a specific offset from the reader in little-endian order. fn cpeek_i64_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i64::from_le_bytes(buf)) } + /// Peeks an [i64] at a specific offset from the reader in big-endian order. fn cpeek_i64_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 8]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i64::from_be_bytes(buf)) } + /// Peeks an [i128] at a specific offset from the reader in little-endian order. fn cpeek_i128_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i128::from_le_bytes(buf)) } + /// Peeks an [i128] at a specific offset from the reader in big-endian order. fn cpeek_i128_be_at(&self, offset: usize) -> Result { let mut buf = [0u8; 16]; self.cpeek_exact_at(offset, &mut buf)?; Ok(i128::from_be_bytes(buf)) } + /// Peeks a C-style string (null-terminated) from the reader. fn cpeek_cstring(&self) -> Result; + /// Peeks a C-style string (null-terminated) from the reader at a specific offset. fn cpeek_cstring_at(&self, offset: usize) -> Result { let mut buf = Vec::new(); let mut byte = [0u8; 1]; @@ -544,6 +662,7 @@ pub trait CPeek { CString::new(buf).map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e)) } + /// Peeks data and checks if it matches the provided data. fn cpeek_and_equal(&self, data: &[u8]) -> Result<()> { let mut buf = vec![0u8; data.len()]; self.cpeek_exact(&mut buf)?; @@ -555,6 +674,7 @@ pub trait CPeek { } Ok(()) } + /// Peeks data at a specific offset and checks if it matches the provided data. 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)?; @@ -591,31 +711,57 @@ impl CPeek for Mutex { } } +/// A trait to help to read data from a reader. pub trait ReadExt { + /// Reads a [u8] from the reader. fn read_u8(&mut self) -> Result; + /// Reads a [u16] from the reader in little-endian order. fn read_u16(&mut self) -> Result; + /// Reads a [u16] from the reader in big-endian order. fn read_u16_be(&mut self) -> Result; + /// Reads a [u32] from the reader in little-endian order. fn read_u32(&mut self) -> Result; + /// Reads a [u32] from the reader in big-endian order. fn read_u32_be(&mut self) -> Result; + /// Reads a [u64] from the reader in little-endian order. fn read_u64(&mut self) -> Result; + /// Reads a [u64] from the reader in big-endian order. fn read_u64_be(&mut self) -> Result; + /// Reads a [u128] from the reader in little-endian order. fn read_u128(&mut self) -> Result; + /// Reads a [u128] from the reader in big-endian order. fn read_u128_be(&mut self) -> Result; + /// Reads an [i8] from the reader. fn read_i8(&mut self) -> Result; + /// Reads an [i16] from the reader in little-endian order. fn read_i16(&mut self) -> Result; + /// Reads an [i16] from the reader in big-endian order. fn read_i16_be(&mut self) -> Result; + /// Reads an [i32] from the reader in little-endian order. fn read_i32(&mut self) -> Result; + /// Reads an [i32] from the reader in big-endian order. fn read_i32_be(&mut self) -> Result; + /// Reads an [i64] from the reader in little-endian order. fn read_i64(&mut self) -> Result; + /// Reads an [i64] from the reader in big-endian order. fn read_i64_be(&mut self) -> Result; + /// Reads an [i128] from the reader in little-endian order. fn read_i128(&mut self) -> Result; + /// Reads an [i128] from the reader in big-endian order. fn read_i128_be(&mut self) -> Result; + /// Reads a C-style string (null-terminated) from the reader. fn read_cstring(&mut self) -> Result; + /// Reads a C-style string (null-terminated) from the reader with maximum length. + /// * `len` is the maximum length of the string to read. + /// * `encoding` specifies the encoding to use for the string. + /// * `trim` indicates whether to trim the string after the first null byte. fn read_fstring(&mut self, len: usize, encoding: Encoding, trim: bool) -> Result; + /// Reads some data from the reader into a vector. fn read_exact_vec(&mut self, len: usize) -> Result>; + /// Reads data and checks if it matches the provided data. fn read_and_equal(&mut self, data: &[u8]) -> Result<()>; } @@ -756,26 +902,46 @@ impl ReadExt for T { } } +/// A trait to help to write data to a writer. pub trait WriteExt { + /// Writes a [u8] to the writer. fn write_u8(&mut self, value: u8) -> Result<()>; + /// Writes a [u16] to the writer in little-endian order. fn write_u16(&mut self, value: u16) -> Result<()>; + /// Writes a [u16] to the writer in big-endian order. fn write_u16_be(&mut self, value: u16) -> Result<()>; + /// Writes a [u32] to the writer in little-endian order. fn write_u32(&mut self, value: u32) -> Result<()>; + /// Writes a [u32] to the writer in big-endian order. fn write_u32_be(&mut self, value: u32) -> Result<()>; + /// Writes a [u64] to the writer in little-endian order. fn write_u64(&mut self, value: u64) -> Result<()>; + /// Writes a [u64] to the writer in big-endian order. fn write_u64_be(&mut self, value: u64) -> Result<()>; + /// Writes a [u128] to the writer in little-endian order. fn write_u128(&mut self, value: u128) -> Result<()>; + /// Writes a [u128] to the writer in big-endian order. fn write_u128_be(&mut self, value: u128) -> Result<()>; + /// Writes an [i8] to the writer. fn write_i8(&mut self, value: i8) -> Result<()>; + /// Writes an [i16] to the writer in little-endian order. fn write_i16(&mut self, value: i16) -> Result<()>; + /// Writes an [i16] to the writer in big-endian order. fn write_i16_be(&mut self, value: i16) -> Result<()>; + /// Writes an [i32] to the writer in little-endian order. fn write_i32(&mut self, value: i32) -> Result<()>; + /// Writes an [i32] to the writer in big-endian order. fn write_i32_be(&mut self, value: i32) -> Result<()>; + /// Writes an [i64] to the writer in little-endian order. fn write_i64(&mut self, value: i64) -> Result<()>; + /// Writes an [i64] to the writer in big-endian order. fn write_i64_be(&mut self, value: i64) -> Result<()>; + /// Writes an [i128] to the writer in little-endian order. fn write_i128(&mut self, value: i128) -> Result<()>; + /// Writes an [i128] to the writer in big-endian order. fn write_i128_be(&mut self, value: i128) -> Result<()>; + /// Writes a C-style string (null-terminated) to the writer. fn write_cstring(&mut self, value: &CString) -> Result<()>; } @@ -840,65 +1006,89 @@ impl WriteExt for T { } } +/// A trait to help to write data to a writer at a specific offset. pub trait WriteAt { + /// Writes data to the writer at a specific offset. + /// Returns the number of bytes written. fn write_at(&mut self, offset: usize, buf: &[u8]) -> Result; + /// Writes all data to the writer at a specific offset. + /// Returns an error if the write fails. fn write_all_at(&mut self, offset: usize, buf: &[u8]) -> Result<()>; + /// Writes a [u8] at a specific offset. fn write_u8_at(&mut self, offset: usize, value: u8) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes a [u16] at a specific offset in little-endian order. fn write_u16_at(&mut self, offset: usize, value: u16) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes a [u16] at a specific offset in big-endian order. fn write_u16_be_at(&mut self, offset: usize, value: u16) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes a [u32] at a specific offset in little-endian order. fn write_u32_at(&mut self, offset: usize, value: u32) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes a [u32] at a specific offset in big-endian order. fn write_u32_be_at(&mut self, offset: usize, value: u32) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes a [u64] at a specific offset in little-endian order. fn write_u64_at(&mut self, offset: usize, value: u64) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes a [u64] at a specific offset in big-endian order. fn write_u64_be_at(&mut self, offset: usize, value: u64) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes a [u128] at a specific offset in little-endian order. fn write_u128_at(&mut self, offset: usize, value: u128) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes a [u128] at a specific offset in big-endian order. fn write_u128_be_at(&mut self, offset: usize, value: u128) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes an [i8] at a specific offset. fn write_i8_at(&mut self, offset: usize, value: i8) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes an [i16] at a specific offset in little-endian order. fn write_i16_at(&mut self, offset: usize, value: i16) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes an [i16] at a specific offset in big-endian order. fn write_i16_be_at(&mut self, offset: usize, value: i16) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes an [i32] at a specific offset in little-endian order. fn write_i32_at(&mut self, offset: usize, value: i32) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes an [i32] at a specific offset in big-endian order. fn write_i32_be_at(&mut self, offset: usize, value: i32) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes an [i64] at a specific offset in little-endian order. fn write_i64_at(&mut self, offset: usize, value: i64) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes an [i64] at a specific offset in big-endian order. fn write_i64_be_at(&mut self, offset: usize, value: i64) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes an [i128] at a specific offset in little-endian order. fn write_i128_at(&mut self, offset: usize, value: i128) -> Result<()> { self.write_all_at(offset, &value.to_le_bytes()) } + /// Writes an [i128] at a specific offset in big-endian order. fn write_i128_be_at(&mut self, offset: usize, value: i128) -> Result<()> { self.write_all_at(offset, &value.to_be_bytes()) } + /// Writes a C-style string (null-terminated) at a specific offset. fn write_cstring_at(&mut self, offset: usize, value: &CString) -> Result<()> { self.write_all_at(offset, value.as_bytes_with_nul()) } @@ -922,7 +1112,9 @@ impl WriteAt for T { } } +/// A trait to help to seek in a stream. pub trait SeekExt { + /// Returns the length of the stream. fn stream_length(&mut self) -> Result; } @@ -935,14 +1127,20 @@ impl SeekExt for T { } } +/// A memory reader that can read data from a vector of bytes. pub struct MemReader { + /// The data to read from. pub data: Vec, + /// The current position in the data. pub pos: usize, } +/// A memory reader that can read data from a slice of bytes. #[derive(Clone)] pub struct MemReaderRef<'a> { + /// The data to read from. pub data: &'a [u8], + /// The current position in the data. pub pos: usize, } @@ -965,10 +1163,12 @@ impl<'a> std::fmt::Debug for MemReaderRef<'a> { } impl MemReader { + /// Creates a new `MemReader` with the given data. pub fn new(data: Vec) -> Self { MemReader { data, pos: 0 } } + /// Creates a new [MemReaderRef] from the current data and position. pub fn to_ref<'a>(&'a self) -> MemReaderRef<'a> { MemReaderRef { data: &self.data, @@ -976,20 +1176,24 @@ impl MemReader { } } + /// Checks if the reader has reached the end of the data. pub fn is_eof(&self) -> bool { self.pos >= self.data.len() } + /// Returns the inner data of the reader. pub fn inner(self) -> Vec { self.data } } impl<'a> MemReaderRef<'a> { + /// Creates a new `MemReaderRef` with the given data. pub fn new(data: &'a [u8]) -> Self { MemReaderRef { data, pos: 0 } } + /// Checks if the reader has reached the end of the data. pub fn is_eof(&self) -> bool { self.pos >= self.data.len() } @@ -1157,12 +1361,16 @@ impl<'a> CPeek for MemReaderRef<'a> { } } +/// A memory writer that can write data to a vector of bytes. pub struct MemWriter { + /// The data to write to. pub data: Vec, + /// The current position in the data. pub pos: usize, } impl MemWriter { + /// Creates a new `MemWriter` with an empty data vector. pub fn new() -> Self { MemWriter { data: Vec::new(), @@ -1170,18 +1378,22 @@ impl MemWriter { } } + /// Creates a new `MemWriter` with the given data. pub fn from_vec(data: Vec) -> Self { MemWriter { data, pos: 0 } } + /// Returns the inner data of the writer. pub fn into_inner(self) -> Vec { self.data } + /// Returns a reference to the inner data of the writer. pub fn as_slice(&self) -> &[u8] { &self.data } + /// Returns a new `MemReaderRef` that references the current data and position. pub fn to_ref<'a>(&'a self) -> MemReaderRef<'a> { MemReaderRef { data: &self.data, @@ -1269,6 +1481,7 @@ impl CPeek for MemWriter { } } +/// A region of a stream that can be read/write and seeked within a specified range. pub struct StreamRegion { stream: T, start_pos: u64, @@ -1277,6 +1490,7 @@ pub struct StreamRegion { } impl StreamRegion { + /// Creates a new `StreamRegion` with the specified stream and position range. pub fn new(stream: T, start_pos: u64, end_pos: u64) -> Result { if start_pos > end_pos { return Err(std::io::Error::new( @@ -1292,6 +1506,8 @@ impl StreamRegion { }) } + /// Creates a new `StreamRegion` with the specified stream and start position. + /// The end position is determined by the length of the stream. pub fn with_start_pos(mut stream: T, start_pos: u64) -> Result { let end_pos = stream.stream_length()?; Self::new(stream, start_pos, end_pos) diff --git a/src/ext/mod.rs b/src/ext/mod.rs index 7162ed3..dacb47e 100644 --- a/src/ext/mod.rs +++ b/src/ext/mod.rs @@ -1,3 +1,4 @@ +//! Extensions for other crates. pub mod atomic; #[cfg(feature = "fancy-regex")] pub mod fancy_regex; diff --git a/src/ext/psb.rs b/src/ext/psb.rs index 23f3d9f..578e57b 100644 --- a/src/ext/psb.rs +++ b/src/ext/psb.rs @@ -1,3 +1,4 @@ +//!Extensions for emote_psb crate. use emote_psb::VirtualPsb; use emote_psb::header::PsbHeader; use emote_psb::types::collection::*; @@ -14,27 +15,46 @@ use std::ops::{Index, IndexMut}; const NONE: PsbValueFixed = PsbValueFixed::None; #[derive(Debug)] +/// Represents of a PSB value. pub enum PsbValueFixed { + /// No value. None, + /// Represents a null value. Null, + /// Represents a boolean value. Bool(bool), + /// Represents a number value. Number(PsbNumber), + /// Represents an array of integers. IntArray(PsbUintArray), + /// Represents a string value. String(PsbString), + /// Represents a list of PSB values. List(PsbListFixed), + /// Represents an object with key-value pairs. Object(PsbObjectFixed), + /// Represents a resource reference. Resource(PsbResourceRef), + /// Represents an extra resource reference. ExtraResource(PsbExtraRef), + /// Represents a compiler number. CompilerNumber, + /// Represents a compiler string. CompilerString, + /// Represents a compiler resource. CompilerResource, + /// Represents a compiler decimal. CompilerDecimal, + /// Represents a compiler array. CompilerArray, + /// Represents a compiler boolean. CompilerBool, + /// Represents a compiler binary tree. CompilerBinaryTree, } impl PsbValueFixed { + /// Converts this value to original PSB value type. pub fn to_psb(self) -> PsbValue { match self { PsbValueFixed::None => PsbValue::None, @@ -57,30 +77,37 @@ impl PsbValueFixed { } } + /// Returns true if this value is a list. pub fn is_list(&self) -> bool { matches!(self, PsbValueFixed::List(_)) } + /// Returns true if this value is an object. pub fn is_object(&self) -> bool { matches!(self, PsbValueFixed::Object(_)) } + /// Returns true if this value is a string or null. pub fn is_string_or_null(&self) -> bool { self.is_string() || self.is_null() } + /// Returns true if this value is a string. pub fn is_string(&self) -> bool { matches!(self, PsbValueFixed::String(_)) } + /// Returns true if this value is none. pub fn is_none(&self) -> bool { matches!(self, PsbValueFixed::None) } + /// Returns true if this value is null. pub fn is_null(&self) -> bool { matches!(self, PsbValueFixed::Null) } + /// Sets the value of this PSB value to a new string. pub fn set_str(&mut self, value: &str) { match self { PsbValueFixed::String(s) => { @@ -94,18 +121,22 @@ impl PsbValueFixed { } } + /// Sets the value of this PSB value to a new string. pub fn set_string(&mut self, value: String) { self.set_str(&value); } + /// Returns the value as a boolean, if it is a boolean. pub fn as_u8(&self) -> Option { self.as_i64().map(|n| n.try_into().ok()).flatten() } + /// Returns the value as a [u32], if it is a number. pub fn as_u32(&self) -> Option { self.as_i64().map(|n| n as u32) } + /// Returns the value as a [i64], if it is a number. pub fn as_i64(&self) -> Option { match self { PsbValueFixed::Number(n) => match n { @@ -116,6 +147,7 @@ impl PsbValueFixed { } } + /// Returns the value as a string, if it is a string. pub fn as_str(&self) -> Option<&str> { match self { PsbValueFixed::String(s) => Some(s.string()), @@ -123,6 +155,7 @@ impl PsbValueFixed { } } + /// Returns the lengtho of a list or object. pub fn len(&self) -> usize { match self { PsbValueFixed::List(l) => l.len(), @@ -131,6 +164,7 @@ impl PsbValueFixed { } } + /// Returns a iterator over the entries of an object. pub fn entries(&self) -> ObjectIter<'_> { match self { PsbValueFixed::Object(o) => o.iter(), @@ -138,6 +172,7 @@ impl PsbValueFixed { } } + /// Returns a mutable iterator over the entries of an object. pub fn entries_mut(&mut self) -> ObjectIterMut<'_> { match self { PsbValueFixed::Object(o) => o.iter_mut(), @@ -145,6 +180,7 @@ impl PsbValueFixed { } } + /// Returns a iterator over the members of a list. pub fn members(&self) -> ListIter<'_> { match self { PsbValueFixed::List(l) => l.iter(), @@ -152,6 +188,7 @@ impl PsbValueFixed { } } + /// Returns a mutable iterator over the members of a list. pub fn members_mut(&mut self) -> ListIterMut<'_> { match self { PsbValueFixed::List(l) => l.iter_mut(), @@ -159,6 +196,7 @@ impl PsbValueFixed { } } + /// Returns the resource ID if this value is a resource reference. pub fn resource_id(&self) -> Option { match self { PsbValueFixed::Resource(r) => Some(r.resource_ref), @@ -166,6 +204,7 @@ impl PsbValueFixed { } } + /// Converts this value to a JSON value, if possible. #[cfg(feature = "json")] pub fn to_json(&self) -> Option { match self { @@ -193,6 +232,7 @@ impl PsbValueFixed { } } + /// Converts a JSON value to a PSB value. #[cfg(feature = "json")] pub fn from_json(obj: &JsonValue) -> Self { match obj { @@ -378,7 +418,9 @@ impl<'a> PartialEq<&'a str> for PsbValueFixed { } } +/// Trait to convert a PSB value to a fixed PSB value. pub trait PsbValueExt { + /// Converts this PSB value to a fixed PSB value. fn to_psb_fixed(self) -> PsbValueFixed; } @@ -407,36 +449,44 @@ impl PsbValueExt for PsbValue { } #[derive(Clone, Debug)] +/// Represents a PSB list of PSB values. pub struct PsbListFixed { + /// The values in the list. pub values: Vec, } impl PsbListFixed { + /// Converts this PSB list to a original PSB list. pub fn to_psb(self) -> PsbList { let v: Vec<_> = self.values.into_iter().map(|v| v.to_psb()).collect(); PsbList::from(v) } + /// Returns a iterator over the values in the list. pub fn iter(&self) -> ListIter<'_> { ListIter { inner: self.values.iter(), } } + /// Returns a mutable iterator over the values in the list. pub fn iter_mut(&mut self) -> ListIterMut<'_> { ListIterMut { inner: self.values.iter_mut(), } } + /// Returns a reference to the values in the list. pub fn values(&self) -> &Vec { &self.values } + /// Returns the length of the list. pub fn len(&self) -> usize { self.values.len() } + /// Converts this PSB list to a JSON value. #[cfg(feature = "json")] pub fn to_json(&self) -> JsonValue { let data: Vec<_> = self.values.iter().filter_map(|v| v.to_json()).collect(); @@ -463,11 +513,13 @@ impl IndexMut for PsbListFixed { } } +/// Iterator for a slice of PSB values in a list. pub struct ListIter<'a> { inner: std::slice::Iter<'a, PsbValueFixed>, } impl<'a> ListIter<'a> { + /// Creates an empty iterator. pub fn empty() -> Self { ListIter { inner: Default::default(), @@ -497,11 +549,13 @@ impl<'a> DoubleEndedIterator for ListIter<'a> { } } +/// Mutable iterator for a slice of PSB values in a list. pub struct ListIterMut<'a> { inner: std::slice::IterMut<'a, PsbValueFixed>, } impl<'a> ListIterMut<'a> { + /// Creates an empty mutable iterator. pub fn empty() -> Self { ListIterMut { inner: Default::default(), @@ -531,7 +585,9 @@ impl<'a> DoubleEndedIterator for ListIterMut<'a> { } } +/// Trait to convert a PSB list to a fixed PSB list. pub trait PsbListExt { + /// Converts this PSB list to a fixed PSB list. fn to_psb_fixed(self) -> PsbListFixed; } @@ -547,11 +603,14 @@ impl PsbListExt for PsbList { } #[derive(Clone, Debug)] +/// Represents a PSB object with key-value pairs. pub struct PsbObjectFixed { + /// The key-value pairs in the object. pub values: HashMap, } impl PsbObjectFixed { + /// Creates a new empty PSB object. pub fn to_psb(self) -> PsbObject { let mut hash_map = HashMap::new(); for (key, value) in self.values { @@ -560,22 +619,26 @@ impl PsbObjectFixed { PsbObject::from(hash_map) } + /// Gets a reference of value in the object by key. pub fn get_value(&self, key: &str) -> Option<&PsbValueFixed> { self.values.get(key) } + /// Returns a iterator over the entries of the object. pub fn iter(&self) -> ObjectIter<'_> { ObjectIter { inner: self.values.iter(), } } + /// Returns a mutable iterator over the entries of the object. pub fn iter_mut(&mut self) -> ObjectIterMut<'_> { ObjectIterMut { inner: self.values.iter_mut(), } } + /// Converts this PSB object to a JSON value. #[cfg(feature = "json")] pub fn to_json(&self) -> JsonValue { let mut obj = json::object::Object::new(); @@ -587,6 +650,7 @@ impl PsbObjectFixed { JsonValue::Object(obj) } + /// Converts a JSON object to a PSB object. #[cfg(feature = "json")] pub fn from_json(obj: &JsonValue) -> Self { let mut values = HashMap::new(); @@ -639,7 +703,9 @@ impl IndexMut for PsbObjectFixed { } } +/// Trait to convert a PSB object to a fixed PSB object. pub trait PsbObjectExt { + /// Converts this PSB object to a fixed PSB object. fn to_psb_fixed(self) -> PsbObjectFixed; } @@ -653,11 +719,13 @@ impl PsbObjectExt for PsbObject { } } +/// Iterator for a slice of PSB values in an object. pub struct ObjectIter<'a> { inner: std::collections::hash_map::Iter<'a, String, PsbValueFixed>, } impl<'a> ObjectIter<'a> { + /// Creates an empty iterator. pub fn empty() -> Self { ObjectIter { inner: Default::default(), @@ -679,11 +747,13 @@ impl<'a> ExactSizeIterator for ObjectIter<'a> { } } +/// Mutable iterator for a slice of PSB values in an object. pub struct ObjectIterMut<'a> { inner: std::collections::hash_map::IterMut<'a, String, PsbValueFixed>, } impl<'a> ObjectIterMut<'a> { + /// Creates an empty mutable iterator. pub fn empty() -> Self { ObjectIterMut { inner: Default::default(), @@ -706,6 +776,7 @@ impl<'a> ExactSizeIterator for ObjectIterMut<'a> { } } +/// Represents a fixed version of a virtual PSB. #[derive(Clone, Debug)] pub struct VirtualPsbFixed { header: PsbHeader, @@ -715,6 +786,7 @@ pub struct VirtualPsbFixed { } impl VirtualPsbFixed { + /// Creates a new fixed virtual PSB. pub fn new( header: PsbHeader, resources: Vec>, @@ -729,47 +801,58 @@ impl VirtualPsbFixed { } } + /// Returns the header of the PSB. pub fn header(&self) -> PsbHeader { self.header } + /// Returns a reference to the resources of the PSB. pub fn resources(&self) -> &Vec> { &self.resources } + /// Returns a mutable reference to the resources of the PSB. pub fn resources_mut(&mut self) -> &mut Vec> { &mut self.resources } + /// Returns a reference to the extra resources of the PSB. pub fn extra(&self) -> &Vec> { &self.extra } + /// Returns a mutable reference to the extra resources of the PSB. pub fn extra_mut(&mut self) -> &mut Vec> { &mut self.extra } + /// Returns a reference to the root object of the PSB. pub fn root(&self) -> &PsbObjectFixed { &self.root } + /// Returns a mutable reference to the root object of the PSB. pub fn root_mut(&mut self) -> &mut PsbObjectFixed { &mut self.root } + /// Sets the root of the PSB. pub fn set_root(&mut self, root: PsbObjectFixed) { self.root = root; } + /// Unwraps the PSB into its components. pub fn unwrap(self) -> (PsbHeader, Vec>, Vec>, PsbObjectFixed) { (self.header, self.resources, self.extra, self.root) } + /// Converts this fixed PSB to a virtual PSB. pub fn to_psb(self) -> VirtualPsb { let (header, resources, extra, root) = self.unwrap(); VirtualPsb::new(header, resources, extra, root.to_psb()) } + /// Converts json object to a fixed PSB. #[cfg(feature = "json")] pub fn from_json(&mut self, obj: &JsonValue) -> Result<(), anyhow::Error> { let version = obj["version"] @@ -784,6 +867,7 @@ impl VirtualPsbFixed { Ok(()) } + /// Converts this fixed PSB to a JSON object. #[cfg(feature = "json")] pub fn to_json(&self) -> JsonValue { json::object! { @@ -794,7 +878,9 @@ impl VirtualPsbFixed { } } +/// Trait to convert a virtual PSB to a fixed PSB. pub trait VirtualPsbExt { + /// Converts this virtual PSB to a fixed PSB. fn to_psb_fixed(self) -> VirtualPsbFixed; } diff --git a/src/ext/vec.rs b/src/ext/vec.rs index 33f20d9..5763423 100644 --- a/src/ext/vec.rs +++ b/src/ext/vec.rs @@ -1,3 +1,5 @@ +//!Extensions for vector operations. +/// Extensions for vector operations. pub trait VecExt { /// Copy potentially overlapping sequence of elements from `src` to `dst`. fn copy_overlapped(&mut self, src: usize, dst: usize, len: usize); diff --git a/src/format/mod.rs b/src/format/mod.rs index 5171c89..0464d09 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -1,7 +1,9 @@ +//! Module for formatting messages. mod fixed; use crate::types::*; +/// Formats messages with the given options. pub fn fmt_message(mes: &mut Vec, opt: FormatOptions, typ: ScriptType) { match opt { FormatOptions::Fixed { diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..bb27c4e --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,11 @@ +//! A Rust library for exporting, importing, packing, and unpacking script files. +pub mod ext; +pub mod format; +pub mod output_scripts; +pub mod scripts; +pub mod types; +pub mod utils; + +lazy_static::lazy_static! { + static ref COUNTER: utils::counter::Counter = utils::counter::Counter::new(); +} diff --git a/src/main.rs b/src/main.rs index a8aa0c7..6c8c41a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1725,10 +1725,10 @@ fn main() { #[cfg(feature = "circus-img")] circus_crx_mode: arg.circus_crx_mode, #[cfg(feature = "ex-hibit")] - ex_hibit_rld_xor_key: scripts::ex_hibit::rld::load_xor_key(&arg) + ex_hibit_rld_xor_key: args::load_ex_hibit_rld_xor_key(&arg) .expect("Failed to load RLD XOR key"), #[cfg(feature = "ex-hibit")] - ex_hibit_rld_def_xor_key: scripts::ex_hibit::rld::load_def_xor_key(&arg) + ex_hibit_rld_def_xor_key: args::load_ex_hibit_rld_def_xor_key(&arg) .expect("Failed to load RLD DEF XOR key"), #[cfg(feature = "ex-hibit")] ex_hibit_rld_keys: scripts::ex_hibit::rld::load_keys(arg.ex_hibit_rld_keys.as_ref()) diff --git a/src/output_scripts/m3t.rs b/src/output_scripts/m3t.rs index c9542b5..abadca4 100644 --- a/src/output_scripts/m3t.rs +++ b/src/output_scripts/m3t.rs @@ -1,12 +1,24 @@ +//! A simple text format that supports both original/llm/translated messages. +//! +//! A simple m3t file example: +//! ```text +//! ○ NAME: Example +//! +//! ○ Original message +//! △ LLM message +//! ● Translated message +//! ``` use crate::types::Message; use anyhow::Result; +/// A parser for the M3T format. pub struct M3tParser<'a> { str: &'a str, line: usize, } impl<'a> M3tParser<'a> { + /// Creates a new M3tParser with the given string. pub fn new(str: &'a str) -> Self { M3tParser { str, line: 1 } } @@ -31,6 +43,7 @@ impl<'a> M3tParser<'a> { } } + /// Parses the M3T format and returns a vector of messages. pub fn parse(&mut self) -> Result> { let mut messages = Vec::new(); let mut name = None; @@ -79,9 +92,11 @@ impl<'a> M3tParser<'a> { } } +/// A dumper for the M3T format. pub struct M3tDumper {} impl M3tDumper { + /// Dumps the messages in M3T format. pub fn dump(messages: &[Message]) -> String { let mut result = String::new(); for message in messages { diff --git a/src/output_scripts/mod.rs b/src/output_scripts/mod.rs index 52fe378..6929b74 100644 --- a/src/output_scripts/mod.rs +++ b/src/output_scripts/mod.rs @@ -1 +1,2 @@ +//! Module for output scripts. pub mod m3t; diff --git a/src/scripts/artemis/archive/mod.rs b/src/scripts/artemis/archive/mod.rs index b92ef74..d76546c 100644 --- a/src/scripts/artemis/archive/mod.rs +++ b/src/scripts/artemis/archive/mod.rs @@ -1 +1,2 @@ +//! Artemis Engine Archive pub mod pfs; diff --git a/src/scripts/artemis/archive/pfs.rs b/src/scripts/artemis/archive/pfs.rs index cc2d656..5e443fa 100644 --- a/src/scripts/artemis/archive/pfs.rs +++ b/src/scripts/artemis/archive/pfs.rs @@ -1,3 +1,4 @@ +//! Artemis Engine PFS Archive (pf6 and pf8) use crate::ext::io::*; use crate::scripts::base::*; use crate::types::*; @@ -10,9 +11,11 @@ use std::io::{Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Mutex}; #[derive(Debug)] +/// The builder for Artemis PFS archive scripts. pub struct ArtemisArcBuilder {} impl ArtemisArcBuilder { + /// Creates a new instance of `ArtemisArcBuilder`. pub fn new() -> Self { ArtemisArcBuilder {} } @@ -125,6 +128,7 @@ struct PfsEntryHeader { } #[derive(Debug)] +/// The Artemis PFS archive script. pub struct ArtemisArc { reader: Arc>, entries: Vec, @@ -133,6 +137,12 @@ pub struct ArtemisArc { } impl ArtemisArc { + /// Creates a new Artemis PFS archive script. + /// + /// * `reader` - The reader for the archive. + /// * `archive_encoding` - The encoding used for the archive. + /// * `config` - Extra configuration options. + /// * `filename` - The name of the archive file. pub fn new( mut reader: T, archive_encoding: Encoding, @@ -336,6 +346,7 @@ fn detect_script_type(buf: &[u8], buf_len: usize, filename: &str) -> Option { writer: T, headers: HashMap, @@ -345,6 +356,12 @@ pub struct ArtemisArcWriter { } impl ArtemisArcWriter { + /// Creates a new Artemis PFS archive writer. + /// + /// * `writer` - The writer for the archive. + /// * `files` - The list of files to include in the archive. + /// * `encoding` - The encoding used for the archive. + /// * `config` - Extra configuration options. pub fn new( mut writer: T, files: &[&str], @@ -445,6 +462,7 @@ impl Archive for ArtemisArcWriter { } } +/// The Artemis PFS archive file writer. pub struct ArtemisArcFile<'a, T: Write + Seek> { header: &'a mut PfsEntryHeader, writer: &'a mut T, diff --git a/src/scripts/artemis/asb.rs b/src/scripts/artemis/asb.rs index af58286..e222f0d 100644 --- a/src/scripts/artemis/asb.rs +++ b/src/scripts/artemis/asb.rs @@ -1,3 +1,4 @@ +//! Artemis Engine ASB file (.asb) use crate::ext::io::*; use crate::scripts::base::*; use crate::types::*; @@ -11,9 +12,11 @@ use std::ops::Index; use unicode_segmentation::UnicodeSegmentation; #[derive(Debug)] +/// The builder for Artemis ASB scripts. pub struct ArtemisAsbBuilder {} impl ArtemisAsbBuilder { + /// Creates a new instance of `ArtemisAsbBuilder`. pub fn new() -> Self { ArtemisAsbBuilder {} } @@ -408,11 +411,17 @@ impl<'a> TextParser<'a> { } #[derive(Debug)] +/// The Artemis ASB script. pub struct Asb { items: Vec, } impl Asb { + /// Creates a new Artemis ASB script from the given buffer. + /// + /// * `buf` - The buffer containing the ASB data. + /// * `encoding` - The encoding used for the ASB data. + /// * `config` - Extra configuration options. pub fn new(buf: Vec, encoding: Encoding, _config: &ExtraConfig) -> Result { let mut data = MemReader::new(buf); let mut magic = [0; 5]; @@ -654,6 +663,12 @@ impl Script for Asb { } } +/// Creates a new ASB file. +/// +/// * `custom_filename` - The path ot the input file. +/// * `writer` - The writer to write the ASB script. +/// * `encoding` - The encoding used for the ASB script. +/// * `output_encoding` - The encoding used for the input file. pub fn create_file<'a>( custom_filename: &'a str, mut writer: Box, diff --git a/src/scripts/artemis/ast/mod.rs b/src/scripts/artemis/ast/mod.rs index 1826632..2b5a67b 100644 --- a/src/scripts/artemis/ast/mod.rs +++ b/src/scripts/artemis/ast/mod.rs @@ -1,3 +1,4 @@ +//! Artemis Engine AST file (.ast) mod dump; mod parser; mod text; @@ -11,9 +12,11 @@ use std::io::Write; use types::*; #[derive(Debug)] +/// The builder for Artemis AST scripts. pub struct AstScriptBuilder {} impl AstScriptBuilder { + /// Creates a new instance of `AstScriptBuilder`. pub fn new() -> Self { AstScriptBuilder {} } @@ -55,6 +58,7 @@ impl ScriptBuilder for AstScriptBuilder { } #[derive(Debug)] +/// The Artemis AST script. pub struct AstScript { ast: AstFile, indent: Option, @@ -64,6 +68,11 @@ pub struct AstScript { } impl AstScript { + /// Creates a new Artemis AST script from the given buffer. + /// + /// * `buf` - The buffer containing the AST data. + /// * `encoding` - The encoding used for the AST data. + /// * `config` - Extra configuration options. pub fn new(buf: Vec, encoding: Encoding, config: &ExtraConfig) -> Result { let parser = parser::Parser::new(&buf, encoding); let ast = parser.parse()?; @@ -680,6 +689,11 @@ impl Script for AstScript { } } +/// Checks if the given buffer is in the Artemis AST format. +/// +/// * `filename` - The name of the file. +/// * `buf` - The buffer containing the data. +/// * `buf_len` - The length of the buffer. pub fn is_this_format(_filename: &str, buf: &[u8], buf_len: usize) -> bool { let parser = parser::Parser::new(&buf[..buf_len], Encoding::Utf8); parser.try_parse_header().is_ok() diff --git a/src/scripts/artemis/mod.rs b/src/scripts/artemis/mod.rs index c749590..579fa1e 100644 --- a/src/scripts/artemis/mod.rs +++ b/src/scripts/artemis/mod.rs @@ -1,3 +1,4 @@ +//! Artemis Engine Scripts #[cfg(feature = "artemis-arc")] pub mod archive; pub mod asb; diff --git a/src/scripts/base.rs b/src/scripts/base.rs index 5630033..c862759 100644 --- a/src/scripts/base.rs +++ b/src/scripts/base.rs @@ -1,12 +1,16 @@ +//! Basic traits and types for script. use crate::ext::io::*; use crate::types::*; use anyhow::Result; use std::io::{Read, Seek, Write}; +/// A trait for reading and seeking in a stream. pub trait ReadSeek: Read + Seek + std::fmt::Debug {} +/// A trait for writing and seeking in a stream. pub trait WriteSeek: Write + Seek {} +/// A trait for types that can be displayed in debug format and are also support downcasting. pub trait AnyDebug: std::fmt::Debug + std::any::Any {} impl ReadSeek for T {} @@ -15,17 +19,30 @@ impl WriteSeek for T {} impl AnyDebug for T {} +/// A trait for script builders. pub trait ScriptBuilder: std::fmt::Debug { + /// Returns the default encoding for the script. fn default_encoding(&self) -> Encoding; + /// Returns the default encoding for the archive. + /// If None, the default encoding should be used. fn default_archive_encoding(&self) -> Option { None } + /// Returns the default encoding for script files when patching scripts. fn default_patched_encoding(&self) -> Encoding { self.default_encoding() } + /// Builds a script from the given buffer. + /// + /// * `buf` - The buffer containing the script data. + /// * `filename` - The name of the file from which the script was read. + /// * `encoding` - The encoding of the script data. + /// * `archive_encoding` - The encoding of the archive, if applicable. + /// * `config` - Additional configuration options. + /// * `archive` - An optional archive to which the script belongs. fn build_script( &self, buf: Vec, @@ -36,6 +53,13 @@ pub trait ScriptBuilder: std::fmt::Debug { archive: Option<&Box>, ) -> Result>; + /// Builds a script from a file. + /// + /// * `filename` - The name of the file to read. + /// * `encoding` - The encoding of the script data. + /// * `archive_encoding` - The encoding of the archive, if applicable. + /// * `config` - Additional configuration options. + /// * `archive` - An optional archive to which the script belongs. fn build_script_from_file( &self, filename: &str, @@ -48,6 +72,14 @@ pub trait ScriptBuilder: std::fmt::Debug { self.build_script(data, filename, encoding, archive_encoding, config, archive) } + /// Builds a script from a reader. + /// + /// * `reader` - A reader with seek capabilities. + /// * `filename` - The name of the file from which the script was read. + /// * `encoding` - The encoding of the script data. + /// * `archive_encoding` - The encoding of the archive, if applicable. + /// * `config` - Additional configuration options. + /// * `archive` - An optional archive to which the script belongs. fn build_script_from_reader( &self, mut reader: Box, @@ -64,18 +96,34 @@ pub trait ScriptBuilder: std::fmt::Debug { self.build_script(data, filename, encoding, archive_encoding, config, archive) } + /// Returns the extensions supported by this script builder. fn extensions(&self) -> &'static [&'static str]; + /// Checks if the given filename and buffer match this script format. + /// * `filename` - The name of the file to check. + /// * `buf` - The buffer containing the script data. + /// * `buf_len` - The length of the buffer. + /// + /// Returns a score (0-255) indicating how well the format matches. + /// A higher score means a better match. fn is_this_format(&self, _filename: &str, _buf: &[u8], _buf_len: usize) -> Option { None } + /// Returns the script type associated with this builder. fn script_type(&self) -> &'static ScriptType; + /// Returns true if this script is an archive. fn is_archive(&self) -> bool { false } + /// Creates an archive with the given files. + /// + /// * `filename` - The path of the archive file to create. + /// * `files` - A list of files to include in the archive. + /// * `encoding` - The encoding to use for the archive. + /// * `config` - Additional configuration options. fn create_archive( &self, _filename: &str, @@ -88,10 +136,18 @@ pub trait ScriptBuilder: std::fmt::Debug { )) } + /// Returns true if this script type can create from a file directly. fn can_create_file(&self) -> bool { false } + /// Creates a new script file. + /// + /// * `filename` - The path to the input file. + /// * `writer` - A writer with seek capabilities to write the script data. + /// * `encoding` - The encoding to use for the script data. + /// * `file_encoding` - The encoding of the file. + /// * `config` - Additional configuration options. fn create_file<'a>( &'a self, _filename: &'a str, @@ -105,6 +161,13 @@ pub trait ScriptBuilder: std::fmt::Debug { )) } + /// Creates a new script file with the given filename. + /// + /// * `filename` - The path to the input file. + /// * `output_filename` - The path to the output file. + /// * `encoding` - The encoding to use for the script data. + /// * `file_encoding` - The encoding of the file. + /// * `config` - Additional configuration options. fn create_file_filename( &self, filename: &str, @@ -118,16 +181,23 @@ pub trait ScriptBuilder: std::fmt::Debug { self.create_file(filename, Box::new(f), encoding, file_encoding, config) } + /// Returns true if this script is an image. #[cfg(feature = "image")] fn is_image(&self) -> bool { false } + /// Returns true if this script type can create from an image file directly. #[cfg(feature = "image")] fn can_create_image_file(&self) -> bool { false } + /// Creates an image file from the given data. + /// + /// * `data` - The image data to write. + /// * `writer` - A writer with seek capabilities to write the image data. + /// * `options` - Additional configuration options. #[cfg(feature = "image")] fn create_image_file<'a>( &'a self, @@ -140,6 +210,11 @@ pub trait ScriptBuilder: std::fmt::Debug { )) } + /// Creates an image file from the given data to the specified filename. + /// + /// * `data` - The image data to write. + /// * `filename` - The path to the output file. + /// * `options` - Additional configuration options. #[cfg(feature = "image")] fn create_image_file_filename( &self, @@ -153,37 +228,49 @@ pub trait ScriptBuilder: std::fmt::Debug { } } +/// A trait to present the file in an archive. pub trait ArchiveContent: Read { + /// Returns the name of the file in the archive. fn name(&self) -> &str; + /// Returns true if the file is a script. fn is_script(&self) -> bool { self.script_type().is_some() } + /// Returns the script type if the file is a script. fn script_type(&self) -> Option<&ScriptType> { None } + /// Returns the data of the file as a vector of bytes. fn data(&mut self) -> Result> { let mut data = Vec::new(); self.read_to_end(&mut data)?; Ok(data) } + /// Returns a reader that supports reading and seeking. fn to_data<'a>(&'a mut self) -> Result> { Ok(Box::new(MemReader::new(self.data()?))) } } +/// A trait for script types. pub trait Script: std::fmt::Debug + std::any::Any { + /// Returns the default output script type for this script. fn default_output_script_type(&self) -> OutputScriptType; + /// Checks if the given output script type is supported by this script. fn is_output_supported(&self, output: OutputScriptType) -> bool { !matches!(output, OutputScriptType::Custom) } + /// Returns the output extension for this script when exporting with custom output. fn custom_output_extension<'a>(&'a self) -> &'a str { "" } + /// Returns the default format options for this script. fn default_format_type(&self) -> FormatOptions; + /// Extract messages from this script. fn extract_messages(&self) -> Result> { if !self.is_archive() { return Err(anyhow::anyhow!( @@ -193,6 +280,12 @@ pub trait Script: std::fmt::Debug + std::any::Any { Ok(vec![]) } + /// Import messages into this script. + /// + /// * `messages` - The messages to import. + /// * `file` - A writer with seek capabilities to write the patched scripts. + /// * `encoding` - The encoding to use for the patched scripts. + /// * `replacement` - An optional replacement table for message replacements. fn import_messages<'a>( &'a self, _messages: Vec, @@ -208,6 +301,12 @@ pub trait Script: std::fmt::Debug + std::any::Any { Ok(()) } + /// Import messages into this script. + /// + /// * `messages` - The messages to import. + /// * `filename` - The path of the file to write the patched scripts. + /// * `encoding` - The encoding to use for the patched scripts. + /// * `replacement` - An optional replacement table for message replacements. fn import_messages_filename( &self, _messages: Vec, @@ -220,12 +319,22 @@ pub trait Script: std::fmt::Debug + std::any::Any { self.import_messages(_messages, Box::new(f), _encoding, _replacement) } + /// Exports data from this script. + /// + /// * `filename` - The path of the file to write the exported data. + /// * `encoding` - The encoding to use for the exported data. fn custom_export(&self, _filename: &std::path::Path, _encoding: Encoding) -> Result<()> { Err(anyhow::anyhow!( "This script type does not support custom export." )) } + /// Imports data into this script. + /// + /// * `custom_filename` - The path of the file to import. + /// * `file` - A writer with seek capabilities to write the patched scripts. + /// * `encoding` - The encoding of the patched scripts. + /// * `output_encoding` - The encoding to use for the imported file. fn custom_import<'a>( &'a self, _custom_filename: &'a str, @@ -238,6 +347,12 @@ pub trait Script: std::fmt::Debug + std::any::Any { )) } + /// Imports data into this script. + /// + /// * `custom_filename` - The path of the file to import. + /// * `filename` - The path of the file to write the patched scripts. + /// * `encoding` - The encoding of the patched scripts. + /// * `output_encoding` - The encoding to use for the imported file. fn custom_import_filename( &self, custom_filename: &str, @@ -250,10 +365,12 @@ pub trait Script: std::fmt::Debug + std::any::Any { self.custom_import(custom_filename, Box::new(f), encoding, output_encoding) } + /// Returns true if this script is an archive. fn is_archive(&self) -> bool { false } + /// Returns an iterator over archive filenames. fn iter_archive_filename<'a>( &'a self, ) -> Result> + 'a>> { @@ -262,18 +379,24 @@ pub trait Script: std::fmt::Debug + std::any::Any { )) } + /// Returns an iterator over archive offsets. fn iter_archive_offset<'a>(&'a self) -> Result> + 'a>> { Err(anyhow::anyhow!( "This script type does not support iterating over archive offsets." )) } + /// Opens a file in the archive by its index. fn open_file<'a>(&'a self, _index: usize) -> Result> { Err(anyhow::anyhow!( "This script type does not support opening files." )) } + /// Opens a file in the archive by its name. + /// + /// * `name` - The name of the file to open. + /// * `ignore_case` - If true, the name comparison will be case-insensitive. fn open_file_by_name<'a>( &'a self, name: &str, @@ -292,6 +415,7 @@ pub trait Script: std::fmt::Debug + std::any::Any { )) } + /// Opens a file in the archive by its offset. fn open_file_by_offset<'a>(&'a self, offset: u64) -> Result> { for (i, off) in self.iter_archive_offset()?.enumerate() { if let Ok(off) = off { @@ -312,11 +436,13 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Returns true if this script type is an image. fn is_image(&self) -> bool { false } #[cfg(feature = "image")] + /// Exports the image data from this script. fn export_image(&self) -> Result { Err(anyhow::anyhow!( "This script type does not support to export image." @@ -324,6 +450,10 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Imports an image into this script. + /// + /// * `data` - The image data to import. + /// * `file` - A writer with seek capabilities to write the patched scripts. fn import_image<'a>(&'a self, _data: ImageData, _file: Box) -> Result<()> { Err(anyhow::anyhow!( "This script type does not support to import image." @@ -331,6 +461,10 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Imports an image into this script. + /// + /// * `data` - The image data to import. + /// * `filename` - The path of the file to write the patched scripts. fn import_image_filename(&self, data: ImageData, filename: &str) -> Result<()> { let f = std::fs::File::create(filename)?; let f = std::io::BufWriter::new(f); @@ -338,11 +472,13 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Returns true if this script is contains multiple images. fn is_multi_image(&self) -> bool { false } #[cfg(feature = "image")] + /// Exports multiple images from this script. fn export_multi_image<'a>( &'a self, ) -> Result> + 'a>> { @@ -352,6 +488,10 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Imports multiple images into this script. + /// + /// * `data` - A vector of image data with names to import. + /// * `file` - A writer with seek capabilities to write the patched scripts. fn import_multi_image<'a>( &'a self, _data: Vec, @@ -363,6 +503,10 @@ pub trait Script: std::fmt::Debug + std::any::Any { } #[cfg(feature = "image")] + /// Imports multiple images into this script. + /// + /// * `data` - A vector of image data with names to import. + /// * `filename` - The path of the file to write the patched scripts. fn import_multi_image_filename( &self, data: Vec, @@ -373,12 +517,16 @@ pub trait Script: std::fmt::Debug + std::any::Any { self.import_multi_image(data, Box::new(f)) } + /// Returns the extra information for this script. fn extra_info<'a>(&'a self) -> Option> { None } } +/// A trait for creating archives. pub trait Archive { + /// Creates a new file in the archive. fn new_file<'a>(&'a mut self, name: &str) -> Result>; + /// Writes the header of the archive. (Must be called after writing all files.) fn write_header(&mut self) -> Result<()>; } diff --git a/src/scripts/bgi/mod.rs b/src/scripts/bgi/mod.rs index 49ac4e0..b17af29 100644 --- a/src/scripts/bgi/mod.rs +++ b/src/scripts/bgi/mod.rs @@ -1,3 +1,4 @@ +//! Buriko General Interpreter / Ethornell Scripts #[cfg(feature = "bgi-arc")] pub mod archive; #[cfg(feature = "bgi-audio")] diff --git a/src/scripts/ex_hibit/rld.rs b/src/scripts/ex_hibit/rld.rs index b8b2367..32ded51 100644 --- a/src/scripts/ex_hibit/rld.rs +++ b/src/scripts/ex_hibit/rld.rs @@ -522,44 +522,6 @@ impl Script for RldScript { } } -pub fn load_xor_key(arg: &crate::args::Arg) -> Result> { - if let Some(key) = &arg.ex_hibit_rld_xor_key { - if key.starts_with("0x") { - return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); - } else { - return Ok(Some(u32::from_str_radix(key, 16)?)); - } - } - if let Some(file) = &arg.ex_hibit_rld_xor_key_file { - let key = std::fs::read_to_string(file)?.trim().to_string(); - if key.starts_with("0x") { - return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); - } else { - return Ok(Some(u32::from_str_radix(&key, 16)?)); - } - } - Ok(None) -} - -pub fn load_def_xor_key(arg: &crate::args::Arg) -> Result> { - if let Some(key) = &arg.ex_hibit_rld_def_xor_key { - if key.starts_with("0x") { - return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); - } else { - return Ok(Some(u32::from_str_radix(key, 16)?)); - } - } - if let Some(file) = &arg.ex_hibit_rld_def_xor_key_file { - let key = std::fs::read_to_string(file)?.trim().to_string(); - if key.starts_with("0x") { - return Ok(Some(u32::from_str_radix(&key[2..], 16)?)); - } else { - return Ok(Some(u32::from_str_radix(&key, 16)?)); - } - } - Ok(None) -} - pub fn load_keys(path: Option<&String>) -> Result>> { if let Some(path) = path { let f = crate::utils::files::read_file(path)?; diff --git a/src/scripts/mod.rs b/src/scripts/mod.rs index 5a1ce98..c89ad2f 100644 --- a/src/scripts/mod.rs +++ b/src/scripts/mod.rs @@ -1,3 +1,4 @@ +//! Module for various script formats and builders. #[cfg(feature = "artemis")] pub mod artemis; pub mod base; @@ -23,6 +24,7 @@ pub mod yaneurao; pub use base::{Script, ScriptBuilder}; lazy_static::lazy_static! { + /// A list of all script builders. pub static ref BUILDER: Vec> = vec![ #[cfg(feature = "circus")] Box::new(circus::script::CircusMesScriptBuilder::new()), @@ -101,8 +103,10 @@ lazy_static::lazy_static! { #[cfg(feature = "bgi-audio")] Box::new(bgi::audio::audio::BgiAudioBuilder::new()), ]; + /// A list of all script extensions. pub static ref ALL_EXTS: Vec = BUILDER.iter().flat_map(|b| b.extensions()).map(|s| s.to_string()).collect(); + /// A list of all script extensions that are archives. pub static ref ARCHIVE_EXTS: Vec = BUILDER.iter().filter(|b| b.is_archive()).flat_map(|b| b.extensions()).map(|s| s.to_string()).collect(); }