lzma_rs/decode/
lzbuffer.rs
1use crate::error;
2use std::io;
3
4pub trait LzBuffer<W>
5where
6 W: io::Write,
7{
8 fn len(&self) -> usize;
9 fn last_or(&self, lit: u8) -> u8;
11 fn last_n(&self, dist: usize) -> error::Result<u8>;
13 fn append_literal(&mut self, lit: u8) -> error::Result<()>;
15 fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()>;
17 fn get_output(&self) -> &W;
19 fn get_output_mut(&mut self) -> &mut W;
21 fn finish(self) -> io::Result<W>;
23 fn into_output(self) -> W;
25}
26
27pub struct LzAccumBuffer<W>
29where
30 W: io::Write,
31{
32 stream: W, buf: Vec<u8>, memlimit: usize, len: usize, }
37
38impl<W> LzAccumBuffer<W>
39where
40 W: io::Write,
41{
42 pub fn from_stream(stream: W, memlimit: usize) -> Self {
43 Self {
44 stream,
45 buf: Vec::new(),
46 memlimit,
47 len: 0,
48 }
49 }
50
51 pub fn append_bytes(&mut self, buf: &[u8]) {
53 self.buf.extend_from_slice(buf);
54 self.len += buf.len();
55 }
56
57 pub fn reset(&mut self) -> io::Result<()> {
59 self.stream.write_all(self.buf.as_slice())?;
60 self.buf.clear();
61 self.len = 0;
62 Ok(())
63 }
64}
65
66impl<W> LzBuffer<W> for LzAccumBuffer<W>
67where
68 W: io::Write,
69{
70 fn len(&self) -> usize {
71 self.len
72 }
73
74 fn last_or(&self, lit: u8) -> u8 {
76 let buf_len = self.buf.len();
77 if buf_len == 0 {
78 lit
79 } else {
80 self.buf[buf_len - 1]
81 }
82 }
83
84 fn last_n(&self, dist: usize) -> error::Result<u8> {
86 let buf_len = self.buf.len();
87 if dist > buf_len {
88 return Err(error::Error::LzmaError(format!(
89 "Match distance {} is beyond output size {}",
90 dist, buf_len
91 )));
92 }
93
94 Ok(self.buf[buf_len - dist])
95 }
96
97 fn append_literal(&mut self, lit: u8) -> error::Result<()> {
99 let new_len = self.len + 1;
100
101 if new_len > self.memlimit {
102 Err(error::Error::LzmaError(format!(
103 "exceeded memory limit of {}",
104 self.memlimit
105 )))
106 } else {
107 self.buf.push(lit);
108 self.len = new_len;
109 Ok(())
110 }
111 }
112
113 fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()> {
115 lzma_debug!("LZ {{ len: {}, dist: {} }}", len, dist);
116 let buf_len = self.buf.len();
117 if dist > buf_len {
118 return Err(error::Error::LzmaError(format!(
119 "LZ distance {} is beyond output size {}",
120 dist, buf_len
121 )));
122 }
123
124 let mut offset = buf_len - dist;
125 for _ in 0..len {
126 let x = self.buf[offset];
127 self.buf.push(x);
128 offset += 1;
129 }
130 self.len += len;
131 Ok(())
132 }
133
134 fn get_output(&self) -> &W {
136 &self.stream
137 }
138
139 fn get_output_mut(&mut self) -> &mut W {
141 &mut self.stream
142 }
143
144 fn finish(mut self) -> io::Result<W> {
146 self.stream.write_all(self.buf.as_slice())?;
147 self.stream.flush()?;
148 Ok(self.stream)
149 }
150
151 fn into_output(self) -> W {
153 self.stream
154 }
155}
156
157pub struct LzCircularBuffer<W>
159where
160 W: io::Write,
161{
162 stream: W, buf: Vec<u8>, dict_size: usize, memlimit: usize, cursor: usize, len: usize, }
169
170impl<W> LzCircularBuffer<W>
171where
172 W: io::Write,
173{
174 pub fn from_stream(stream: W, dict_size: usize, memlimit: usize) -> Self {
175 lzma_info!("Dict size in LZ buffer: {}", dict_size);
176 Self {
177 stream,
178 buf: Vec::new(),
179 dict_size,
180 memlimit,
181 cursor: 0,
182 len: 0,
183 }
184 }
185
186 fn get(&self, index: usize) -> u8 {
187 *self.buf.get(index).unwrap_or(&0)
188 }
189
190 fn set(&mut self, index: usize, value: u8) -> error::Result<()> {
191 let new_len = index + 1;
192
193 if self.buf.len() < new_len {
194 if new_len <= self.memlimit {
195 self.buf.resize(new_len, 0);
196 } else {
197 return Err(error::Error::LzmaError(format!(
198 "exceeded memory limit of {}",
199 self.memlimit
200 )));
201 }
202 }
203 self.buf[index] = value;
204 Ok(())
205 }
206}
207
208impl<W> LzBuffer<W> for LzCircularBuffer<W>
209where
210 W: io::Write,
211{
212 fn len(&self) -> usize {
213 self.len
214 }
215
216 fn last_or(&self, lit: u8) -> u8 {
218 if self.len == 0 {
219 lit
220 } else {
221 self.get((self.dict_size + self.cursor - 1) % self.dict_size)
222 }
223 }
224
225 fn last_n(&self, dist: usize) -> error::Result<u8> {
227 if dist > self.dict_size {
228 return Err(error::Error::LzmaError(format!(
229 "Match distance {} is beyond dictionary size {}",
230 dist, self.dict_size
231 )));
232 }
233 if dist > self.len {
234 return Err(error::Error::LzmaError(format!(
235 "Match distance {} is beyond output size {}",
236 dist, self.len
237 )));
238 }
239
240 let offset = (self.dict_size + self.cursor - dist) % self.dict_size;
241 Ok(self.get(offset))
242 }
243
244 fn append_literal(&mut self, lit: u8) -> error::Result<()> {
246 self.set(self.cursor, lit)?;
247 self.cursor += 1;
248 self.len += 1;
249
250 if self.cursor == self.dict_size {
252 self.stream.write_all(self.buf.as_slice())?;
253 self.cursor = 0;
254 }
255
256 Ok(())
257 }
258
259 fn append_lz(&mut self, len: usize, dist: usize) -> error::Result<()> {
261 lzma_debug!("LZ {{ len: {}, dist: {} }}", len, dist);
262 if dist > self.dict_size {
263 return Err(error::Error::LzmaError(format!(
264 "LZ distance {} is beyond dictionary size {}",
265 dist, self.dict_size
266 )));
267 }
268 if dist > self.len {
269 return Err(error::Error::LzmaError(format!(
270 "LZ distance {} is beyond output size {}",
271 dist, self.len
272 )));
273 }
274
275 let mut offset = (self.dict_size + self.cursor - dist) % self.dict_size;
276 for _ in 0..len {
277 let x = self.get(offset);
278 self.append_literal(x)?;
279 offset += 1;
280 if offset == self.dict_size {
281 offset = 0
282 }
283 }
284 Ok(())
285 }
286
287 fn get_output(&self) -> &W {
289 &self.stream
290 }
291
292 fn get_output_mut(&mut self) -> &mut W {
294 &mut self.stream
295 }
296
297 fn finish(mut self) -> io::Result<W> {
299 if self.cursor > 0 {
300 self.stream.write_all(&self.buf[0..self.cursor])?;
301 self.stream.flush()?;
302 }
303 Ok(self.stream)
304 }
305
306 fn into_output(self) -> W {
308 self.stream
309 }
310}