use crate::block::literals::LiteralsSection;
use crate::fse::{BitReader, FseDecoder, FseTable};
use haagenti_core::{Error, Result};
type ParseTableResult = Result<(Option<(FseTable, usize)>, Option<u8>)>;
const MAX_LL_SYMBOL: u8 = 35; const MAX_OF_SYMBOL: u8 = 31; const MAX_ML_SYMBOL: u8 = 52;
#[derive(Debug, Clone, Copy)]
struct RepeatOffsets {
offsets: [u32; 3],
}
impl RepeatOffsets {
fn new() -> Self {
Self { offsets: [1, 4, 8] }
}
fn resolve(&mut self, offset_value: u32, literal_length: u32) -> u32 {
if offset_value == 0 {
1
} else if offset_value <= 3 {
if literal_length == 0 {
match offset_value {
1 => {
let offset = self.offsets[1];
self.offsets.swap(0, 1);
offset
}
2 => {
let offset = self.offsets[2];
let temp = self.offsets[2];
self.offsets[2] = self.offsets[1];
self.offsets[1] = self.offsets[0];
self.offsets[0] = temp;
offset
}
3 => {
let offset = self.offsets[0].saturating_sub(1).max(1);
self.offsets[2] = self.offsets[1];
self.offsets[1] = self.offsets[0];
self.offsets[0] = offset;
offset
}
_ => unreachable!(),
}
} else {
let idx = (offset_value - 1) as usize;
let offset = self.offsets[idx];
if idx > 0 {
let temp = self.offsets[idx];
for i in (1..=idx).rev() {
self.offsets[i] = self.offsets[i - 1];
}
self.offsets[0] = temp;
}
offset
}
} else {
let offset = offset_value - 3;
self.offsets[2] = self.offsets[1];
self.offsets[1] = self.offsets[0];
self.offsets[0] = offset;
offset
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Sequence {
pub literal_length: u32,
pub offset: u32,
pub match_length: u32,
}
impl Sequence {
pub fn new(literal_length: u32, offset: u32, match_length: u32) -> Self {
Self {
literal_length,
offset,
match_length,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SymbolMode {
Predefined,
Rle,
Fse,
Repeat,
}
impl SymbolMode {
pub fn from_field(field: u8) -> Self {
match field {
0 => SymbolMode::Predefined,
1 => SymbolMode::Rle,
2 => SymbolMode::Fse,
3 => SymbolMode::Repeat,
_ => unreachable!(),
}
}
}
#[derive(Debug, Clone)]
pub struct SequencesSection {
pub num_sequences: usize,
pub sequences: Vec<Sequence>,
}
impl SequencesSection {
pub fn parse(input: &[u8], _literals: &LiteralsSection) -> Result<Self> {
if input.is_empty() {
return Ok(Self {
num_sequences: 0,
sequences: Vec::new(),
});
}
let (num_sequences, count_header_size) = Self::parse_sequence_count(input)?;
if num_sequences == 0 {
return Ok(Self {
num_sequences: 0,
sequences: Vec::new(),
});
}
if input.len() < count_header_size + 1 {
return Err(Error::corrupted("Sequences section truncated"));
}
let mode_byte = input[count_header_size];
let ll_mode = SymbolMode::from_field(mode_byte & 0x03);
let of_mode = SymbolMode::from_field((mode_byte >> 2) & 0x03);
let ml_mode = SymbolMode::from_field((mode_byte >> 4) & 0x03);
let mut pos = count_header_size + 1;
if ll_mode == SymbolMode::Rle && of_mode == SymbolMode::Rle && ml_mode == SymbolMode::Rle {
if input.len() < pos + 3 {
return Err(Error::corrupted("RLE sequence symbols truncated"));
}
let ll_sym = input[pos];
let of_sym = input[pos + 1];
let ml_sym = input[pos + 2];
pos += 3;
return Self::decode_rle_sequences(
&input[pos..],
num_sequences,
ll_sym,
of_sym,
ml_sym,
);
}
let (ll_table, ll_rle_sym) = Self::parse_table_for_mode(
ll_mode,
&input[pos..],
MAX_LL_SYMBOL,
"Literal Length",
&PREDEFINED_LL_DISTRIBUTION,
PREDEFINED_LL_ACCURACY_LOG,
)?;
pos += ll_table.as_ref().map_or(0, |(_, consumed)| *consumed);
let (of_table, of_rle_sym) = Self::parse_table_for_mode(
of_mode,
&input[pos..],
MAX_OF_SYMBOL,
"Offset",
&PREDEFINED_OF_DISTRIBUTION,
PREDEFINED_OF_ACCURACY_LOG,
)?;
pos += of_table.as_ref().map_or(0, |(_, consumed)| *consumed);
let (ml_table, ml_rle_sym) = Self::parse_table_for_mode(
ml_mode,
&input[pos..],
MAX_ML_SYMBOL,
"Match Length",
&PREDEFINED_ML_DISTRIBUTION,
PREDEFINED_ML_ACCURACY_LOG,
)?;
pos += ml_table.as_ref().map_or(0, |(_, consumed)| *consumed);
let has_rle = ll_rle_sym.is_some() || of_rle_sym.is_some() || ml_rle_sym.is_some();
let ll = ll_table
.map(|(t, _)| t)
.or_else(|| {
FseTable::from_predefined(&PREDEFINED_LL_DISTRIBUTION, PREDEFINED_LL_ACCURACY_LOG)
.ok()
})
.ok_or_else(|| Error::corrupted("Failed to build LL table"))?;
let of = of_table
.map(|(t, _)| t)
.or_else(|| {
FseTable::from_predefined(&PREDEFINED_OF_DISTRIBUTION, PREDEFINED_OF_ACCURACY_LOG)
.ok()
})
.ok_or_else(|| Error::corrupted("Failed to build OF table"))?;
let ml = ml_table
.map(|(t, _)| t)
.or_else(|| {
FseTable::from_predefined(&PREDEFINED_ML_DISTRIBUTION, PREDEFINED_ML_ACCURACY_LOG)
.ok()
})
.ok_or_else(|| Error::corrupted("Failed to build ML table"))?;
if has_rle {
return Self::decode_mixed_sequences(
&input[pos..],
num_sequences,
&ll,
ll_rle_sym,
&of,
of_rle_sym,
&ml,
ml_rle_sym,
);
}
let (ll_table, of_table, ml_table) = (ll, of, ml);
let bitstream_data = &input[pos..];
Self::decode_fse_sequences(
bitstream_data,
num_sequences,
&ll_table,
&of_table,
&ml_table,
)
}
fn decode_fse_sequences(
data: &[u8],
num_sequences: usize,
ll_table: &FseTable,
of_table: &FseTable,
ml_table: &FseTable,
) -> Result<Self> {
if data.is_empty() {
return Err(Error::corrupted("Empty sequence bitstream"));
}
let mut bits = BitReader::new(data);
bits.init_from_end()?;
let mut ll_decoder = FseDecoder::new(ll_table);
let mut of_decoder = FseDecoder::new(of_table);
let mut ml_decoder = FseDecoder::new(ml_table);
ll_decoder.init_state(&mut bits)?;
of_decoder.init_state(&mut bits)?;
ml_decoder.init_state(&mut bits)?;
bits.switch_to_lsb_mode()?;
let mut sequences = Vec::with_capacity(num_sequences);
let mut repeat_offsets = RepeatOffsets::new();
for i in 0..num_sequences {
let is_last = i == num_sequences - 1;
let ll_code = ll_decoder.peek_symbol();
let of_code = of_decoder.peek_symbol();
let _ml_code = ml_decoder.peek_symbol();
let ll_extra_bits = if ll_code < LITERAL_LENGTH_BASELINE.len() as u8 {
let (bits_needed, _) = LITERAL_LENGTH_BASELINE[ll_code as usize];
if bits_needed > 0 {
bits.read_bits(bits_needed as usize)?
} else {
0
}
} else {
0
};
let ml_seq_extra_bits = ml_decoder.peek_seq_extra_bits();
let ml_seq_base = ml_decoder.peek_seq_base();
let ml_extra_bits = if ml_seq_extra_bits > 0 {
bits.read_bits(ml_seq_extra_bits as usize)?
} else {
0
};
let of_num_bits = offset_code_extra_bits(of_code);
let of_extra_bits = if of_num_bits > 0 {
bits.read_bits(of_num_bits as usize)?
} else {
0
};
if !is_last {
ll_decoder.update_state(&mut bits)?;
ml_decoder.update_state(&mut bits)?;
of_decoder.update_state(&mut bits)?;
}
let literal_length = decode_literal_length(ll_code, ll_extra_bits);
let match_length = ml_seq_base + ml_extra_bits;
let offset_value = decode_offset(of_code, of_extra_bits);
let offset = repeat_offsets.resolve(offset_value, literal_length);
sequences.push(Sequence::new(literal_length, offset, match_length));
}
Ok(Self {
num_sequences,
sequences,
})
}
fn decode_rle_sequences(
data: &[u8],
num_sequences: usize,
ll_sym: u8,
of_sym: u8,
ml_sym: u8,
) -> Result<Self> {
if data.is_empty() && num_sequences > 0 {
return Err(Error::corrupted("Empty RLE sequence data"));
}
let mut bits = BitReader::new(data);
if !data.is_empty() {
bits.init_fse()?;
}
let mut sequences = Vec::with_capacity(num_sequences);
let mut repeat_offsets = RepeatOffsets::new();
for _ in 0..num_sequences {
let ll_extra_bits = if ll_sym < LITERAL_LENGTH_BASELINE.len() as u8 {
let (bits_needed, _) = LITERAL_LENGTH_BASELINE[ll_sym as usize];
if bits_needed > 0 {
bits.read_bits(bits_needed as usize)?
} else {
0
}
} else {
0
};
let ml_extra_bits = if ml_sym < MATCH_LENGTH_BASELINE.len() as u8 {
let (bits_needed, _) = MATCH_LENGTH_BASELINE[ml_sym as usize];
if bits_needed > 0 {
bits.read_bits(bits_needed as usize)?
} else {
0
}
} else {
0
};
let of_num_bits = offset_code_extra_bits(of_sym);
let of_extra_bits = if of_num_bits > 0 {
bits.read_bits(of_num_bits as usize)?
} else {
0
};
let literal_length = decode_literal_length(ll_sym, ll_extra_bits);
let match_length = decode_match_length(ml_sym, ml_extra_bits);
let offset_value = decode_offset(of_sym, of_extra_bits);
let offset = repeat_offsets.resolve(offset_value, literal_length);
sequences.push(Sequence::new(literal_length, offset, match_length));
}
Ok(Self {
num_sequences,
sequences,
})
}
fn parse_table_for_mode(
mode: SymbolMode,
data: &[u8],
max_symbol: u8,
name: &str,
predefined_dist: &[i16],
predefined_log: u8,
) -> ParseTableResult {
match mode {
SymbolMode::Predefined => {
let table = FseTable::from_predefined(predefined_dist, predefined_log)?;
Ok((Some((table, 0)), None))
}
SymbolMode::Rle => {
if data.is_empty() {
return Err(Error::corrupted(format!("{} RLE symbol missing", name)));
}
Ok((
Some((
FseTable::from_predefined(predefined_dist, predefined_log)?,
1,
)),
Some(data[0]),
))
}
SymbolMode::Fse => {
let (table, consumed) = FseTable::parse(data, max_symbol)?;
Ok((Some((table, consumed)), None))
}
SymbolMode::Repeat => {
Err(Error::Unsupported(format!(
"{} Repeat mode not yet implemented",
name
)))
}
}
}
#[allow(clippy::too_many_arguments)]
fn decode_mixed_sequences(
data: &[u8],
num_sequences: usize,
ll_table: &FseTable,
ll_rle: Option<u8>,
of_table: &FseTable,
of_rle: Option<u8>,
ml_table: &FseTable,
ml_rle: Option<u8>,
) -> Result<Self> {
if data.is_empty() && num_sequences > 0 {
return Err(Error::corrupted("Empty mixed sequence data"));
}
let mut bits = BitReader::new(data);
if !data.is_empty() {
bits.init_from_end()?;
}
let mut ll_decoder = if ll_rle.is_none() {
let mut d = FseDecoder::new(ll_table);
d.init_state(&mut bits)?;
Some(d)
} else {
None
};
let mut of_decoder = if of_rle.is_none() {
let mut d = FseDecoder::new(of_table);
d.init_state(&mut bits)?;
Some(d)
} else {
None
};
let mut ml_decoder = if ml_rle.is_none() {
let mut d = FseDecoder::new(ml_table);
d.init_state(&mut bits)?;
Some(d)
} else {
None
};
bits.switch_to_lsb_mode()?;
let mut sequences = Vec::with_capacity(num_sequences);
let mut repeat_offsets = RepeatOffsets::new();
for _ in 0..num_sequences {
let of_code = if let Some(ref mut dec) = of_decoder {
dec.peek_symbol()
} else {
of_rle.unwrap()
};
let ml_code = if let Some(ref mut dec) = ml_decoder {
dec.decode_symbol(&mut bits)?
} else {
ml_rle.unwrap()
};
let ll_code = if let Some(ref mut dec) = ll_decoder {
dec.decode_symbol(&mut bits)?
} else {
ll_rle.unwrap()
};
let ll_extra_bits = if ll_code < LITERAL_LENGTH_BASELINE.len() as u8 {
let (bits_needed, _) = LITERAL_LENGTH_BASELINE[ll_code as usize];
if bits_needed > 0 {
bits.read_bits(bits_needed as usize)?
} else {
0
}
} else {
0
};
let ml_extra_bits = if ml_code < MATCH_LENGTH_BASELINE.len() as u8 {
let (bits_needed, _) = MATCH_LENGTH_BASELINE[ml_code as usize];
if bits_needed > 0 {
bits.read_bits(bits_needed as usize)?
} else {
0
}
} else {
0
};
let of_num_bits = offset_code_extra_bits(of_code);
let of_extra_bits = if of_num_bits > 0 {
bits.read_bits(of_num_bits as usize)?
} else {
0
};
let literal_length = decode_literal_length(ll_code, ll_extra_bits);
let match_length = decode_match_length(ml_code, ml_extra_bits);
let offset_value = decode_offset(of_code, of_extra_bits);
let offset = repeat_offsets.resolve(offset_value, literal_length);
sequences.push(Sequence::new(literal_length, offset, match_length));
}
Ok(Self {
num_sequences,
sequences,
})
}
fn parse_sequence_count(input: &[u8]) -> Result<(usize, usize)> {
if input.is_empty() {
return Err(Error::corrupted("Empty sequences header"));
}
let byte0 = input[0] as usize;
if byte0 == 0 {
Ok((0, 1))
} else if byte0 < 128 {
Ok((byte0, 1))
} else if byte0 < 255 {
if input.len() < 2 {
return Err(Error::corrupted("Sequences count truncated"));
}
let count = ((byte0 - 128) << 8) + (input[1] as usize);
Ok((count, 2))
} else {
if input.len() < 3 {
return Err(Error::corrupted("Sequences count truncated"));
}
let count = (input[1] as usize) + ((input[2] as usize) << 8) + 0x7F00;
Ok((count, 3))
}
}
}
pub const PREDEFINED_LL_DISTRIBUTION: [i16; 36] = [
4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, -1, ];
pub const PREDEFINED_OF_DISTRIBUTION: [i16; 29] = [
1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, ];
pub const PREDEFINED_ML_DISTRIBUTION: [i16; 53] = [
1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, ];
pub const PREDEFINED_LL_ACCURACY_LOG: u8 = 6;
pub const PREDEFINED_OF_ACCURACY_LOG: u8 = 5;
pub const PREDEFINED_ML_ACCURACY_LOG: u8 = 6;
pub const LITERAL_LENGTH_BASELINE: [(u8, u32); 36] = [
(0, 0),
(0, 1),
(0, 2),
(0, 3),
(0, 4),
(0, 5),
(0, 6),
(0, 7),
(0, 8),
(0, 9),
(0, 10),
(0, 11),
(0, 12),
(0, 13),
(0, 14),
(0, 15),
(1, 16),
(1, 18),
(1, 20),
(1, 22),
(2, 24),
(2, 28),
(3, 32),
(3, 40),
(4, 48),
(6, 64),
(7, 128),
(8, 256),
(9, 512),
(10, 1024),
(11, 2048),
(12, 4096),
(13, 8192),
(14, 16384),
(15, 32768),
(16, 65536),
];
pub const MATCH_LENGTH_BASELINE: [(u8, u32); 53] = [
(0, 3),
(0, 4),
(0, 5),
(0, 6),
(0, 7),
(0, 8),
(0, 9),
(0, 10),
(0, 11),
(0, 12),
(0, 13),
(0, 14),
(0, 15),
(0, 16),
(0, 17),
(0, 18),
(0, 19),
(0, 20),
(0, 21),
(0, 22),
(0, 23),
(0, 24),
(0, 25),
(0, 26),
(0, 27),
(0, 28),
(0, 29),
(0, 30),
(0, 31),
(0, 32),
(0, 33),
(0, 34),
(1, 35),
(1, 37),
(1, 39),
(1, 41),
(2, 43),
(2, 47),
(3, 51),
(3, 59),
(4, 67),
(4, 83),
(5, 99),
(7, 131),
(8, 259),
(9, 515),
(10, 1027),
(11, 2051),
(12, 4099),
(13, 8195),
(14, 16387),
(15, 32771),
(16, 65539),
];
pub fn decode_literal_length(code: u8, extra_bits: u32) -> u32 {
if code as usize >= LITERAL_LENGTH_BASELINE.len() {
return 0;
}
let (bits, baseline) = LITERAL_LENGTH_BASELINE[code as usize];
if bits == 0 {
baseline
} else {
baseline + (extra_bits & ((1 << bits) - 1))
}
}
pub fn decode_match_length(code: u8, extra_bits: u32) -> u32 {
if code as usize >= MATCH_LENGTH_BASELINE.len() {
return 3; }
let (bits, baseline) = MATCH_LENGTH_BASELINE[code as usize];
if bits == 0 {
baseline
} else {
baseline + (extra_bits & ((1 << bits) - 1))
}
}
pub fn decode_offset(code: u8, extra_bits: u32) -> u32 {
let code = code.min(31); (1u32 << code) + extra_bits
}
pub fn offset_code_extra_bits(code: u8) -> u8 {
code.min(31)
}
#[cfg(test)]
fn build_predefined_tables() -> Result<(FseTable, FseTable, FseTable)> {
let ll_table = FseTable::build(
&PREDEFINED_LL_DISTRIBUTION,
PREDEFINED_LL_ACCURACY_LOG,
PREDEFINED_LL_DISTRIBUTION.len() as u8,
)?;
let of_table = FseTable::build(
&PREDEFINED_OF_DISTRIBUTION,
PREDEFINED_OF_ACCURACY_LOG,
PREDEFINED_OF_DISTRIBUTION.len() as u8,
)?;
let ml_table = FseTable::build(
&PREDEFINED_ML_DISTRIBUTION,
PREDEFINED_ML_ACCURACY_LOG,
PREDEFINED_ML_DISTRIBUTION.len() as u8,
)?;
Ok((ll_table, of_table, ml_table))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sequence_creation() {
let seq = Sequence::new(10, 5, 20);
assert_eq!(seq.literal_length, 10);
assert_eq!(seq.offset, 5);
assert_eq!(seq.match_length, 20);
}
#[test]
fn test_symbol_mode_parsing() {
assert_eq!(SymbolMode::from_field(0), SymbolMode::Predefined);
assert_eq!(SymbolMode::from_field(1), SymbolMode::Rle);
assert_eq!(SymbolMode::from_field(2), SymbolMode::Fse);
assert_eq!(SymbolMode::from_field(3), SymbolMode::Repeat);
}
#[test]
fn test_sequence_count_zero() {
let (count, size) = SequencesSection::parse_sequence_count(&[0]).unwrap();
assert_eq!(count, 0);
assert_eq!(size, 1);
}
#[test]
fn test_sequence_count_small() {
let (count, size) = SequencesSection::parse_sequence_count(&[50]).unwrap();
assert_eq!(count, 50);
assert_eq!(size, 1);
}
#[test]
fn test_sequence_count_medium() {
let (count, size) = SequencesSection::parse_sequence_count(&[129, 44]).unwrap();
assert_eq!(count, 300);
assert_eq!(size, 2);
}
#[test]
fn test_sequence_count_large() {
let (count, size) = SequencesSection::parse_sequence_count(&[255, 0, 0]).unwrap();
assert_eq!(count, 0x7F00);
assert_eq!(size, 3);
let (count, size) = SequencesSection::parse_sequence_count(&[255, 0, 1]).unwrap();
assert_eq!(count, 0x8000);
assert_eq!(size, 3);
}
#[test]
fn test_literal_length_decoding() {
assert_eq!(decode_literal_length(0, 0), 0);
assert_eq!(decode_literal_length(15, 0), 15);
assert_eq!(decode_literal_length(16, 0), 16);
assert_eq!(decode_literal_length(16, 1), 17);
assert_eq!(decode_literal_length(20, 0), 24);
assert_eq!(decode_literal_length(20, 3), 27);
}
#[test]
fn test_match_length_decoding() {
assert_eq!(decode_match_length(0, 0), 3);
assert_eq!(decode_match_length(31, 0), 34);
assert_eq!(decode_match_length(32, 0), 35);
assert_eq!(decode_match_length(32, 1), 36);
}
#[test]
fn test_offset_decoding() {
assert_eq!(decode_offset(0, 0), 1);
assert_eq!(decode_offset(0, 1), 2);
assert_eq!(decode_offset(1, 0), 2);
assert_eq!(decode_offset(1, 1), 3);
assert_eq!(decode_offset(2, 0), 4);
assert_eq!(decode_offset(2, 3), 7);
assert_eq!(decode_offset(3, 0), 8);
assert_eq!(decode_offset(3, 7), 15);
assert_eq!(decode_offset(10, 0), 1024);
assert_eq!(decode_offset(10, 500), 1524);
}
#[test]
fn test_empty_sequences() {
let literals = LiteralsSection::new_raw(vec![]);
let result = SequencesSection::parse(&[], &literals);
assert!(result.is_ok());
let section = result.unwrap();
assert_eq!(section.num_sequences, 0);
assert!(section.sequences.is_empty());
}
#[test]
fn test_zero_sequences() {
let literals = LiteralsSection::new_raw(vec![]);
let result = SequencesSection::parse(&[0], &literals);
assert!(result.is_ok());
let section = result.unwrap();
assert_eq!(section.num_sequences, 0);
}
#[test]
fn test_predefined_tables_build() {
let result = build_predefined_tables();
assert!(result.is_ok(), "Build failed: {:?}", result.err());
let (ll_table, of_table, ml_table) = result.unwrap();
assert_eq!(ll_table.accuracy_log(), PREDEFINED_LL_ACCURACY_LOG);
assert_eq!(of_table.accuracy_log(), PREDEFINED_OF_ACCURACY_LOG);
assert_eq!(ml_table.accuracy_log(), PREDEFINED_ML_ACCURACY_LOG);
}
#[test]
fn test_predefined_ll_distribution_sum() {
let sum: i32 = PREDEFINED_LL_DISTRIBUTION
.iter()
.filter(|&&x| x > 0)
.map(|&x| x as i32)
.sum();
let less_than_one = PREDEFINED_LL_DISTRIBUTION
.iter()
.filter(|&&x| x == -1)
.count();
assert!(sum + less_than_one as i32 <= 64);
}
#[test]
fn test_predefined_of_distribution_sum() {
let sum: i32 = PREDEFINED_OF_DISTRIBUTION
.iter()
.filter(|&&x| x > 0)
.map(|&x| x as i32)
.sum();
let less_than_one = PREDEFINED_OF_DISTRIBUTION
.iter()
.filter(|&&x| x == -1)
.count();
assert!(sum + less_than_one as i32 <= 32);
}
#[test]
fn test_predefined_ml_distribution_sum() {
let sum: i32 = PREDEFINED_ML_DISTRIBUTION
.iter()
.filter(|&&x| x > 0)
.map(|&x| x as i32)
.sum();
let less_than_one = PREDEFINED_ML_DISTRIBUTION
.iter()
.filter(|&&x| x == -1)
.count();
assert!(sum + less_than_one as i32 <= 64);
}
#[test]
fn test_literal_length_baseline_all_codes() {
for code in 0..36u8 {
let (bits, baseline) = LITERAL_LENGTH_BASELINE[code as usize];
let result = decode_literal_length(code, 0);
assert_eq!(result, baseline, "Code {} failed", code);
if bits > 0 {
let max_extra = (1u32 << bits) - 1;
let result_max = decode_literal_length(code, max_extra);
assert_eq!(result_max, baseline + max_extra);
}
}
}
#[test]
fn test_match_length_baseline_all_codes() {
for code in 0..53u8 {
let (bits, baseline) = MATCH_LENGTH_BASELINE[code as usize];
let result = decode_match_length(code, 0);
assert_eq!(result, baseline, "Code {} failed", code);
if bits > 0 {
let max_extra = (1u32 << bits) - 1;
let result_max = decode_match_length(code, max_extra);
assert_eq!(result_max, baseline + max_extra);
}
}
}
#[test]
fn test_offset_decoding_range() {
for code in 0..=30u8 {
let base_offset = decode_offset(code, 0);
assert_eq!(base_offset, 1u32 << code, "Code {} failed", code);
}
assert_eq!(decode_offset(31, 0), 1u32 << 31);
}
#[test]
fn test_sequences_with_predefined_mode() {
let literals = LiteralsSection::new_raw(vec![]);
let mut data = vec![1]; data.push(0x00);
data.push(0x80);
let result = SequencesSection::parse(&data, &literals);
if result.is_err() {
} else {
let section = result.unwrap();
assert_eq!(section.num_sequences, 1);
}
}
#[test]
fn test_mode_byte_parsing() {
let mode_byte = 0x00u8;
assert_eq!(
SymbolMode::from_field((mode_byte >> 6) & 0x03),
SymbolMode::Predefined
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 4) & 0x03),
SymbolMode::Predefined
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 2) & 0x03),
SymbolMode::Predefined
);
let mode_byte = 0x54u8;
assert_eq!(
SymbolMode::from_field((mode_byte >> 6) & 0x03),
SymbolMode::Rle
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 4) & 0x03),
SymbolMode::Rle
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 2) & 0x03),
SymbolMode::Rle
);
let mode_byte = 0xA8u8;
assert_eq!(
SymbolMode::from_field((mode_byte >> 6) & 0x03),
SymbolMode::Fse
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 4) & 0x03),
SymbolMode::Fse
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 2) & 0x03),
SymbolMode::Fse
);
let mode_byte = 0xFCu8;
assert_eq!(
SymbolMode::from_field((mode_byte >> 6) & 0x03),
SymbolMode::Repeat
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 4) & 0x03),
SymbolMode::Repeat
);
assert_eq!(
SymbolMode::from_field((mode_byte >> 2) & 0x03),
SymbolMode::Repeat
);
}
#[test]
fn test_sequence_count_boundary_127() {
let (count, size) = SequencesSection::parse_sequence_count(&[127]).unwrap();
assert_eq!(count, 127);
assert_eq!(size, 1);
}
#[test]
fn test_sequence_count_boundary_128() {
let (count, size) = SequencesSection::parse_sequence_count(&[128, 128]).unwrap();
assert_eq!(count, 128);
assert_eq!(size, 2);
}
#[test]
fn test_repeat_offsets_initial_values() {
let offsets = RepeatOffsets::new();
assert_eq!(offsets.offsets, [1, 4, 8]);
}
#[test]
fn test_repeat_offsets_new_offset() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(7, 5); assert_eq!(result, 4); assert_eq!(offsets.offsets, [4, 1, 4]); }
#[test]
fn test_repeat_offsets_use_first() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(1, 5);
assert_eq!(result, 1); assert_eq!(offsets.offsets, [1, 4, 8]); }
#[test]
fn test_repeat_offsets_use_second() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(2, 5);
assert_eq!(result, 4); assert_eq!(offsets.offsets, [4, 1, 8]); }
#[test]
fn test_repeat_offsets_use_third() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(3, 5);
assert_eq!(result, 8); assert_eq!(offsets.offsets, [8, 1, 4]); }
#[test]
fn test_repeat_offsets_ll_zero_special_case_1() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(1, 0);
assert_eq!(result, 4); assert_eq!(offsets.offsets, [4, 1, 8]); }
#[test]
fn test_repeat_offsets_ll_zero_special_case_2() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(2, 0);
assert_eq!(result, 8); assert_eq!(offsets.offsets, [8, 1, 4]); }
#[test]
fn test_repeat_offsets_ll_zero_special_case_3() {
let mut offsets = RepeatOffsets::new();
let result = offsets.resolve(3, 0);
assert_eq!(result, 1); assert_eq!(offsets.offsets, [1, 1, 4]); }
#[test]
fn test_repeat_offsets_ll_zero_case_3_larger_offset() {
let mut offsets = RepeatOffsets::new();
offsets.resolve(13, 5); assert_eq!(offsets.offsets[0], 10);
let result = offsets.resolve(3, 0);
assert_eq!(result, 9);
assert_eq!(offsets.offsets[0], 9);
}
#[test]
fn test_repeat_offsets_sequence_of_operations() {
let mut offsets = RepeatOffsets::new();
offsets.resolve(106, 5);
assert_eq!(offsets.offsets, [103, 1, 4]);
let result = offsets.resolve(1, 5);
assert_eq!(result, 103);
assert_eq!(offsets.offsets, [103, 1, 4]);
let result = offsets.resolve(2, 5);
assert_eq!(result, 1);
assert_eq!(offsets.offsets, [1, 103, 4]); }
}