/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 | } |