1use crate::{BlockType, DeflateEncoder, Error, Options, Write};
2
3pub struct GzipEncoder<W: Write> {
11 deflate_encoder: Option<DeflateEncoder<W>>,
12 crc32_hasher: crc32fast::Hasher,
13 input_size: u32,
14}
15
16impl<W: Write> GzipEncoder<W> {
17 pub fn new(options: Options, btype: BlockType, mut sink: W) -> Result<Self, Error> {
20 static HEADER: &[u8] = &[
21 31, 139, 8, 0, 0, 0, 0, 0, 2, 3, ];
29
30 sink.write_all(HEADER)?;
31
32 Ok(Self {
33 deflate_encoder: Some(DeflateEncoder::new(options, btype, sink)),
34 crc32_hasher: crc32fast::Hasher::new(),
35 input_size: 0,
36 })
37 }
38
39 #[cfg(feature = "std")]
44 pub fn new_buffered(
45 options: Options,
46 btype: BlockType,
47 sink: W,
48 ) -> Result<std::io::BufWriter<Self>, Error> {
49 Ok(std::io::BufWriter::with_capacity(
50 crate::util::ZOPFLI_MASTER_BLOCK_SIZE,
51 Self::new(options, btype, sink)?,
52 ))
53 }
54
55 pub fn finish(mut self) -> Result<W, Error> {
64 self.__finish().map(|sink| sink.unwrap())
65 }
66
67 fn __finish(&mut self) -> Result<Option<W>, Error> {
68 if self.deflate_encoder.is_none() {
69 return Ok(None);
70 }
71
72 let mut sink = self.deflate_encoder.take().unwrap().finish()?;
73
74 sink.write_all(&self.crc32_hasher.clone().finalize().to_le_bytes())?;
75 sink.write_all(&self.input_size.to_le_bytes())?;
76
77 Ok(Some(sink))
78 }
79
80 pub fn get_ref(&self) -> &W {
82 self.deflate_encoder.as_ref().unwrap().get_ref()
83 }
84
85 pub fn get_mut(&mut self) -> &mut W {
90 self.deflate_encoder.as_mut().unwrap().get_mut()
91 }
92}
93
94impl<W: Write> Write for GzipEncoder<W> {
95 fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
96 self.deflate_encoder
97 .as_mut()
98 .unwrap()
99 .write(buf)
100 .map(|bytes_written| {
101 self.crc32_hasher.update(&buf[..bytes_written]);
102 self.input_size = self.input_size.wrapping_add(bytes_written as u32);
103 bytes_written
104 })
105 }
106
107 fn flush(&mut self) -> Result<(), Error> {
108 self.deflate_encoder.as_mut().unwrap().flush()
109 }
110}
111
112impl<W: Write> Drop for GzipEncoder<W> {
113 fn drop(&mut self) {
114 self.__finish().ok();
115 }
116}
117
118#[cfg(all(doc, feature = "std"))]
120impl<W: crate::io::Write> std::io::Write for GzipEncoder<W> {
121 fn write(&mut self, _buf: &[u8]) -> std::io::Result<usize> {
122 unimplemented!()
123 }
124
125 fn flush(&mut self) -> std::io::Result<()> {
126 unimplemented!()
127 }
128}