diff --git a/src/greedy_packer.rs b/src/greedy_packer.rs index 8794039..73cfd84 100644 --- a/src/greedy_packer.rs +++ b/src/greedy_packer.rs @@ -21,7 +21,7 @@ pub fn pack( if let Some(m) = match_finder.matches(pos).next() { let max_offset = 1 << (m.length * 3 - 1).min(31); let offset = pos - m.pos; - if offset < max_offset { + if offset < max_offset && m.length >= config.min_length() { lz::Op::Match { offset: offset as u32, len: m.length as u32, @@ -40,7 +40,7 @@ pub fn pack( .zip(data[(pos - offset)..].iter()) .take_while(|(a, b)| a == b) .count(); - if length > 0 { + if length >= config.min_length() { lz::Op::Match { offset: offset as u32, len: length as u32, diff --git a/src/lib.rs b/src/lib.rs index ff133b8..6bbcafd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub struct Config { pub simplified_prob_update: bool, pub no_repeated_offsets: bool, + pub eof_in_length: bool, } impl Default for Config { @@ -39,6 +40,17 @@ impl Default for Config { simplified_prob_update: false, no_repeated_offsets: false, + eof_in_length: false, + } + } +} + +impl Config { + pub fn min_length(&self) -> usize { + if self.eof_in_length { + 2 + } else { + 1 } } } diff --git a/src/lz.rs b/src/lz.rs index 759282e..d1ee613 100644 --- a/src/lz.rs +++ b/src/lz.rs @@ -40,11 +40,12 @@ impl Op { coder, state, 256 * state.parity_contexts + 1, - offset + 1, + offset + if config.eof_in_length { 0 } else { 1 }, config, ); state.last_offset = offset; } + assert!(!config.eof_in_length || len > 1); encode_length(coder, state, 256 * state.parity_contexts + 65, len, config); state.prev_was_match = true; state.pos += len as usize; @@ -60,15 +61,20 @@ pub fn encode_eof(coder: &mut dyn EntropyCoder, state: &mut CoderState, config: state.pos % state.parity_contexts * 256, config.is_match_bit, ); - if !state.prev_was_match { + if !state.prev_was_match && !config.no_repeated_offsets { encode_bit( coder, state, 256 * state.parity_contexts, - config.new_offset_bit, + config.new_offset_bit ^ config.eof_in_length, ); } - encode_length(coder, state, 256 * state.parity_contexts + 1, 1, config); + if !config.eof_in_length || config.no_repeated_offsets { + encode_length(coder, state, 256 * state.parity_contexts + 1, 1, config); + } + if config.eof_in_length { + encode_length(coder, state, 256 * state.parity_contexts + 65, 1, config); + } } fn encode_bit( @@ -183,7 +189,7 @@ pub fn unpack_internal( &mut contexts, 256 * config.parity_contexts + 1, &config, - ) - 1; + ) - if config.eof_in_length { 0 } else { 1 }; if offset == 0 { break; } @@ -194,6 +200,9 @@ pub fn unpack_internal( 256 * config.parity_contexts + 65, &config, ); + if config.eof_in_length && length == 1 { + break; + } if let Some(ref mut result) = result { for _ in 0..length { result.push(result[result.len() - offset]); diff --git a/src/main.rs b/src/main.rs index a3708a6..d724657 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,12 +30,14 @@ fn main() -> Result<()> { config.bitstream_is_big_endian = true; } Long("no-repeated-offsets") => config.no_repeated_offsets = true, + Long("eof-in-length") => config.eof_in_length = true, Long("z80") => { config.use_bitstream = true; config.bitstream_is_big_endian = true; config.invert_bit_encoding = true; config.simplified_prob_update = true; + level = 9; } Long("x86") => { config.use_bitstream = true; diff --git a/src/parsing_packer.rs b/src/parsing_packer.rs index d4a7283..c5e9728 100644 --- a/src/parsing_packer.rs +++ b/src/parsing_packer.rs @@ -110,6 +110,9 @@ fn parse( max_arrivals: usize, config: &crate::Config, ) { + if length < config.min_length() { + return; + } cost_counter.reset(); let mut state = arrival.state.clone(); let op = lz::Op::Match {