use length_encode::EncodedLength;
use length_encode::{encode_lengths, huffman_lengths_from_frequency, COPY_PREVIOUS,
REPEAT_ZERO_3_BITS, REPEAT_ZERO_7_BITS};
use huffman_table::{create_codes, NUM_LITERALS_AND_LENGTHS, NUM_DISTANCE_CODES};
use bitstream::{BitWriter, LsbWriter};
use std::io::{Write, Result};
use std::cmp;
pub const MIN_NUM_LITERALS_AND_LENGTHS: usize = 257;
pub const MIN_NUM_DISTANCES: usize = 1;
const HUFFMAN_LENGTH_ORDER: [u8; 19] = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14,
1, 15];
const HLIT_BITS: u8 = 5;
const HDIST_BITS: u8 = 5;
const HCLEN_BITS: u8 = 4;
const MAX_HUFFMAN_CODE_LENGTH: usize = 7;
pub fn remove_trailing_zeroes<T: From<u8> + PartialEq>(input: &[T], min_length: usize) -> &[T] {
let num_zeroes = input.iter().rev().take_while(|&a| *a == T::from(0)).count();
&input[0..cmp::max(input.len() - num_zeroes, min_length)]
}
pub fn write_huffman_lengths<W: Write>(literal_len_lengths: &[u8],
distance_lengths: &[u8],
writer: &mut LsbWriter<W>)
-> Result<()> {
assert!(literal_len_lengths.len() <= NUM_LITERALS_AND_LENGTHS);
assert!(literal_len_lengths.len() >= MIN_NUM_LITERALS_AND_LENGTHS);
assert!(distance_lengths.len() <= NUM_DISTANCE_CODES);
assert!(distance_lengths.len() >= MIN_NUM_DISTANCES);
let hlit = (literal_len_lengths.len() - MIN_NUM_LITERALS_AND_LENGTHS) as u16;
writer.write_bits(hlit, HLIT_BITS)?;
let hdist = (distance_lengths.len() - MIN_NUM_DISTANCES) as u16;
writer.write_bits(hdist, HDIST_BITS)?;
let (encoded, freqs) =
encode_lengths(literal_len_lengths.iter().chain(distance_lengths.iter()).cloned()).unwrap();
let huffman_table_lengths = huffman_lengths_from_frequency(&freqs, MAX_HUFFMAN_CODE_LENGTH);
let used_hclens = HUFFMAN_LENGTH_ORDER.len() -
HUFFMAN_LENGTH_ORDER.iter()
.rev()
.take_while(|&&n| huffman_table_lengths[n as usize] == 0)
.count();
let hclen = used_hclens - 4;
writer.write_bits(hclen as u16, HCLEN_BITS)?;
for n in &HUFFMAN_LENGTH_ORDER[..used_hclens] {
writer.write_bits(huffman_table_lengths[usize::from(*n)] as u16, 3)?;
}
let codes = create_codes(&huffman_table_lengths).expect("Failed to create huffman codes!");
for v in encoded {
match v {
EncodedLength::Length(n) => {
let code = codes[usize::from(n)];
writer.write_bits(code.code, code.length)?;
}
EncodedLength::CopyPrevious(n) => {
let code = codes[COPY_PREVIOUS];
writer.write_bits(code.code, code.length)?;
assert!(n >= 3);
assert!(n <= 6);
writer.write_bits((n - 3).into(), 2)?;
}
EncodedLength::RepeatZero3Bits(n) => {
let code = codes[REPEAT_ZERO_3_BITS];
writer.write_bits(code.code, code.length)?;
assert!(n >= 3);
writer.write_bits((n - 3).into(), 3)?;
}
EncodedLength::RepeatZero7Bits(n) => {
let code = codes[REPEAT_ZERO_7_BITS];
writer.write_bits(code.code, code.length)?;
assert!(n >= 11);
assert!(n <= 138);
writer.write_bits((n - 11).into(), 7)?;
}
}
}
Ok(())
}