use std::collections::HashMap;
use std::cmp::min;
use std::fmt::Error;
const WINDOW_LEN: usize = 32767;
const MAX_MATCH_LEN: usize = 255;
struct Match {
len: u8,
offset: u16,
next_symbol: u8,
}
pub fn lz77_encode(source: &[u8]) -> Vec<u8> {
let mut search_buf: &[u8] = &[];
let mut lookahead_buf = &source[0..min(WINDOW_LEN, source.len())];
let mut output = Vec::<u8>::new();
let mut cursor: usize = 0;
while lookahead_buf.len() > 0 {
let mut best_match = Match::with_symbol(source[cursor]);
let mut sb_iter = search_buf.iter().enumerate().peekable();
while sb_iter.peek().is_some() {
let sb_pos = sb_iter.peek().unwrap().0;
let mut inner_sb_iter = sb_iter.clone().cycle();
let mut match_len = 0;
for (lb_pos, lb_symbol) in lookahead_buf.iter().enumerate() {
let sb_symbol = inner_sb_iter.next().unwrap().1;
if sb_symbol == lb_symbol {
match_len += 1;
}
if sb_symbol != lb_symbol || lb_pos == lookahead_buf.len()-1 || match_len == MAX_MATCH_LEN {
if match_len as u8 > best_match.len {
best_match.len = match_len as u8;
best_match.offset = (search_buf.len() - sb_pos) as u16;
best_match.next_symbol = lookahead_buf[min(match_len as usize, lookahead_buf.len()-1)];
}
break;
}
}
sb_iter.next();
}
output.push(best_match.len);
output.push((best_match.offset >> 8) as u8);
output.push(best_match.offset as u8);
output.push(best_match.next_symbol);
cursor += best_match.len as usize + 1;
if cursor >= source.len() { break; }
search_buf = &source[cursor.saturating_sub(WINDOW_LEN)..cursor];
lookahead_buf = &source[cursor..min(WINDOW_LEN+cursor, source.len())];
}
output
}
pub fn lz77_decode(source: &[u8]) -> Result<Vec<u8>, Error> {
let mut output = Vec::new();
let mut iter = source.iter();
while let Some(&len) = iter.next() {
let first_off_byte = *iter.next().ok_or(Error)? as u16;
let second_off_byte = *iter.next().ok_or(Error)? as u16;
let offset = (first_off_byte << 8) | second_off_byte;
let next_symbol = *iter.next().ok_or(Error)?;
let start = output.len() - offset as usize;
for i in start..start+len as usize {
output.push(output[i % output.len()]);
}
output.push(next_symbol);
}
Ok(output)
}
impl Match {
pub fn new() -> Self { Match { len: 0, offset: 0, next_symbol: 0 } }
pub fn with_symbol(symbol: u8) -> Self {
Match { len: 0, offset: 0, next_symbol: symbol }
}
}
pub fn trie_encode(source: &[u8]) {
}