diff options
Diffstat (limited to 'crates/rsli/src/compress')
| -rw-r--r-- | crates/rsli/src/compress/deflate.rs | 14 | ||||
| -rw-r--r-- | crates/rsli/src/compress/lzh.rs | 303 | ||||
| -rw-r--r-- | crates/rsli/src/compress/lzss.rs | 79 | ||||
| -rw-r--r-- | crates/rsli/src/compress/mod.rs | 9 | ||||
| -rw-r--r-- | crates/rsli/src/compress/xor.rs | 29 |
5 files changed, 0 insertions, 434 deletions
diff --git a/crates/rsli/src/compress/deflate.rs b/crates/rsli/src/compress/deflate.rs deleted file mode 100644 index 6b8ea73..0000000 --- a/crates/rsli/src/compress/deflate.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::error::Error; -use crate::Result; -use flate2::read::DeflateDecoder; -use std::io::Read; - -/// Decode raw Deflate (RFC 1951) payload. -pub fn decode_deflate(packed: &[u8]) -> Result<Vec<u8>> { - let mut out = Vec::new(); - let mut decoder = DeflateDecoder::new(packed); - decoder - .read_to_end(&mut out) - .map_err(|_| Error::DecompressionFailed("deflate"))?; - Ok(out) -} diff --git a/crates/rsli/src/compress/lzh.rs b/crates/rsli/src/compress/lzh.rs deleted file mode 100644 index 9486c50..0000000 --- a/crates/rsli/src/compress/lzh.rs +++ /dev/null @@ -1,303 +0,0 @@ -use super::xor::XorState; -use crate::error::Error; -use crate::Result; - -pub(crate) const LZH_N: usize = 4096; -pub(crate) const LZH_F: usize = 60; -pub(crate) const LZH_THRESHOLD: usize = 2; -pub(crate) const LZH_N_CHAR: usize = 256 - LZH_THRESHOLD + LZH_F; -pub(crate) const LZH_T: usize = LZH_N_CHAR * 2 - 1; -pub(crate) const LZH_R: usize = LZH_T - 1; -pub(crate) const LZH_MAX_FREQ: u16 = 0x8000; - -/// LZSS-Huffman decompression with optional on-the-fly XOR decryption. -pub fn lzss_huffman_decompress( - data: &[u8], - expected_size: usize, - xor_key: Option<u16>, -) -> Result<Vec<u8>> { - let mut decoder = LzhDecoder::new(data, xor_key); - decoder.decode(expected_size) -} - -struct LzhDecoder<'a> { - bit_reader: BitReader<'a>, - text: [u8; LZH_N], - freq: [u16; LZH_T + 1], - parent: [usize; LZH_T + LZH_N_CHAR], - son: [usize; LZH_T], - d_code: [u8; 256], - d_len: [u8; 256], - ring_pos: usize, -} - -impl<'a> LzhDecoder<'a> { - fn new(data: &'a [u8], xor_key: Option<u16>) -> Self { - let mut decoder = Self { - bit_reader: BitReader::new(data, xor_key), - text: [0x20u8; LZH_N], - freq: [0u16; LZH_T + 1], - parent: [0usize; LZH_T + LZH_N_CHAR], - son: [0usize; LZH_T], - d_code: [0u8; 256], - d_len: [0u8; 256], - ring_pos: LZH_N - LZH_F, - }; - decoder.init_tables(); - decoder.start_huff(); - decoder - } - - fn decode(&mut self, expected_size: usize) -> Result<Vec<u8>> { - let mut out = Vec::with_capacity(expected_size); - - while out.len() < expected_size { - let c = self.decode_char()?; - if c < 256 { - let byte = c as u8; - out.push(byte); - self.text[self.ring_pos] = byte; - self.ring_pos = (self.ring_pos + 1) & (LZH_N - 1); - } else { - let mut offset = self.decode_position()?; - offset = (self.ring_pos.wrapping_sub(offset).wrapping_sub(1)) & (LZH_N - 1); - let mut length = c.saturating_sub(253); - - while length > 0 && out.len() < expected_size { - let byte = self.text[offset]; - out.push(byte); - self.text[self.ring_pos] = byte; - self.ring_pos = (self.ring_pos + 1) & (LZH_N - 1); - offset = (offset + 1) & (LZH_N - 1); - length -= 1; - } - } - } - - if out.len() != expected_size { - return Err(Error::DecompressionFailed("lzss-huffman")); - } - Ok(out) - } - - fn init_tables(&mut self) { - let d_code_group_counts = [1usize, 3, 8, 12, 24, 16]; - let d_len_group_counts = [32usize, 48, 64, 48, 48, 16]; - - let mut group_index = 0u8; - let mut idx = 0usize; - let mut run = 32usize; - for count in d_code_group_counts { - for _ in 0..count { - for _ in 0..run { - self.d_code[idx] = group_index; - idx += 1; - } - group_index = group_index.wrapping_add(1); - } - run >>= 1; - } - - let mut len = 3u8; - idx = 0; - for count in d_len_group_counts { - for _ in 0..count { - self.d_len[idx] = len; - idx += 1; - } - len = len.saturating_add(1); - } - } - - fn start_huff(&mut self) { - for i in 0..LZH_N_CHAR { - self.freq[i] = 1; - self.son[i] = i + LZH_T; - self.parent[i + LZH_T] = i; - } - - let mut i = 0usize; - let mut j = LZH_N_CHAR; - while j <= LZH_R { - self.freq[j] = self.freq[i].saturating_add(self.freq[i + 1]); - self.son[j] = i; - self.parent[i] = j; - self.parent[i + 1] = j; - i += 2; - j += 1; - } - - self.freq[LZH_T] = u16::MAX; - self.parent[LZH_R] = 0; - } - - fn decode_char(&mut self) -> Result<usize> { - let mut node = self.son[LZH_R]; - while node < LZH_T { - let bit = usize::from(self.bit_reader.read_bit()?); - let branch = node - .checked_add(bit) - .ok_or(Error::DecompressionFailed("lzss-huffman tree overflow"))?; - node = *self.son.get(branch).ok_or(Error::DecompressionFailed( - "lzss-huffman tree out of bounds", - ))?; - } - - let c = node - LZH_T; - self.update(c); - Ok(c) - } - - fn decode_position(&mut self) -> Result<usize> { - let i = self.bit_reader.read_bits(8)? as usize; - let mut c = usize::from(self.d_code[i]) << 6; - let mut j = usize::from(self.d_len[i]).saturating_sub(2); - - while j > 0 { - j -= 1; - c |= usize::from(self.bit_reader.read_bit()?) << j; - } - - Ok(c | (i & 0x3F)) - } - - fn update(&mut self, c: usize) { - if self.freq[LZH_R] == LZH_MAX_FREQ { - self.reconstruct(); - } - - let mut current = self.parent[c + LZH_T]; - loop { - self.freq[current] = self.freq[current].saturating_add(1); - let freq = self.freq[current]; - - if current + 1 < self.freq.len() && freq > self.freq[current + 1] { - let mut swap_idx = current + 1; - while swap_idx + 1 < self.freq.len() && freq > self.freq[swap_idx + 1] { - swap_idx += 1; - } - - self.freq.swap(current, swap_idx); - - let left = self.son[current]; - let right = self.son[swap_idx]; - self.son[current] = right; - self.son[swap_idx] = left; - - self.parent[left] = swap_idx; - if left < LZH_T { - self.parent[left + 1] = swap_idx; - } - - self.parent[right] = current; - if right < LZH_T { - self.parent[right + 1] = current; - } - - current = swap_idx; - } - - current = self.parent[current]; - if current == 0 { - break; - } - } - } - - fn reconstruct(&mut self) { - let mut j = 0usize; - for i in 0..LZH_T { - if self.son[i] >= LZH_T { - self.freq[j] = (self.freq[i].saturating_add(1)) / 2; - self.son[j] = self.son[i]; - j += 1; - } - } - - let mut i = 0usize; - let mut current = LZH_N_CHAR; - while current < LZH_T { - let sum = self.freq[i].saturating_add(self.freq[i + 1]); - self.freq[current] = sum; - - let mut insert_at = current; - while insert_at > 0 && sum < self.freq[insert_at - 1] { - insert_at -= 1; - } - - for move_idx in (insert_at..current).rev() { - self.freq[move_idx + 1] = self.freq[move_idx]; - self.son[move_idx + 1] = self.son[move_idx]; - } - - self.freq[insert_at] = sum; - self.son[insert_at] = i; - - i += 2; - current += 1; - } - - for idx in 0..LZH_T { - let node = self.son[idx]; - self.parent[node] = idx; - if node < LZH_T { - self.parent[node + 1] = idx; - } - } - - self.freq[LZH_T] = u16::MAX; - self.parent[LZH_R] = 0; - } -} - -struct BitReader<'a> { - data: &'a [u8], - byte_pos: usize, - bit_mask: u8, - current_byte: u8, - xor_state: Option<XorState>, -} - -impl<'a> BitReader<'a> { - fn new(data: &'a [u8], xor_key: Option<u16>) -> Self { - Self { - data, - byte_pos: 0, - bit_mask: 0x80, - current_byte: 0, - xor_state: xor_key.map(XorState::new), - } - } - - fn read_bit(&mut self) -> Result<u8> { - if self.bit_mask == 0x80 { - let Some(mut byte) = self.data.get(self.byte_pos).copied() else { - return Err(Error::DecompressionFailed("lzss-huffman: unexpected EOF")); - }; - if let Some(state) = &mut self.xor_state { - byte = state.decrypt_byte(byte); - } - self.current_byte = byte; - } - - let bit = if (self.current_byte & self.bit_mask) != 0 { - 1 - } else { - 0 - }; - self.bit_mask >>= 1; - if self.bit_mask == 0 { - self.bit_mask = 0x80; - self.byte_pos = self.byte_pos.saturating_add(1); - } - Ok(bit) - } - - fn read_bits(&mut self, bits: usize) -> Result<u32> { - let mut value = 0u32; - for _ in 0..bits { - value = (value << 1) | u32::from(self.read_bit()?); - } - Ok(value) - } -} diff --git a/crates/rsli/src/compress/lzss.rs b/crates/rsli/src/compress/lzss.rs deleted file mode 100644 index d30345c..0000000 --- a/crates/rsli/src/compress/lzss.rs +++ /dev/null @@ -1,79 +0,0 @@ -use super::xor::XorState; -use crate::error::Error; -use crate::Result; - -/// Simple LZSS decompression with optional on-the-fly XOR decryption -pub fn lzss_decompress_simple( - data: &[u8], - expected_size: usize, - xor_key: Option<u16>, -) -> Result<Vec<u8>> { - let mut ring = [0x20u8; 0x1000]; - let mut ring_pos = 0xFEEusize; - let mut out = Vec::with_capacity(expected_size); - let mut in_pos = 0usize; - - let mut control = 0u8; - let mut bits_left = 0u8; - - // XOR state for on-the-fly decryption - let mut xor_state = xor_key.map(XorState::new); - - // Helper to read byte with optional XOR decryption - let read_byte = |pos: usize, state: &mut Option<XorState>| -> Option<u8> { - let encrypted = data.get(pos).copied()?; - Some(if let Some(ref mut s) = state { - s.decrypt_byte(encrypted) - } else { - encrypted - }) - }; - - while out.len() < expected_size { - if bits_left == 0 { - let byte = read_byte(in_pos, &mut xor_state) - .ok_or(Error::DecompressionFailed("lzss-simple: unexpected EOF"))?; - control = byte; - in_pos += 1; - bits_left = 8; - } - - if (control & 1) != 0 { - let byte = read_byte(in_pos, &mut xor_state) - .ok_or(Error::DecompressionFailed("lzss-simple: unexpected EOF"))?; - in_pos += 1; - - out.push(byte); - ring[ring_pos] = byte; - ring_pos = (ring_pos + 1) & 0x0FFF; - } else { - let low = read_byte(in_pos, &mut xor_state) - .ok_or(Error::DecompressionFailed("lzss-simple: unexpected EOF"))?; - let high = read_byte(in_pos + 1, &mut xor_state) - .ok_or(Error::DecompressionFailed("lzss-simple: unexpected EOF"))?; - in_pos += 2; - - let offset = usize::from(low) | (usize::from(high & 0xF0) << 4); - let length = usize::from((high & 0x0F) + 3); - - for step in 0..length { - let byte = ring[(offset + step) & 0x0FFF]; - out.push(byte); - ring[ring_pos] = byte; - ring_pos = (ring_pos + 1) & 0x0FFF; - if out.len() >= expected_size { - break; - } - } - } - - control >>= 1; - bits_left -= 1; - } - - if out.len() != expected_size { - return Err(Error::DecompressionFailed("lzss-simple")); - } - - Ok(out) -} diff --git a/crates/rsli/src/compress/mod.rs b/crates/rsli/src/compress/mod.rs deleted file mode 100644 index bd23143..0000000 --- a/crates/rsli/src/compress/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub mod deflate; -pub mod lzh; -pub mod lzss; -pub mod xor; - -pub use deflate::decode_deflate; -pub use lzh::lzss_huffman_decompress; -pub use lzss::lzss_decompress_simple; -pub use xor::{xor_stream, XorState}; diff --git a/crates/rsli/src/compress/xor.rs b/crates/rsli/src/compress/xor.rs deleted file mode 100644 index c4c3d7d..0000000 --- a/crates/rsli/src/compress/xor.rs +++ /dev/null @@ -1,29 +0,0 @@ -/// XOR cipher state for RsLi format -pub struct XorState { - lo: u8, - hi: u8, -} - -impl XorState { - /// Create new XOR state from 16-bit key - pub fn new(key16: u16) -> Self { - Self { - lo: (key16 & 0xFF) as u8, - hi: ((key16 >> 8) & 0xFF) as u8, - } - } - - /// Decrypt a single byte and update state - pub fn decrypt_byte(&mut self, encrypted: u8) -> u8 { - self.lo = self.hi ^ self.lo.wrapping_shl(1); - let decrypted = encrypted ^ self.lo; - self.hi = self.lo ^ (self.hi >> 1); - decrypted - } -} - -/// Decrypt entire buffer with XOR stream cipher -pub fn xor_stream(data: &[u8], key16: u16) -> Vec<u8> { - let mut state = XorState::new(key16); - data.iter().map(|&b| state.decrypt_byte(b)).collect() -} |
