1use std::error;
4use std::fmt;
5use std::marker;
6use std::mem;
7
8use core::ffi::{c_int, c_uint};
9
10use crate::{ffi, Compression};
11
12pub struct Compress {
16 inner: Stream<DirCompress>,
17}
18
19pub struct Decompress {
24 inner: Stream<DirDecompress>,
25}
26
27struct Stream<D: Direction> {
28 raw: Box<ffi::bz_stream>,
30 _marker: marker::PhantomData<D>,
31}
32
33unsafe impl<D: Direction> Send for Stream<D> {}
34unsafe impl<D: Direction> Sync for Stream<D> {}
35
36trait Direction {
37 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int;
38}
39
40enum DirCompress {}
41enum DirDecompress {}
42
43#[derive(PartialEq, Eq, Copy, Debug, Clone)]
45pub enum Action {
46 Run = ffi::BZ_RUN as isize,
48 Flush = ffi::BZ_FLUSH as isize,
50 Finish = ffi::BZ_FINISH as isize,
52}
53
54#[derive(PartialEq, Eq, Copy, Debug, Clone)]
56pub enum Status {
57 Ok,
59
60 FlushOk,
62
63 RunOk,
65
66 FinishOk,
68
69 StreamEnd,
71
72 MemNeeded,
75}
76
77#[derive(PartialEq, Eq, Copy, Debug, Clone)]
82pub enum Error {
83 Sequence,
86
87 Data,
90
91 DataMagic,
93
94 Param,
96}
97
98impl Compress {
99 pub fn new(lvl: Compression, work_factor: u32) -> Self {
120 unsafe {
121 let mut raw = Box::new(mem::zeroed());
122 assert_eq!(
123 ffi::BZ2_bzCompressInit(&mut *raw, lvl.level() as c_int, 0, work_factor as c_int),
124 0
125 );
126 Self {
127 inner: Stream {
128 raw,
129 _marker: marker::PhantomData,
130 },
131 }
132 }
133 }
134
135 unsafe fn compress_inner(
136 &mut self,
137 input: &[u8],
138 output_ptr: *mut u8,
139 output_len: usize,
140 action: Action,
141 ) -> Result<Status, Error> {
142 if input.is_empty() && action == Action::Run {
146 return Ok(Status::RunOk);
147 }
148 self.inner.raw.next_in = input.as_ptr() as *mut _;
149 self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
150 self.inner.raw.next_out = output_ptr as *mut _;
151 self.inner.raw.avail_out = output_len.min(c_uint::MAX as usize) as c_uint;
152 unsafe {
153 match ffi::BZ2_bzCompress(&mut *self.inner.raw, action as c_int) {
154 ffi::BZ_RUN_OK => Ok(Status::RunOk),
155 ffi::BZ_FLUSH_OK => Ok(Status::FlushOk),
156 ffi::BZ_FINISH_OK => Ok(Status::FinishOk),
157 ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
158 ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
159 c => panic!("unknown return status: {c}"),
160 }
161 }
162 }
163
164 pub fn compress(
172 &mut self,
173 input: &[u8],
174 output: &mut [u8],
175 action: Action,
176 ) -> Result<Status, Error> {
177 unsafe { self.compress_inner(input, output.as_mut_ptr(), output.len(), action) }
178 }
179
180 pub fn compress_uninit(
182 &mut self,
183 input: &[u8],
184 output: &mut [mem::MaybeUninit<u8>],
185 action: Action,
186 ) -> Result<Status, Error> {
187 unsafe { self.compress_inner(input, output.as_mut_ptr() as *mut _, output.len(), action) }
188 }
189
190 pub fn compress_vec(
196 &mut self,
197 input: &[u8],
198 output: &mut Vec<u8>,
199 action: Action,
200 ) -> Result<Status, Error> {
201 let len = output.len();
202
203 unsafe {
204 let before = self.total_out();
205 let ret = self.compress_uninit(input, output.spare_capacity_mut(), action);
206 output.set_len((self.total_out() - before) as usize + len);
207
208 ret
209 }
210 }
211
212 pub fn total_in(&self) -> u64 {
214 self.inner.total_in()
215 }
216
217 pub fn total_out(&self) -> u64 {
219 self.inner.total_out()
220 }
221}
222
223impl Decompress {
224 pub fn new(small: bool) -> Self {
231 unsafe {
232 let mut raw = Box::new(mem::zeroed());
233 assert_eq!(ffi::BZ2_bzDecompressInit(&mut *raw, 0, small as c_int), 0);
234 Self {
235 inner: Stream {
236 raw,
237 _marker: marker::PhantomData,
238 },
239 }
240 }
241 }
242
243 unsafe fn decompress_inner(
244 &mut self,
245 input: &[u8],
246 output_ptr: *mut u8,
247 output_len: usize,
248 ) -> Result<Status, Error> {
249 self.inner.raw.next_in = input.as_ptr() as *mut _;
250 self.inner.raw.avail_in = input.len().min(c_uint::MAX as usize) as c_uint;
251 self.inner.raw.next_out = output_ptr as *mut _;
252 self.inner.raw.avail_out = output_len.min(c_uint::MAX as usize) as c_uint;
253 unsafe {
254 match ffi::BZ2_bzDecompress(&mut *self.inner.raw) {
255 ffi::BZ_OK => Ok(Status::Ok),
256 ffi::BZ_MEM_ERROR => Ok(Status::MemNeeded),
257 ffi::BZ_STREAM_END => Ok(Status::StreamEnd),
258 ffi::BZ_PARAM_ERROR => Err(Error::Param),
259 ffi::BZ_DATA_ERROR => Err(Error::Data),
260 ffi::BZ_DATA_ERROR_MAGIC => Err(Error::DataMagic),
261 ffi::BZ_SEQUENCE_ERROR => Err(Error::Sequence),
262 c => panic!("wut: {c}"),
263 }
264 }
265 }
266
267 pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Status, Error> {
269 unsafe { self.decompress_inner(input, output.as_mut_ptr(), output.len()) }
270 }
271
272 pub fn decompress_uninit(
274 &mut self,
275 input: &[u8],
276 output: &mut [mem::MaybeUninit<u8>],
277 ) -> Result<Status, Error> {
278 unsafe { self.decompress_inner(input, output.as_mut_ptr() as *mut _, output.len()) }
279 }
280
281 pub fn decompress_vec(&mut self, input: &[u8], output: &mut Vec<u8>) -> Result<Status, Error> {
287 let len = output.len();
288
289 unsafe {
290 let before = self.total_out();
291 let ret = self.decompress_uninit(input, output.spare_capacity_mut());
292 output.set_len((self.total_out() - before) as usize + len);
293
294 ret
295 }
296 }
297
298 pub fn total_in(&self) -> u64 {
300 self.inner.total_in()
301 }
302
303 pub fn total_out(&self) -> u64 {
305 self.inner.total_out()
306 }
307}
308
309impl<D: Direction> Stream<D> {
310 fn total_in(&self) -> u64 {
311 (self.raw.total_in_lo32 as u64) | ((self.raw.total_in_hi32 as u64) << 32)
312 }
313
314 fn total_out(&self) -> u64 {
315 (self.raw.total_out_lo32 as u64) | ((self.raw.total_out_hi32 as u64) << 32)
316 }
317}
318
319impl error::Error for Error {}
320
321impl fmt::Display for Error {
322 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
323 let description = match self {
324 Self::Sequence => "bzip2: sequence of operations invalid",
325 Self::Data => "bzip2: invalid data",
326 Self::DataMagic => "bzip2: bz2 header missing",
327 Self::Param => "bzip2: invalid parameters",
328 };
329 f.write_str(description)
330 }
331}
332
333impl From<Error> for std::io::Error {
334 fn from(data: Error) -> Self {
335 Self::other(data)
336 }
337}
338
339impl Direction for DirCompress {
340 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
341 ffi::BZ2_bzCompressEnd(stream)
342 }
343}
344impl Direction for DirDecompress {
345 unsafe fn destroy(stream: *mut ffi::bz_stream) -> c_int {
346 ffi::BZ2_bzDecompressEnd(stream)
347 }
348}
349
350impl<D: Direction> Drop for Stream<D> {
351 fn drop(&mut self) {
352 unsafe {
353 let _ = D::destroy(&mut *self.raw);
354 }
355 }
356}