1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::io::{self, Read};
use std::ops::Drop;
use lzma_sys::*;
use std;
use error::LzmaError;
use ::Direction;
use lzma_stream_wrapper::LzmaStreamWrapper;
const DEFAULT_BUF_SIZE: usize = 4 * 1024;
pub struct LzmaReader<T> {
inner: T,
stream: LzmaStreamWrapper,
buffer: Vec<u8>,
buffer_offset: usize,
buffer_len: usize,
direction: Direction,
}
impl<T: Read> LzmaReader<T> {
pub fn new_compressor(inner: T, preset: u32) -> Result<LzmaReader<T>, LzmaError> {
LzmaReader::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Compress, preset)
}
pub fn new_decompressor(inner: T) -> Result<LzmaReader<T>, LzmaError> {
LzmaReader::with_capacity(DEFAULT_BUF_SIZE, inner, Direction::Decompress, 0)
}
pub fn with_capacity(capacity: usize, inner: T, direction: Direction, preset: u32) -> Result<LzmaReader<T>, LzmaError> {
let mut reader = LzmaReader {
inner: inner,
stream: LzmaStreamWrapper::new(),
buffer: vec![0; capacity],
buffer_offset: 0,
buffer_len: 0,
direction: direction,
};
match reader.direction {
Direction::Compress => {
try!(reader.stream.easy_encoder(preset, lzma_check::LZMA_CHECK_CRC64))
},
Direction::Decompress => {
try!(reader.stream.stream_decoder(std::u64::MAX, 0))
},
}
Ok(reader)
}
}
impl<T> Drop for LzmaReader<T> {
fn drop(&mut self) {
self.stream.end()
}
}
impl<R: Read> Read for LzmaReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if buf.len() == 0 {
return Ok(0);
}
loop {
let mut action = lzma_action::LZMA_RUN;
if self.buffer_len == 0 {
self.buffer_offset = 0;
self.buffer_len = try!(self.inner.read(&mut self.buffer));
if self.buffer_len == 0 {
action = lzma_action::LZMA_FINISH;
}
}
let result = self.stream.code(&self.buffer[self.buffer_offset..(self.buffer_offset+self.buffer_len)], buf, action);
self.buffer_offset += result.bytes_read;
self.buffer_len -= result.bytes_read;
let stream_end = match result.ret {
Ok(lzma_ret::LZMA_STREAM_END) => true,
Ok(_) => false,
Err(err) => return Err(io::Error::new(io::ErrorKind::Other, err)),
};
if stream_end || result.bytes_written > 0 {
return Ok(result.bytes_written);
}
}
}
}