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
extern crate xz_embedded_sys as raw;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
pub struct XZError {
msg: &'static str,
code: Option<raw::XZRawError>
}
impl Error for XZError {
fn description(&self) -> &str { self.msg }
fn cause<'a>(&'a self) -> Option<&'a Error> {
if let Some(ref e) = self.code {
Some(e)
} else {
None
}
}
}
impl fmt::Display for XZError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
pub fn decompress(compressed_data: &[u8]) -> Result<Vec<u8>, XZError> {
unsafe {
raw::xz_crc32_init();
raw::xz_crc64_init();
}
let state = unsafe {
raw::xz_dec_init(raw::xz_mode::XZ_DYNALLOC, 1 << 26)
};
if state.is_null() {
return Err(XZError{msg: "Failed to initialize", code: None});
}
let mut out_vec = Vec::new();
let out_size = 4096;
let mut out_buf = Vec::with_capacity(out_size);
out_buf.resize(out_size, 0);
let mut buf = raw::xz_buf {
_in: compressed_data.as_ptr(),
in_size: compressed_data.len() as u64,
in_pos:0,
out: out_buf.as_mut_ptr(),
out_pos: 0,
out_size: out_size as u64,
};
loop {
let ret = unsafe { raw::xz_dec_run(state, &mut buf) };
if ret == raw::xz_ret::XZ_OK {
out_vec.extend(&out_buf[0..(buf.out_pos as usize)]);
buf.out_pos = 0;
} else if ret == raw::xz_ret::XZ_STREAM_END {
out_vec.extend(&out_buf[0..(buf.out_pos as usize)]);
break;
} else {
return Err(XZError{msg: "Decompressing error", code: Some(raw::XZRawError::from(ret))})
}
if buf.in_pos == buf.in_size {
return Err(XZError{msg: "Reached end of input buffer", code: None})
}
}
unsafe { raw::xz_dec_end(state) };
Ok(out_vec)
}