diff --git a/source/marathon/defl.rs b/source/marathon/defl.rs index ebdcf24..89b07cc 100644 --- a/source/marathon/defl.rs +++ b/source/marathon/defl.rs @@ -99,12 +99,10 @@ pub fn load_deflate(b: &[u8]) -> ResultS<(usize, Vec)> Ok((p / 8, v)) } -fn stream_deflate(v: &mut Vec, b: &[u8], p: usize) -> ResultS +fn stream_deflate(v: &mut Vec, b: &[u8], mut p: usize) -> ResultS { - let bfinal = read_bits_l(b, p, 1)?; - let btype = read_bits_l(b, p + 1, 2)?; - - let p = p + 3; + let bfinal = read_bits_l(b, p, 1)?; p += 1; + let btype = read_bits_l(b, p, 2)?; p += 2; let p = match btype { 0b10 => stream_dynamic(v, b, p)?, @@ -177,30 +175,21 @@ fn stream_dynamic(v: &mut Vec, b: &[u8], mut p: usize) -> ResultS let lst = alphabet[i - 1]; p += 2; - for _ in 0..len { - alphabet[i] = lst; - i += 1; - } + for _ in 0..len {alphabet[i] = lst; i += 1;} } 17 => { // repeat '0' 3-10 times let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3); p += 3; - for _ in 0..len { - alphabet[i] = 0; - i += 1; - } + for _ in 0..len {alphabet[i] = 0; i += 1;} } 18 => { // repeat '0' 11-138 times let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11); p += 7; - for _ in 0..len { - alphabet[i] = 0; - i += 1; - } + for _ in 0..len {alphabet[i] = 0; i += 1;} } _ => { bail!("bad symbol in alphabet"); @@ -221,15 +210,28 @@ fn stream_dynamic(v: &mut Vec, b: &[u8], mut p: usize) -> ResultS let dst_sta = len_end; let dst_end = dst_sta + hdist; + // build the length and distance tables from this information let table_len = HuffmanTable::new(&alphabet[len_sta..len_end])?; let table_dst = HuffmanTable::new(&alphabet[dst_sta..dst_end])?; output_tables(v, b, p, table_len, table_dst) } -fn stream_s_table(_v: &mut Vec, _b: &[u8], _p: usize) -> ResultS +fn stream_s_table(v: &mut Vec, b: &[u8], p: usize) -> ResultS { - unimplemented!() + let mut len = [0; 288]; + + for len in len.iter_mut().take(144) {*len = 8;} + for len in len.iter_mut().take(256).skip(144) {*len = 9;} + for len in len.iter_mut().take(280).skip(256) {*len = 7;} + for len in len.iter_mut().take(280).skip(288) {*len = 8;} + + let dst = [5; 30]; + + let table_len = HuffmanTable::new(&len)?; + let table_dst = HuffmanTable::new(&dst)?; + + output_tables(v, b, p, table_len, table_dst) } fn stream_literal(v: &mut Vec, b: &[u8], p: usize) -> ResultS @@ -280,6 +282,7 @@ fn output_tables(v: &mut Vec, match sym.cmp(&256) { Ordering::Less => { + // direct byte v.push(sym as u8); output_tables(v, b, p, table_len, table_dst) } @@ -287,36 +290,41 @@ fn output_tables(v: &mut Vec, Ok(p) } Ordering::Greater => { + // this is a pair let sym = sym - 257; if sym > 29 { - Err(err_msg("invalid fixed code")) - } else { - let sym = usize::from(sym); - - let bits = LEN_EXTRA_BITS[sym]; - let leng = LEN_BASE[sym] + read_bits_l(b, p, bits)? as usize; - p += usize::from(bits); - - let (bits, sym) = table_dst.decode(b, p)?; - p += bits; - - let sym = usize::from(sym); - - let bits = DST_EXTRA_BITS[sym]; - let dist = DST_BASE[sym] + read_bits_l(b, p, bits)? as usize; - p += usize::from(bits); - - if dist > v.len() { - bail!("bad distance"); - } - - for _ in 0..leng { - v.push(v[v.len() - dist]); - } - - output_tables(v, b, p, table_len, table_dst) + bail!("invalid fixed code"); } + + let sym = usize::from(sym); + + // first get the actual length and any extra bits it may have + let bits = LEN_EXTRA_BITS[sym]; + let leng = LEN_BASE[sym] + read_bits_l(b, p, bits)? as usize; + p += usize::from(bits); + + // decode the distance with its alphabet + let (bits, sym) = table_dst.decode(b, p)?; + p += bits; + + let sym = usize::from(sym); + + // get the actual distance and any extra bits it may have + let bits = DST_EXTRA_BITS[sym]; + let dist = DST_BASE[sym] + read_bits_l(b, p, bits)? as usize; + p += usize::from(bits); + + if dist > v.len() { + bail!("bad distance"); + } + + // copy bytes from earlier + for _ in 0..leng { + v.push(v[v.len() - dist]); + } + + output_tables(v, b, p, table_len, table_dst) } } } diff --git a/tests/defl.rs b/tests/defl.rs index f73f402..80936ab 100644 --- a/tests/defl.rs +++ b/tests/defl.rs @@ -46,4 +46,13 @@ fn defl_must_not_succeed() assert!(defl::load_gzip_header(include_bytes!("data/gzbad7.bin")).is_err()); } +#[test] +#[allow(unused_must_use)] +fn defl_must_not_panic() +{ + for inp in &RANDOM { + defl::load_deflate(inp); + } +} + // EOF