lzma_rs/encode/
dumbencoder.rs

1use crate::compress::{Options, UnpackedSize};
2use crate::encode::rangecoder;
3use byteorder::{LittleEndian, WriteBytesExt};
4use std::io;
5
6pub struct Encoder<'a, W>
7where
8    W: 'a + io::Write,
9{
10    rangecoder: rangecoder::RangeEncoder<'a, W>,
11    literal_probs: [[u16; 0x300]; 8],
12    is_match: [u16; 4], // true = LZ, false = literal
13    unpacked_size: UnpackedSize,
14}
15
16const LC: u32 = 3;
17const LP: u32 = 0;
18const PB: u32 = 2;
19
20impl<'a, W> Encoder<'a, W>
21where
22    W: io::Write,
23{
24    pub fn from_stream(stream: &'a mut W, options: &Options) -> io::Result<Self> {
25        let dict_size = 0x0080_0000;
26
27        // Properties
28        let props = (LC + 9 * (LP + 5 * PB)) as u8;
29        lzma_info!("Properties {{ lc: {}, lp: {}, pb: {} }}", LC, LP, PB);
30        stream.write_u8(props)?;
31
32        // Dictionary
33        lzma_info!("Dict size: {}", dict_size);
34        stream.write_u32::<LittleEndian>(dict_size)?;
35
36        // Unpacked size
37        match &options.unpacked_size {
38            UnpackedSize::WriteToHeader(unpacked_size) => {
39                let value: u64 = match unpacked_size {
40                    None => {
41                        lzma_info!("Unpacked size: unknown");
42                        0xFFFF_FFFF_FFFF_FFFF
43                    }
44                    Some(x) => {
45                        lzma_info!("Unpacked size: {}", x);
46                        *x
47                    }
48                };
49                stream.write_u64::<LittleEndian>(value)?;
50            }
51            UnpackedSize::SkipWritingToHeader => {}
52        };
53
54        let encoder = Encoder {
55            rangecoder: rangecoder::RangeEncoder::new(stream),
56            literal_probs: [[0x400; 0x300]; 8],
57            is_match: [0x400; 4],
58            unpacked_size: options.unpacked_size,
59        };
60
61        Ok(encoder)
62    }
63
64    pub fn process<R>(mut self, input: R) -> io::Result<()>
65    where
66        R: io::Read,
67    {
68        let mut prev_byte = 0u8;
69        let mut input_len = 0;
70
71        for (out_len, byte_result) in input.bytes().enumerate() {
72            let byte = byte_result?;
73            let pos_state = out_len & 3;
74            input_len = out_len;
75
76            // Literal
77            self.rangecoder
78                .encode_bit(&mut self.is_match[pos_state], false)?;
79
80            self.encode_literal(byte, prev_byte)?;
81            prev_byte = byte;
82        }
83
84        self.finish(input_len + 1)
85    }
86
87    fn finish(&mut self, input_len: usize) -> io::Result<()> {
88        match self.unpacked_size {
89            UnpackedSize::SkipWritingToHeader | UnpackedSize::WriteToHeader(Some(_)) => {}
90            UnpackedSize::WriteToHeader(None) => {
91                // Write end-of-stream marker
92                let pos_state = input_len & 3;
93
94                // Match
95                self.rangecoder
96                    .encode_bit(&mut self.is_match[pos_state], true)?;
97                // New distance
98                self.rangecoder.encode_bit(&mut 0x400, false)?;
99
100                // Dummy len, as small as possible (len = 0)
101                for _ in 0..4 {
102                    self.rangecoder.encode_bit(&mut 0x400, false)?;
103                }
104
105                // Distance marker = 0xFFFFFFFF
106                // pos_slot = 63
107                for _ in 0..6 {
108                    self.rangecoder.encode_bit(&mut 0x400, true)?;
109                }
110                // num_direct_bits = 30
111                // result = 3 << 30 = C000_0000
112                //        + 3FFF_FFF0  (26 bits)
113                //        + F          ( 4 bits)
114                for _ in 0..30 {
115                    self.rangecoder.encode_bit(&mut 0x400, true)?;
116                }
117                //        = FFFF_FFFF
118            }
119        }
120
121        // Flush range coder
122        self.rangecoder.finish()
123    }
124
125    fn encode_literal(&mut self, byte: u8, prev_byte: u8) -> io::Result<()> {
126        let prev_byte = prev_byte as usize;
127
128        let mut result: usize = 1;
129        let lit_state = prev_byte >> 5;
130        let probs = &mut self.literal_probs[lit_state];
131
132        for i in 0..8 {
133            let bit = ((byte >> (7 - i)) & 1) != 0;
134            self.rangecoder.encode_bit(&mut probs[result], bit)?;
135            result = (result << 1) ^ (bit as usize);
136        }
137
138        Ok(())
139    }
140}