diff options
| author | Valentin Popov <valentin@popov.link> | 2026-06-22 12:12:27 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-06-22 12:13:32 +0300 |
| commit | d0bdbaa1ed76dfbf3211bb43eee48c49cc4fd448 (patch) | |
| tree | a0bd35c3940be62a5b5de1acc2366af377ffd181 /crates/rsli/src/compress/lzh.rs | |
| parent | 7416fdc7e9a48837fff5056e6dc8d0774e90964b (diff) | |
| download | fparkan-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/lzh.rs')
| -rw-r--r-- | crates/rsli/src/compress/lzh.rs | 303 |
1 files changed, 0 insertions, 303 deletions
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) - } -} |
