use crate::raw::codec::bits::{BitReader, BitWriter};
use crate::raw::codec::huffman::{HUFFMAN_CODES, HUFFMAN_TREE, HuffmanNode};
use crate::raw::error::SdmpError;
#[must_use]
pub fn encode(input: &str) -> Vec<u8> {
let codes = &*HUFFMAN_CODES;
let mut writer = BitWriter::new();
for c in input.chars() {
if let Some(&(code, length)) = codes.get(&c) {
writer.write_bits(code, length);
} else {
writer.write_bits(0xFF, 8);
let codepoint = c as u32;
writer.write_bits(u64::from(codepoint), 24);
}
}
let padding = writer.padding_bits();
let mut output = vec![padding];
output.extend(writer.finish());
output
}
pub fn decode(input: &[u8]) -> Result<String, SdmpError> {
if input.is_empty() {
return Ok(String::new());
}
let padding = input[0];
let data = &input[1..];
if data.is_empty() {
return Ok(String::new());
}
let mut reader = BitReader::new(data, padding);
let mut output = String::new();
let tree = &*HUFFMAN_TREE;
let mut node = tree;
loop {
match reader.read_bit() {
None => break,
Some(bit) => {
match node {
HuffmanNode::Internal { left, right, .. } => {
node = if bit == 0 { left } else { right };
}
HuffmanNode::Leaf { .. } => unreachable!(),
}
if let HuffmanNode::Leaf { ch, .. } = node {
if *ch as u32 == 0xFF {
let mut codepoint = 0u32;
for _ in 0..24 {
match reader.read_bit() {
Some(b) => codepoint = (codepoint << 1) | u32::from(b),
None => return Err(SdmpError::UnexpectedEof),
}
}
match char::from_u32(codepoint) {
Some(c) => output.push(c),
None => return Err(SdmpError::InvalidUtf8),
}
} else {
output.push(*ch);
}
node = tree;
}
}
}
}
Ok(output)
}