compression_codecs/brotli/
decoder.rs1use 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 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}