Coverage Report

Created: 2025-11-16 07:09

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