compression_codecs/bzip2/
decoder.rs

1use crate::DecodeV2;
2use bzip2::{Decompress, Status};
3use compression_core::util::{PartialBuffer, WriteBuffer};
4use std::{fmt, io};
5
6pub struct BzDecoder {
7    decompress: Decompress,
8    stream_ended: bool,
9}
10
11impl fmt::Debug for BzDecoder {
12    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13        write!(
14            f,
15            "BzDecoder {{total_in: {}, total_out: {}}}",
16            self.decompress.total_in(),
17            self.decompress.total_out()
18        )
19    }
20}
21
22impl Default for BzDecoder {
23    fn default() -> Self {
24        Self {
25            decompress: Decompress::new(false),
26            stream_ended: false,
27        }
28    }
29}
30
31impl BzDecoder {
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    fn decode(
37        &mut self,
38        input: &mut PartialBuffer<&[u8]>,
39        output: &mut WriteBuffer<'_>,
40    ) -> io::Result<Status> {
41        let prior_in = self.decompress.total_in();
42        let prior_out = self.decompress.total_out();
43
44        let result = self
45            .decompress
46            .decompress(input.unwritten(), output.initialize_unwritten())
47            .map_err(io::Error::other);
48
49        input.advance((self.decompress.total_in() - prior_in) as usize);
50        output.advance((self.decompress.total_out() - prior_out) as usize);
51
52        // Track when stream has properly ended
53        if matches!(result, Ok(Status::StreamEnd)) {
54            self.stream_ended = true;
55        }
56
57        result
58    }
59}
60
61impl DecodeV2 for BzDecoder {
62    fn reinit(&mut self) -> io::Result<()> {
63        self.decompress = Decompress::new(false);
64        self.stream_ended = false;
65        Ok(())
66    }
67
68    fn decode(
69        &mut self,
70        input: &mut PartialBuffer<&[u8]>,
71        output: &mut WriteBuffer<'_>,
72    ) -> io::Result<bool> {
73        match self.decode(input, output)? {
74            // Decompression went fine, nothing much to report.
75            Status::Ok => Ok(false),
76
77            // The Flush action on a compression went ok.
78            Status::FlushOk => unreachable!(),
79
80            // THe Run action on compression went ok.
81            Status::RunOk => unreachable!(),
82
83            // The Finish action on compression went ok.
84            Status::FinishOk => unreachable!(),
85
86            // The stream's end has been met, meaning that no more data can be input.
87            Status::StreamEnd => Ok(true),
88
89            // There was insufficient memory in the input or output buffer to complete
90            // the request, but otherwise everything went normally.
91            Status::MemNeeded => Err(io::ErrorKind::OutOfMemory.into()),
92        }
93    }
94
95    fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
96        self.decode(&mut PartialBuffer::new(&[][..]), output)?;
97
98        loop {
99            let old_len = output.written_len();
100            self.decode(&mut PartialBuffer::new(&[][..]), output)?;
101            if output.written_len() == old_len {
102                break;
103            }
104        }
105
106        Ok(!output.has_no_spare_space())
107    }
108
109    fn finish(&mut self, _output: &mut WriteBuffer<'_>) -> io::Result<bool> {
110        if self.stream_ended {
111            Ok(true)
112        } else {
113            Err(io::Error::new(
114                io::ErrorKind::UnexpectedEof,
115                "bzip2 stream did not finish",
116            ))
117        }
118    }
119}