compression_codecs/brotli/
decoder.rs

1use crate::DecodeV2;
2use brotli::{enc::StandardAlloc, BrotliDecompressStream, BrotliResult};
3use compression_core::util::{PartialBuffer, WriteBuffer};
4use std::{fmt, io};
5
6type BrotliState = brotli::BrotliState<StandardAlloc, StandardAlloc, StandardAlloc>;
7
8pub struct BrotliDecoder {
9    // `BrotliState` is very large (over 2kb) which is why we're boxing it.
10    state: Box<BrotliState>,
11}
12
13impl Default for BrotliDecoder {
14    fn default() -> Self {
15        Self {
16            state: Box::new(Self::new_brotli_state()),
17        }
18    }
19}
20
21impl BrotliDecoder {
22    fn new_brotli_state() -> BrotliState {
23        BrotliState::new(
24            StandardAlloc::default(),
25            StandardAlloc::default(),
26            StandardAlloc::default(),
27        )
28    }
29
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    fn decode(
35        &mut self,
36        input: &mut PartialBuffer<&[u8]>,
37        output: &mut WriteBuffer<'_>,
38    ) -> io::Result<BrotliResult> {
39        let in_buf = input.unwritten();
40        let out_buf = output.initialize_unwritten();
41
42        let mut input_len = 0;
43        let mut output_len = 0;
44
45        let result = match BrotliDecompressStream(
46            &mut in_buf.len(),
47            &mut input_len,
48            in_buf,
49            &mut out_buf.len(),
50            &mut output_len,
51            out_buf,
52            &mut 0,
53            &mut self.state,
54        ) {
55            BrotliResult::ResultFailure => Err(io::Error::other("brotli error")),
56            status => Ok(status),
57        };
58
59        input.advance(input_len);
60        output.advance(output_len);
61
62        result
63    }
64}
65
66impl DecodeV2 for BrotliDecoder {
67    fn reinit(&mut self) -> io::Result<()> {
68        *self.state = Self::new_brotli_state();
69        Ok(())
70    }
71
72    fn decode(
73        &mut self,
74        input: &mut PartialBuffer<&[u8]>,
75        output: &mut WriteBuffer<'_>,
76    ) -> io::Result<bool> {
77        match self.decode(input, output)? {
78            BrotliResult::ResultSuccess => Ok(true),
79            BrotliResult::NeedsMoreOutput | BrotliResult::NeedsMoreInput => Ok(false),
80            BrotliResult::ResultFailure => unreachable!(),
81        }
82    }
83
84    fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
85        match self.decode(&mut PartialBuffer::new(&[][..]), output)? {
86            BrotliResult::ResultSuccess | BrotliResult::NeedsMoreInput => Ok(true),
87            BrotliResult::NeedsMoreOutput => Ok(false),
88            BrotliResult::ResultFailure => unreachable!(),
89        }
90    }
91
92    fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
93        match self.decode(&mut PartialBuffer::new(&[][..]), output)? {
94            BrotliResult::ResultSuccess => Ok(true),
95            BrotliResult::NeedsMoreOutput => Ok(false),
96            BrotliResult::NeedsMoreInput => Err(io::Error::new(
97                io::ErrorKind::UnexpectedEof,
98                "reached unexpected EOF",
99            )),
100            BrotliResult::ResultFailure => unreachable!(),
101        }
102    }
103}
104
105impl fmt::Debug for BrotliDecoder {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.debug_struct("BrotliDecoder")
108            .field("decompress", &"<no debug>")
109            .finish()
110    }
111}