1use std::error;
4use std::fmt;
5use std::marker;
6use std::mem;
7use std::slice;
8
9use libc::{c_int, c_uint};
10
11use {ffi, Compression};
12
13pub struct Compress {
17 inner: Stream<DirCompress>,
18}
19
20pub struct Decompress {
25 inner: Stream<DirDecompress>,
26}
27
28struct Stream<D: Direction> {
29 raw: Box<ffi::bz_stream>,
31 _marker: marker::PhantomData<D>,
32}
33
34unsafe impl<D: Direction> Send for Stream<D> {}
35unsafe impl<D: Direction> Sync for Stream<D> {}
36
37trait Direction {
38 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int;
39}
40
41enum DirCompress {}
42enum DirDecompress {}
43
44#[derive(PartialEq, Eq, Copy, Debug, Clone)]
46pub enum Action {
47 Run = ffi::BZ_RUN as isize,
49 Flush = ffi::BZ_FLUSH as isize,
51 Finish = ffi::BZ_FINISH as isize,
53}
54
55#[derive(PartialEq, Eq, Copy, Debug, Clone)]
57pub enum Status {
58 Ok,
60
61 FlushOk,
63
64 RunOk,
66
67 FinishOk,
69
70 StreamEnd,
72
73 MemNeeded,
76}
77
78#[derive(PartialEq, Eq, Copy, Debug, Clone)]
83pub enum Error {
84 Sequence,
87
88 Data,
91
92 DataMagic,
94
95 Param,
97}
98
99impl Compress {
100 pub fn new(lvl: Compression, work_factor: u32) -> Compress {
121 unsafe {
122 let mut raw = Box::new(mem::zeroed());
123 assert_eq!(
124 ffi::BZ2_bzCompressInit(&mut *raw, lvl.level() as c_int, 0, work_factor as c_int),
125 0
126 );
127 Compress {
128 inner: Stream {
129 raw: raw,
130 _marker: marker::PhantomData,
131 },
132 }
133 }
134 }
135
136 pub fn compress(
141 &mut self,
142 input: &[u8],
143 output: &mut [u8],
144 action: Action,
145 ) -> Result<Status, Error> {
146 if input.len() == 0 && action == Action::Run {
150 return Ok(Status::RunOk);
151 }
152 self.inner.raw.next_in = input.as_ptr() as *mut _;
153 self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
154 self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
155 self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
156 unsafe {
157 match ffi::BZ2_bzCompress(&mut *self.inner.raw, action as c_int) {
158 ffi::BZ_RUN_OK => Ok(Status::RunOk),
159 ffi::BZ_FLUSH_OK => Ok(Status::FlushOk),
160 ffi::BZ_FINISH_OK => Ok(Status::FinishOk),
161 ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
162 ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
163 c => panic!("unknown return status: {}", c),
164 }
165 }
166 }
167
168 pub fn compress_vec(
174 &mut self,
175 input: &[u8],
176 output: &mut Vec<u8>,
177 action: Action,
178 ) -> Result<Status, Error> {
179 let cap = output.capacity();
180 let len = output.len();
181
182 unsafe {
183 let before = self.total_out();
184 let ret = {
185 let ptr = output.as_mut_ptr().offset(len as isize);
186 let out = slice::from_raw_parts_mut(ptr, cap - len);
187 self.compress(input, out, action)
188 };
189 output.set_len((self.total_out() - before) as usize + len);
190 return ret;
191 }
192 }
193
194 pub fn total_in(&self) -> u64 {
196 self.inner.total_in()
197 }
198
199 pub fn total_out(&self) -> u64 {
201 self.inner.total_out()
202 }
203}
204
205impl Decompress {
206 pub fn new(small: bool) -> Decompress {
213 unsafe {
214 let mut raw = Box::new(mem::zeroed());
215 assert_eq!(ffi::BZ2_bzDecompressInit(&mut *raw, 0, small as c_int), 0);
216 Decompress {
217 inner: Stream {
218 raw: raw,
219 _marker: marker::PhantomData,
220 },
221 }
222 }
223 }
224
225 pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Status, Error> {
227 self.inner.raw.next_in = input.as_ptr() as *mut _;
228 self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
229 self.inner.raw.next_out = output.as_mut_ptr() as *mut _;
230 self.inner.raw.avail_out = output.len().min(c_uint::MAX as usize) as c_uint;
231 unsafe {
232 match ffi::BZ2_bzDecompress(&mut *self.inner.raw) {
233 ffi::BZ_OK => Ok(Status::Ok),
234 ffi::BZ_MEM_ERROR => Ok(Status::MemNeeded),
235 ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
236 ffi::BZ_PARAM_ERROR => Err(Error::Param),
237 ffi::BZ_DATA_ERROR => Err(Error::Data),
238 ffi::BZ_DATA_ERROR_MAGIC => Err(Error::DataMagic),
239 ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
240 c => panic!("wut: {}", c),
241 }
242 }
243 }
244
245 pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>) -> Result<Status, Error> {
251 let cap = output.capacity();
252 let len = output.len();
253
254 unsafe {
255 let before = self.total_out();
256 let ret = {
257 let ptr = output.as_mut_ptr().offset(len as isize);
258 let out = slice::from_raw_parts_mut(ptr, cap - len);
259 self.decompress(input, out)
260 };
261 output.set_len((self.total_out() - before) as usize + len);
262 return ret;
263 }
264 }
265
266 pub fn total_in(&self) -> u64 {
268 self.inner.total_in()
269 }
270
271 pub fn total_out(&self) -> u64 {
273 self.inner.total_out()
274 }
275}
276
277impl<D: Direction> Stream<D> {
278 fn total_in(&self) -> u64 {
279 (self.raw.total_in_lo32 as u64) | ((self.raw.total_in_hi32 as u64) << 32)
280 }
281
282 fn total_out(&self) -> u64 {
283 (self.raw.total_out_lo32 as u64) | ((self.raw.total_out_hi32 as u64) << 32)
284 }
285}
286
287impl error::Error for Error {}
288
289impl fmt::Display for Error {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
291 let description = match self {
292 Error::Sequence => "bzip2: sequence of operations invalid",
293 Error::Data => "bzip2: invalid data",
294 Error::DataMagic => "bzip2: bz2 header missing",
295 Error::Param => "bzip2: invalid parameters",
296 };
297 f.write_str(description)
298 }
299}
300
301impl From<Error> for std::io::Error {
302 fn from(data: Error) -> std::io::Error {
303 std::io::Error::new(std::io::ErrorKind::Other, data)
304 }
305}
306
307impl Direction for DirCompress {
308 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
309 ffi::BZ2_bzCompressEnd(stream)
310 }
311}
312impl Direction for DirDecompress {
313 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
314 ffi::BZ2_bzDecompressEnd(stream)
315 }
316}
317
318impl<D: Direction> Drop for Stream<D> {
319 fn drop(&mut self) {
320 unsafe {
321 let _ = D::destroy(&mut *self.raw);
322 }
323 }
324}