#![forbid(unsafe_code)] use super::flush_block; use crate::{ deflate::{ compare256::compare256_rle_slice, fill_window, BlockState, DeflateStream, MIN_LOOKAHEAD, STD_MAX_MATCH, STD_MIN_MATCH, }, DeflateFlush, }; pub fn deflate_rle(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { let mut match_len = 0; let mut bflush; loop { // Make sure that we always have enough lookahead, except // at the end of the input file. We need STD_MAX_MATCH bytes // for the next match, plus WANT_MIN_MATCH bytes to insert the // string following the next match. if stream.state.lookahead < MIN_LOOKAHEAD { fill_window(stream); if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush { return BlockState::NeedMore; } if stream.state.lookahead == 0 { break; /* flush the current block */ } } /* See how many times the previous byte repeats */ let state = &mut stream.state; if state.lookahead >= STD_MIN_MATCH && state.strstart > 0 { let scan = &state.window.filled()[state.strstart - 1..][..3 + 256]; { if scan[0] == scan[1] && scan[1] == scan[2] { match_len = compare256_rle_slice(scan[0], &scan[3..]) + 2; match_len = Ord::min(match_len, state.lookahead); match_len = Ord::min(match_len, STD_MAX_MATCH); } } assert!( state.strstart - 1 + match_len <= state.window_size - 1, "wild scan" ); } /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ if match_len >= STD_MIN_MATCH { // check_match(s, s->strstart, s->strstart - 1, match_len); bflush = state.tally_dist(1, match_len - STD_MIN_MATCH); state.lookahead -= match_len; state.strstart += match_len; match_len = 0; } else { /* No match, output a literal byte */ let lc = state.window.filled()[state.strstart]; bflush = state.tally_lit(lc); state.lookahead -= 1; state.strstart += 1; } if bflush { flush_block!(stream, false); } } stream.state.insert = 0; if flush == DeflateFlush::Finish { flush_block!(stream, true); return BlockState::FinishDone; } if !stream.state.sym_buf.is_empty() { flush_block!(stream, false); } BlockState::BlockDone }