compression_codecs/gzip/
encoder.rs1use crate::{flate::params::FlateEncoderParams, EncodeV2, FlateEncoder};
2use compression_core::util::{PartialBuffer, WriteBuffer};
3use flate2::{Compression, Crc};
4use std::io;
5
6#[derive(Debug)]
7enum State {
8 Header(PartialBuffer<Vec<u8>>),
9 Encoding,
10 Footer(PartialBuffer<Vec<u8>>),
11 Done,
12}
13
14#[derive(Debug)]
15pub struct GzipEncoder {
16 inner: FlateEncoder,
17 crc: Crc,
18 state: State,
19}
20
21fn header(level: Compression) -> Vec<u8> {
22 let level_byte = if level.level() >= Compression::best().level() {
23 0x02
24 } else if level.level() <= Compression::fast().level() {
25 0x04
26 } else {
27 0x00
28 };
29
30 vec![0x1f, 0x8b, 0x08, 0, 0, 0, 0, 0, level_byte, 0xff]
31}
32
33impl GzipEncoder {
34 pub fn new(level: FlateEncoderParams) -> Self {
35 Self {
36 inner: FlateEncoder::new(level.clone(), false),
37 crc: Crc::new(),
38 state: State::Header(header(Compression::from(level)).into()),
39 }
40 }
41
42 fn footer(&mut self) -> Vec<u8> {
43 let mut output = Vec::with_capacity(8);
44
45 output.extend(&self.crc.sum().to_le_bytes());
46 output.extend(&self.crc.amount().to_le_bytes());
47
48 output
49 }
50}
51
52impl EncodeV2 for GzipEncoder {
53 fn encode(
54 &mut self,
55 input: &mut PartialBuffer<&[u8]>,
56 output: &mut WriteBuffer<'_>,
57 ) -> io::Result<()> {
58 loop {
59 match &mut self.state {
60 State::Header(header) => {
61 output.copy_unwritten_from(&mut *header);
62
63 if header.unwritten().is_empty() {
64 self.state = State::Encoding;
65 }
66 }
67
68 State::Encoding => {
69 let prior_written = input.written().len();
70 self.inner.encode(input, output)?;
71 self.crc.update(&input.written()[prior_written..]);
72 }
73
74 State::Footer(_) | State::Done => {
75 return Err(io::Error::other("encode after complete"));
76 }
77 };
78
79 if input.unwritten().is_empty() || output.has_no_spare_space() {
80 return Ok(());
81 }
82 }
83 }
84
85 fn flush(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
86 loop {
87 let done = match &mut self.state {
88 State::Header(header) => {
89 output.copy_unwritten_from(&mut *header);
90
91 if header.unwritten().is_empty() {
92 self.state = State::Encoding;
93 }
94 false
95 }
96
97 State::Encoding => self.inner.flush(output)?,
98
99 State::Footer(footer) => {
100 output.copy_unwritten_from(&mut *footer);
101
102 if footer.unwritten().is_empty() {
103 self.state = State::Done;
104 true
105 } else {
106 false
107 }
108 }
109
110 State::Done => true,
111 };
112
113 if done {
114 return Ok(true);
115 }
116
117 if output.has_no_spare_space() {
118 return Ok(false);
119 }
120 }
121 }
122
123 fn finish(&mut self, output: &mut WriteBuffer<'_>) -> io::Result<bool> {
124 loop {
125 match &mut self.state {
126 State::Header(header) => {
127 output.copy_unwritten_from(&mut *header);
128
129 if header.unwritten().is_empty() {
130 self.state = State::Encoding;
131 }
132 }
133
134 State::Encoding => {
135 if self.inner.finish(output)? {
136 self.state = State::Footer(self.footer().into());
137 }
138 }
139
140 State::Footer(footer) => {
141 output.copy_unwritten_from(&mut *footer);
142
143 if footer.unwritten().is_empty() {
144 self.state = State::Done;
145 }
146 }
147
148 State::Done => {}
149 };
150
151 if let State::Done = self.state {
152 return Ok(true);
153 }
154
155 if output.has_no_spare_space() {
156 return Ok(false);
157 }
158 }
159 }
160}