add static huffman tables
as it turns out, the static huffman tables are completely and utterly useless, and I don't think any modern compressor actually uses them, but we should probably implement them instead of panickingpng-branch
parent
bd13092188
commit
f832a45f36
|
@ -99,12 +99,10 @@ pub fn load_deflate(b: &[u8]) -> ResultS<(usize, Vec<u8>)>
|
||||||
Ok((p / 8, v))
|
Ok((p / 8, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream_deflate(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
fn stream_deflate(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize>
|
||||||
{
|
{
|
||||||
let bfinal = read_bits_l(b, p, 1)?;
|
let bfinal = read_bits_l(b, p, 1)?; p += 1;
|
||||||
let btype = read_bits_l(b, p + 1, 2)?;
|
let btype = read_bits_l(b, p, 2)?; p += 2;
|
||||||
|
|
||||||
let p = p + 3;
|
|
||||||
|
|
||||||
let p = match btype {
|
let p = match btype {
|
||||||
0b10 => stream_dynamic(v, b, p)?,
|
0b10 => stream_dynamic(v, b, p)?,
|
||||||
|
@ -177,30 +175,21 @@ fn stream_dynamic(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize>
|
||||||
let lst = alphabet[i - 1];
|
let lst = alphabet[i - 1];
|
||||||
p += 2;
|
p += 2;
|
||||||
|
|
||||||
for _ in 0..len {
|
for _ in 0..len {alphabet[i] = lst; i += 1;}
|
||||||
alphabet[i] = lst;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
17 => {
|
17 => {
|
||||||
// repeat '0' 3-10 times
|
// repeat '0' 3-10 times
|
||||||
let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3);
|
let len = usize::from(read_bits_l(b, p, 3)? as u8 + 3);
|
||||||
p += 3;
|
p += 3;
|
||||||
|
|
||||||
for _ in 0..len {
|
for _ in 0..len {alphabet[i] = 0; i += 1;}
|
||||||
alphabet[i] = 0;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
18 => {
|
18 => {
|
||||||
// repeat '0' 11-138 times
|
// repeat '0' 11-138 times
|
||||||
let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11);
|
let len = usize::from(read_bits_l(b, p, 7)? as u8 + 11);
|
||||||
p += 7;
|
p += 7;
|
||||||
|
|
||||||
for _ in 0..len {
|
for _ in 0..len {alphabet[i] = 0; i += 1;}
|
||||||
alphabet[i] = 0;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
bail!("bad symbol in alphabet");
|
bail!("bad symbol in alphabet");
|
||||||
|
@ -221,15 +210,28 @@ fn stream_dynamic(v: &mut Vec<u8>, b: &[u8], mut p: usize) -> ResultS<usize>
|
||||||
let dst_sta = len_end;
|
let dst_sta = len_end;
|
||||||
let dst_end = dst_sta + hdist;
|
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_len = HuffmanTable::new(&alphabet[len_sta..len_end])?;
|
||||||
let table_dst = HuffmanTable::new(&alphabet[dst_sta..dst_end])?;
|
let table_dst = HuffmanTable::new(&alphabet[dst_sta..dst_end])?;
|
||||||
|
|
||||||
output_tables(v, b, p, table_len, table_dst)
|
output_tables(v, b, p, table_len, table_dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream_s_table(_v: &mut Vec<u8>, _b: &[u8], _p: usize) -> ResultS<usize>
|
fn stream_s_table(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
||||||
{
|
{
|
||||||
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<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
fn stream_literal(v: &mut Vec<u8>, b: &[u8], p: usize) -> ResultS<usize>
|
||||||
|
@ -280,6 +282,7 @@ fn output_tables(v: &mut Vec<u8>,
|
||||||
|
|
||||||
match sym.cmp(&256) {
|
match sym.cmp(&256) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
|
// direct byte
|
||||||
v.push(sym as u8);
|
v.push(sym as u8);
|
||||||
output_tables(v, b, p, table_len, table_dst)
|
output_tables(v, b, p, table_len, table_dst)
|
||||||
}
|
}
|
||||||
|
@ -287,36 +290,41 @@ fn output_tables(v: &mut Vec<u8>,
|
||||||
Ok(p)
|
Ok(p)
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
|
// this is a <len, dst> pair
|
||||||
let sym = sym - 257;
|
let sym = sym - 257;
|
||||||
|
|
||||||
if sym > 29 {
|
if sym > 29 {
|
||||||
Err(err_msg("invalid fixed code"))
|
bail!("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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,4 +46,13 @@ fn defl_must_not_succeed()
|
||||||
assert!(defl::load_gzip_header(include_bytes!("data/gzbad7.bin")).is_err());
|
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
|
// EOF
|
||||||
|
|
Loading…
Reference in New Issue