use crate::bitstream::LsbWriter;
use crate::huffman_table::HuffmanTable;
use crate::lzvalue::LZType;
#[cfg(test)]
use std::mem;
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 {
pub huffman_table: HuffmanTable,
pub writer: LsbWriter,
}
impl EncoderState {
pub fn new(writer: Vec<u8>) -> EncoderState {
EncoderState {
huffman_table: HuffmanTable::empty(),
writer: LsbWriter::new(writer),
}
}
#[cfg(test)]
pub fn fixed(writer: Vec<u8>) -> EncoderState {
EncoderState {
huffman_table: HuffmanTable::fixed_table(),
writer: LsbWriter::new(writer),
}
}
pub fn inner_vec(&mut self) -> &mut Vec<u8> {
&mut self.writer.w
}
fn write_literal(&mut self, value: u8) {
let code = self.huffman_table.get_literal(value);
debug_assert!(code.length > 0);
self.writer.write_bits(code.code, code.length);
}
pub fn write_lzvalue(&mut self, value: LZType) {
match value {
LZType::Literal(l) => self.write_literal(l),
LZType::StoredLengthDistance(l, d) => {
let (code, extra_bits_code) = self.huffman_table.get_length_huffman(l);
debug_assert!(
code.length != 0,
format!("Code: {:?}, Value: {:?}", code, value)
);
self.writer.write_bits(code.code, code.length);
self.writer
.write_bits(extra_bits_code.code, extra_bits_code.length);
let (code, extra_bits_code) = self.huffman_table.get_distance_huffman(d);
debug_assert!(
code.length != 0,
format!("Code: {:?}, Value: {:?}", code, value)
);
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) {
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) {
let code = self.huffman_table.get_end_of_block();
self.writer.write_bits(code.code, code.length)
}
pub fn flush(&mut self) {
self.writer.flush_raw()
}
pub fn set_huffman_to_fixed(&mut self) {
self.huffman_table.set_to_fixed()
}
#[cfg(test)]
pub fn reset(&mut self, writer: Vec<u8>) -> Vec<u8> {
self.flush();
self.huffman_table = HuffmanTable::empty();
mem::replace(&mut self.writer.w, writer)
}
}