- Added `lzss_decompress_simple` function for LZSS decompression in `lzss.rs`. - Introduced `XorState` struct and `xor_stream` function for XOR decryption in `xor.rs`. - Updated `mod.rs` to include new LZSS and XOR modules. - Refactored `parse_library` function in `parse.rs` to utilize the new XOR decryption functionality. - Cleaned up and organized code in `lib.rs` by removing redundant functions and structures. - Added tests for new functionality in `tests.rs`.
80 lines
2.4 KiB
Rust
80 lines
2.4 KiB
Rust
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)
|
|
}
|