Skip to main content

async_compression_issue_150_workaround/codec/brotli/
decoder.rs

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