1use crate::bitstream::LsbWriter;
2use crate::huffman_table::HuffmanTable;
3use crate::lzvalue::LZType;
4#[cfg(test)]
5use std::mem;
67// The first bits of each block, which describe the type of the block
8// `-TTF` - TT = type, 00 = stored, 01 = fixed, 10 = dynamic, 11 = reserved, F - 1 if final block
9// `0000`;
10const FIXED_FIRST_BYTE: u16 = 0b010;
11const FIXED_FIRST_BYTE_FINAL: u16 = 0b011;
12const DYNAMIC_FIRST_BYTE: u16 = 0b100;
13const DYNAMIC_FIRST_BYTE_FINAL: u16 = 0b101;
1415#[allow(dead_code)]
16pub enum BType {
17 NoCompression = 0b00,
18 FixedHuffman = 0b01,
19 DynamicHuffman = 0b10, // Reserved = 0b11, //Error
20}
2122/// A struct wrapping a writer that writes data compressed using the provided Huffman table
23pub struct EncoderState {
24pub huffman_table: HuffmanTable,
25pub writer: LsbWriter,
26}
2728impl EncoderState {
29/// Creates a new encoder state using the provided Huffman table and writer
30pub fn new(writer: Vec<u8>) -> EncoderState {
31 EncoderState {
32 huffman_table: HuffmanTable::empty(),
33 writer: LsbWriter::new(writer),
34 }
35 }
3637#[cfg(test)]
38/// Creates a new encoder state using the fixed Huffman table
39pub fn fixed(writer: Vec<u8>) -> EncoderState {
40 EncoderState {
41 huffman_table: HuffmanTable::fixed_table(),
42 writer: LsbWriter::new(writer),
43 }
44 }
4546pub fn inner_vec(&mut self) -> &mut Vec<u8> {
47&mut self.writer.w
48 }
4950/// Encodes a literal value to the writer
51fn write_literal(&mut self, value: u8) {
52let code = self.huffman_table.get_literal(value);
53debug_assert!(code.length > 0);
54self.writer.write_bits(code.code, code.length);
55 }
5657/// Write a LZvalue to the contained writer, returning Err if the write operation fails
58pub fn write_lzvalue(&mut self, value: LZType) {
59match value {
60 LZType::Literal(l) => self.write_literal(l),
61 LZType::StoredLengthDistance(l, d) => {
62let (code, extra_bits_code) = self.huffman_table.get_length_huffman(l);
63debug_assert!(
64 code.length != 0,
65"Code: {:?}, Value: {:?}", code, value
66 );
67self.writer.write_bits(code.code, code.length);
68self.writer
69 .write_bits(extra_bits_code.code, extra_bits_code.length);
7071let (code, extra_bits_code) = self.huffman_table.get_distance_huffman(d);
72debug_assert!(
73 code.length != 0,
74"Code: {:?}, Value: {:?}", code, value
75 );
7677self.writer.write_bits(code.code, code.length);
78self.writer
79 .write_bits(extra_bits_code.code, extra_bits_code.length)
80 }
81 };
82 }
8384/// Write the start of a block, returning Err if the write operation fails.
85pub fn write_start_of_block(&mut self, fixed: bool, final_block: bool) {
86if final_block {
87// The final block has one bit flipped to indicate it's
88 // the final one
89if fixed {
90self.writer.write_bits(FIXED_FIRST_BYTE_FINAL, 3)
91 } else {
92self.writer.write_bits(DYNAMIC_FIRST_BYTE_FINAL, 3)
93 }
94 } else if fixed {
95self.writer.write_bits(FIXED_FIRST_BYTE, 3)
96 } else {
97self.writer.write_bits(DYNAMIC_FIRST_BYTE, 3)
98 }
99 }
100101/// Write the end of block code
102pub fn write_end_of_block(&mut self) {
103let code = self.huffman_table.get_end_of_block();
104self.writer.write_bits(code.code, code.length)
105 }
106107/// Flush the contained writer and it's bitstream wrapper.
108pub fn flush(&mut self) {
109self.writer.flush_raw()
110 }
111112pub fn set_huffman_to_fixed(&mut self) {
113self.huffman_table.set_to_fixed()
114 }
115116/// Reset the encoder state with a new writer, returning the old one if flushing
117 /// succeeds.
118#[cfg(test)]
119pub fn reset(&mut self, writer: Vec<u8>) -> Vec<u8> {
120// Make sure the writer is flushed
121 // Ideally this should be done before this function is called, but we
122 // do it here just in case.
123self.flush();
124// Reset the huffman table
125 // This probably isn't needed, but again, we do it just in case to avoid leaking any data
126 // If this turns out to be a performance issue, it can probably be ignored later.
127self.huffman_table = HuffmanTable::empty();
128 mem::replace(&mut self.writer.w, writer)
129 }
130}