1 use crate::{codec::Encode, util::PartialBuffer};
2 use std::{
3     fmt,
4     io::{Error, ErrorKind, Result},
5 };
6 
7 use brotli::enc::{
8     backward_references::BrotliEncoderParams,
9     encode::{
10         BrotliEncoderCompressStream, BrotliEncoderCreateInstance, BrotliEncoderHasMoreOutput,
11         BrotliEncoderIsFinished, BrotliEncoderOperation, BrotliEncoderStateStruct,
12     },
13     StandardAlloc,
14 };
15 
16 pub struct BrotliEncoder {
17     state: BrotliEncoderStateStruct<StandardAlloc>,
18 }
19 
20 impl BrotliEncoder {
new(params: BrotliEncoderParams) -> Self21     pub(crate) fn new(params: BrotliEncoderParams) -> Self {
22         let mut state = BrotliEncoderCreateInstance(StandardAlloc::default());
23         state.params = params;
24         Self { state }
25     }
26 
encode( &mut self, input: &mut PartialBuffer<impl AsRef<[u8]>>, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, op: BrotliEncoderOperation, ) -> Result<()>27     fn encode(
28         &mut self,
29         input: &mut PartialBuffer<impl AsRef<[u8]>>,
30         output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
31         op: BrotliEncoderOperation,
32     ) -> Result<()> {
33         let in_buf = input.unwritten();
34         let mut out_buf = output.unwritten_mut();
35 
36         let mut input_len = 0;
37         let mut output_len = 0;
38 
39         if BrotliEncoderCompressStream(
40             &mut self.state,
41             op,
42             &mut in_buf.len(),
43             in_buf,
44             &mut input_len,
45             &mut out_buf.len(),
46             &mut out_buf,
47             &mut output_len,
48             &mut None,
49             &mut |_, _, _, _| (),
50         ) <= 0
51         {
52             return Err(Error::new(ErrorKind::Other, "brotli error"));
53         }
54 
55         input.advance(input_len);
56         output.advance(output_len);
57 
58         Ok(())
59     }
60 }
61 
62 impl Encode for BrotliEncoder {
encode( &mut self, input: &mut PartialBuffer<impl AsRef<[u8]>>, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<()>63     fn encode(
64         &mut self,
65         input: &mut PartialBuffer<impl AsRef<[u8]>>,
66         output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
67     ) -> Result<()> {
68         self.encode(
69             input,
70             output,
71             BrotliEncoderOperation::BROTLI_OPERATION_PROCESS,
72         )
73     }
74 
flush( &mut self, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<bool>75     fn flush(
76         &mut self,
77         output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
78     ) -> Result<bool> {
79         self.encode(
80             &mut PartialBuffer::new(&[][..]),
81             output,
82             BrotliEncoderOperation::BROTLI_OPERATION_FLUSH,
83         )?;
84 
85         Ok(BrotliEncoderHasMoreOutput(&self.state) == 0)
86     }
87 
finish( &mut self, output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>, ) -> Result<bool>88     fn finish(
89         &mut self,
90         output: &mut PartialBuffer<impl AsRef<[u8]> + AsMut<[u8]>>,
91     ) -> Result<bool> {
92         self.encode(
93             &mut PartialBuffer::new(&[][..]),
94             output,
95             BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
96         )?;
97 
98         Ok(BrotliEncoderIsFinished(&self.state) == 1)
99     }
100 }
101 
102 impl fmt::Debug for BrotliEncoder {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result103     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104         f.debug_struct("BrotliEncoder")
105             .field("compress", &"<no debug>")
106             .finish()
107     }
108 }
109