Coverage Report

Created: 2026-09-28 07:39

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/decode/lzma2.rs
Line
Count
Source
1
use crate::decode::lzbuffer;
2
use crate::decode::lzbuffer::LzBuffer;
3
use crate::decode::lzma;
4
use crate::decode::rangecoder;
5
use crate::error;
6
use byteorder::{BigEndian, ReadBytesExt};
7
use std::io;
8
use std::io::Read;
9
10
0
pub fn decode_stream<R, W>(input: &mut R, output: &mut W) -> error::Result<()>
11
0
where
12
0
    R: io::BufRead,
13
0
    W: io::Write,
14
{
15
0
    let accum = lzbuffer::LzAccumBuffer::from_stream(output);
16
0
    let mut decoder = lzma::new_accum(accum, 0, 0, 0, None);
17
18
    loop {
19
0
        let status = input
20
0
            .read_u8()
21
0
            .map_err(|e| error::Error::LzmaError(format!("LZMA2 expected new status: {}", e)))?;
22
23
        lzma_info!("LZMA2 status: {}", status);
24
25
0
        if status == 0 {
26
            lzma_info!("LZMA2 end of input");
27
0
            break;
28
0
        } else if status == 1 {
29
            // uncompressed reset dict
30
0
            parse_uncompressed(&mut decoder, input, true)?;
31
0
        } else if status == 2 {
32
            // uncompressed no reset
33
0
            parse_uncompressed(&mut decoder, input, false)?;
34
        } else {
35
0
            parse_lzma(&mut decoder, input, status)?;
36
        }
37
    }
38
39
0
    decoder.output.finish()?;
40
0
    Ok(())
41
0
}
42
43
0
fn parse_lzma<R, W>(
44
0
    decoder: &mut lzma::DecoderState<W, lzbuffer::LzAccumBuffer<W>>,
45
0
    input: &mut R,
46
0
    status: u8,
47
0
) -> error::Result<()>
48
0
where
49
0
    R: io::BufRead,
50
0
    W: io::Write,
51
{
52
0
    if status & 0x80 == 0 {
53
0
        return Err(error::Error::LzmaError(format!(
54
0
            "LZMA2 invalid status {}, must be 0, 1, 2 or >= 128",
55
0
            status
56
0
        )));
57
0
    }
58
59
    let reset_dict: bool;
60
    let reset_state: bool;
61
    let reset_props: bool;
62
0
    match (status >> 5) & 0x3 {
63
0
        0 => {
64
0
            reset_dict = false;
65
0
            reset_state = false;
66
0
            reset_props = false;
67
0
        }
68
0
        1 => {
69
0
            reset_dict = false;
70
0
            reset_state = true;
71
0
            reset_props = false;
72
0
        }
73
0
        2 => {
74
0
            reset_dict = false;
75
0
            reset_state = true;
76
0
            reset_props = true;
77
0
        }
78
0
        3 => {
79
0
            reset_dict = true;
80
0
            reset_state = true;
81
0
            reset_props = true;
82
0
        }
83
0
        _ => unreachable!(),
84
    }
85
86
0
    let unpacked_size = input
87
0
        .read_u16::<BigEndian>()
88
0
        .map_err(|e| error::Error::LzmaError(format!("LZMA2 expected unpacked size: {}", e)))?;
89
0
    let unpacked_size = ((((status & 0x1F) as u64) << 16) | (unpacked_size as u64)) + 1;
90
91
0
    let packed_size = input
92
0
        .read_u16::<BigEndian>()
93
0
        .map_err(|e| error::Error::LzmaError(format!("LZMA2 expected packed size: {}", e)))?;
94
0
    let packed_size = (packed_size as u64) + 1;
95
96
    lzma_info!(
97
        "LZMA2 compressed block {{ unpacked_size: {}, packed_size: {}, reset_dict: {}, reset_state: {}, reset_props: {} }}",
98
        unpacked_size,
99
        packed_size,
100
        reset_dict,
101
        reset_state,
102
        reset_props
103
    );
104
105
0
    if reset_dict {
106
0
        decoder.output.reset()?;
107
0
    }
108
109
0
    if reset_state {
110
        let lc: u32;
111
        let lp: u32;
112
        let mut pb: u32;
113
114
0
        if reset_props {
115
0
            let props = input.read_u8().map_err(|e| {
116
0
                error::Error::LzmaError(format!("LZMA2 expected new properties: {}", e))
117
0
            })?;
118
119
0
            pb = props as u32;
120
0
            if pb >= 225 {
121
0
                return Err(error::Error::LzmaError(format!(
122
0
                    "LZMA2 invalid properties: {} must be < 225",
123
0
                    pb
124
0
                )));
125
0
            }
126
127
0
            lc = pb % 9;
128
0
            pb /= 9;
129
0
            lp = pb % 5;
130
0
            pb /= 5;
131
132
0
            if lc + lp > 4 {
133
0
                return Err(error::Error::LzmaError(format!(
134
0
                    "LZMA2 invalid properties: lc + lp ({} + {}) must be <= 4",
135
0
                    lc, lp
136
0
                )));
137
0
            }
138
139
            lzma_info!("Properties {{ lc: {}, lp: {}, pb: {} }}", lc, lp, pb);
140
0
        } else {
141
0
            lc = decoder.lc;
142
0
            lp = decoder.lp;
143
0
            pb = decoder.pb;
144
0
        }
145
146
0
        decoder.reset_state(lc, lp, pb);
147
0
    }
148
149
0
    decoder.set_unpacked_size(Some(unpacked_size + decoder.output.len() as u64));
150
151
0
    let mut taken = input.take(packed_size);
152
0
    let mut rangecoder = rangecoder::RangeDecoder::new(&mut taken)
153
0
        .map_err(|e| error::Error::LzmaError(format!("LZMA input too short: {}", e)))?;
154
0
    decoder.process(&mut rangecoder)
155
0
}
156
157
0
fn parse_uncompressed<R, W>(
158
0
    decoder: &mut lzma::DecoderState<W, lzbuffer::LzAccumBuffer<W>>,
159
0
    input: &mut R,
160
0
    reset_dict: bool,
161
0
) -> error::Result<()>
162
0
where
163
0
    R: io::BufRead,
164
0
    W: io::Write,
165
{
166
0
    let unpacked_size = input
167
0
        .read_u16::<BigEndian>()
168
0
        .map_err(|e| error::Error::LzmaError(format!("LZMA2 expected unpacked size: {}", e)))?;
169
0
    let unpacked_size = (unpacked_size as usize) + 1;
170
171
    lzma_info!(
172
        "LZMA2 uncompressed block {{ unpacked_size: {}, reset_dict: {} }}",
173
        unpacked_size,
174
        reset_dict
175
    );
176
177
0
    if reset_dict {
178
0
        decoder.output.reset()?;
179
0
    }
180
181
0
    let mut buf = vec![0; unpacked_size];
182
0
    input.read_exact(buf.as_mut_slice()).map_err(|e| {
183
0
        error::Error::LzmaError(format!(
184
0
            "LZMA2 expected {} uncompressed bytes: {}",
185
0
            unpacked_size, e
186
0
        ))
187
0
    })?;
188
0
    decoder.output.append_bytes(buf.as_slice());
189
190
0
    Ok(())
191
0
}