aboutsummaryrefslogtreecommitdiff
path: root/crates/rsli/src/compress
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-22 12:12:27 +0300
committerValentin Popov <valentin@popov.link>2026-06-22 12:13:32 +0300
commitd0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448 (patch)
treea0bd35c3940be62a5b5de1acc2366af377ffd181 /crates/rsli/src/compress
parent7416fdc7e9a48837fff5056e6dc8d0774e90964b (diff)
downloadfparkan-d0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448.tar.xz
fparkan-d0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448.zip
feat: implement FParkan architecture foundation
Add the modular fparkan workspace, domain crates, adapters, apps, xtask policy/CI, acceptance evidence, and licensed corpus gates for the macOS-focused roadmap foundation.
Diffstat (limited to 'crates/rsli/src/compress')
-rw-r--r--crates/rsli/src/compress/deflate.rs14
-rw-r--r--crates/rsli/src/compress/lzh.rs303
-rw-r--r--crates/rsli/src/compress/lzss.rs79
-rw-r--r--crates/rsli/src/compress/mod.rs9
-rw-r--r--crates/rsli/src/compress/xor.rs29
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()
-}