use std::io;
use std::io::Write;
use std::mem;
use huffman_table::{HuffmanTable, HuffmanError};
use bitstream::{LsbWriter, BitWriter};
use lz77::LDPair;
const FIXED_FIRST_BYTE: u16 = 0b010;
const FIXED_FIRST_BYTE_FINAL: u16 = 0b011;
const DYNAMIC_FIRST_BYTE: u16 = 0b100;
const DYNAMIC_FIRST_BYTE_FINAL: u16 = 0b101;
#[allow(dead_code)]
pub enum BType {
NoCompression = 0b00,
FixedHuffman = 0b01,
DynamicHuffman = 0b10, }
pub struct EncoderState<W: Write> {
huffman_table: HuffmanTable,
pub writer: LsbWriter<W>,
}
impl<W: Write> EncoderState<W> {
pub fn new(huffman_table: HuffmanTable, writer: W) -> EncoderState<W> {
EncoderState {
huffman_table: huffman_table,
writer: LsbWriter::new(writer),
}
}
#[cfg(test)]
pub fn fixed(writer: W) -> EncoderState<W> {
EncoderState::new(HuffmanTable::fixed_table(), writer)
}
fn write_literal(&mut self, value: u8) -> io::Result<()> {
let code = self.huffman_table.get_literal(value);
self.writer.write_bits(code.code, code.length)
}
#[inline]
pub fn write_ldpair(&mut self, value: LDPair) -> io::Result<()> {
match value {
LDPair::Literal(l) => self.write_literal(l),
LDPair::Length(l) => {
let (code, extra_bits_code) = self.huffman_table.get_length_huffman(l).unwrap();
self.writer
.write_bits(code.code, code.length)?;
self.writer.write_bits(extra_bits_code.code, extra_bits_code.length)
}
LDPair::Distance(d) => {
let (code, extra_bits_code) = self.huffman_table
.get_distance_huffman(d)
.unwrap();
self.writer
.write_bits(code.code, code.length)?;
self.writer.write_bits(extra_bits_code.code, extra_bits_code.length)
}
}
}
pub fn write_start_of_block(&mut self, fixed: bool, final_block: bool) -> io::Result<()> {
if final_block {
if fixed {
self.writer.write_bits(FIXED_FIRST_BYTE_FINAL, 3)
} else {
self.writer.write_bits(DYNAMIC_FIRST_BYTE_FINAL, 3)
}
} else if fixed {
self.writer.write_bits(FIXED_FIRST_BYTE, 3)
} else {
self.writer.write_bits(DYNAMIC_FIRST_BYTE, 3)
}
}
pub fn write_end_of_block(&mut self) -> io::Result<()> {
let code = self.huffman_table.get_end_of_block();
self.writer.write_bits(code.code, code.length)
}
pub fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
pub fn update_huffman_table(&mut self,
literals_and_lengths: &[u8],
distances: &[u8])
-> Result<(), HuffmanError> {
self.huffman_table.update_from_length_tables(literals_and_lengths, distances)
}
pub fn reset(&mut self, writer: W) -> io::Result<W> {
self.flush()?;
self.huffman_table = HuffmanTable::empty();
Ok(mem::replace(&mut self.writer.w, writer))
}
}