Coverage Report

Created: 2024-12-17 06:15

/rust/registry/src/index.crates.io-6f17d22bba15001f/deflate-1.0.0/src/encoder_state.rs
Line
Count
Source (jump to first uncovered line)
1
use crate::bitstream::LsbWriter;
2
use crate::huffman_table::HuffmanTable;
3
use crate::lzvalue::LZType;
4
#[cfg(test)]
5
use std::mem;
6
7
// 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`;
10
const FIXED_FIRST_BYTE: u16 = 0b010;
11
const FIXED_FIRST_BYTE_FINAL: u16 = 0b011;
12
const DYNAMIC_FIRST_BYTE: u16 = 0b100;
13
const DYNAMIC_FIRST_BYTE_FINAL: u16 = 0b101;
14
15
#[allow(dead_code)]
16
pub enum BType {
17
    NoCompression = 0b00,
18
    FixedHuffman = 0b01,
19
    DynamicHuffman = 0b10, // Reserved = 0b11, //Error
20
}
21
22
/// A struct wrapping a writer that writes data compressed using the provided Huffman table
23
pub struct EncoderState {
24
    pub huffman_table: HuffmanTable,
25
    pub writer: LsbWriter,
26
}
27
28
impl EncoderState {
29
    /// Creates a new encoder state using the provided Huffman table and writer
30
0
    pub fn new(writer: Vec<u8>) -> EncoderState {
31
0
        EncoderState {
32
0
            huffman_table: HuffmanTable::empty(),
33
0
            writer: LsbWriter::new(writer),
34
0
        }
35
0
    }
36
37
    #[cfg(test)]
38
    /// Creates a new encoder state using the fixed Huffman table
39
    pub fn fixed(writer: Vec<u8>) -> EncoderState {
40
        EncoderState {
41
            huffman_table: HuffmanTable::fixed_table(),
42
            writer: LsbWriter::new(writer),
43
        }
44
    }
45
46
0
    pub fn inner_vec(&mut self) -> &mut Vec<u8> {
47
0
        &mut self.writer.w
48
0
    }
49
50
    /// Encodes a literal value to the writer
51
0
    fn write_literal(&mut self, value: u8) {
52
0
        let code = self.huffman_table.get_literal(value);
53
0
        debug_assert!(code.length > 0);
54
0
        self.writer.write_bits(code.code, code.length);
55
0
    }
56
57
    /// Write a LZvalue to the contained writer, returning Err if the write operation fails
58
0
    pub fn write_lzvalue(&mut self, value: LZType) {
59
0
        match value {
60
0
            LZType::Literal(l) => self.write_literal(l),
61
0
            LZType::StoredLengthDistance(l, d) => {
62
0
                let (code, extra_bits_code) = self.huffman_table.get_length_huffman(l);
63
0
                debug_assert!(
64
0
                    code.length != 0,
65
0
                    "Code: {:?}, Value: {:?}", code, value
66
                );
67
0
                self.writer.write_bits(code.code, code.length);
68
0
                self.writer
69
0
                    .write_bits(extra_bits_code.code, extra_bits_code.length);
70
0
71
0
                let (code, extra_bits_code) = self.huffman_table.get_distance_huffman(d);
72
0
                debug_assert!(
73
0
                    code.length != 0,
74
0
                    "Code: {:?}, Value: {:?}", code, value
75
                );
76
77
0
                self.writer.write_bits(code.code, code.length);
78
0
                self.writer
79
0
                    .write_bits(extra_bits_code.code, extra_bits_code.length)
80
            }
81
        };
82
0
    }
83
84
    /// Write the start of a block, returning Err if the write operation fails.
85
0
    pub fn write_start_of_block(&mut self, fixed: bool, final_block: bool) {
86
0
        if final_block {
87
            // The final block has one bit flipped to indicate it's
88
            // the final one
89
0
            if fixed {
90
0
                self.writer.write_bits(FIXED_FIRST_BYTE_FINAL, 3)
91
            } else {
92
0
                self.writer.write_bits(DYNAMIC_FIRST_BYTE_FINAL, 3)
93
            }
94
0
        } else if fixed {
95
0
            self.writer.write_bits(FIXED_FIRST_BYTE, 3)
96
        } else {
97
0
            self.writer.write_bits(DYNAMIC_FIRST_BYTE, 3)
98
        }
99
0
    }
100
101
    /// Write the end of block code
102
0
    pub fn write_end_of_block(&mut self) {
103
0
        let code = self.huffman_table.get_end_of_block();
104
0
        self.writer.write_bits(code.code, code.length)
105
0
    }
106
107
    /// Flush the contained writer and it's bitstream wrapper.
108
0
    pub fn flush(&mut self) {
109
0
        self.writer.flush_raw()
110
0
    }
111
112
0
    pub fn set_huffman_to_fixed(&mut self) {
113
0
        self.huffman_table.set_to_fixed()
114
0
    }
115
116
    /// Reset the encoder state with a new writer, returning the old one if flushing
117
    /// succeeds.
118
    #[cfg(test)]
119
    pub 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.
123
        self.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.
127
        self.huffman_table = HuffmanTable::empty();
128
        mem::replace(&mut self.writer.w, writer)
129
    }
130
}