compression/gzip/
encoder.rs1use crate::action::Action;
9use crate::core::borrow::BorrowMut;
10use crate::core::hash::{BuildHasher, Hasher};
11use crate::core::marker::PhantomData;
12use crate::core::mem;
13use crate::crc32::{BuiltinDigest, IEEE_REVERSE};
14use crate::deflate::encoder::Inflater;
15use crate::error::CompressionError;
16use crate::traits::encoder::Encoder;
17
18struct ScanIterator<I: Iterator, BI: BorrowMut<I>, F: FnMut(&I::Item) -> ()> {
19 phantom: PhantomData<I>,
20 inner: BI,
21 closure: F,
22}
23
24impl<I: Iterator, BI: BorrowMut<I>, F: FnMut(&I::Item) -> ()> Iterator
25 for ScanIterator<I, BI, F>
26{
27 type Item = I::Item;
28 fn next(&mut self) -> Option<I::Item> {
29 let ret = self.inner.borrow_mut().next();
30 if let Some(ref s) = ret {
31 (self.closure)(s);
32 }
33 ret
34 }
35}
36
37impl<I: Iterator, BI: BorrowMut<I>, F: FnMut(&I::Item) -> ()>
38 ScanIterator<I, BI, F>
39{
40 pub(crate) fn new(inner: BI, closure: F) -> Self {
41 Self {
42 inner,
43 closure,
44 phantom: PhantomData,
45 }
46 }
47}
48
49#[derive(Debug)]
50pub struct GZipEncoder {
51 inflater: Inflater,
52 crc32: Option<BuiltinDigest>,
53 header_len: u8,
54 header: [u8; 10],
55 hash: Option<u32>,
56 hashlen: u8,
57 i_size_len: u8,
58 i_size: u32,
59}
60
61impl Default for GZipEncoder {
62 fn default() -> Self {
63 Self::new()
64 }
65}
66
67impl GZipEncoder {
68 pub fn new() -> Self {
69 Self {
70 inflater: Inflater::new(),
71 crc32: Some(IEEE_REVERSE.build_hasher()),
72 header: [
73 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
74 ],
75 header_len: 10,
76 hash: None,
77 hashlen: 3,
78 i_size: 0,
79 i_size_len: 4,
80 }
81 }
82}
83
84impl Encoder for GZipEncoder {
85 type Error = CompressionError;
86 type In = u8;
87 type Out = u8;
88 fn next<I: Iterator<Item = u8>>(
89 &mut self,
90 iter: &mut I,
91 action: Action,
92 ) -> Option<Result<u8, CompressionError>> {
93 let hlen = self.header_len;
94 if hlen > 0 {
95 let hlen_all = self.header.len();
96 self.header_len = hlen - 1;
97 Some(Ok(self.header[hlen_all - hlen as usize]))
98 } else if let Some(hash) = self.hash {
99 if self.hashlen == 0 {
100 if self.i_size_len == 0 {
101 None
102 } else {
103 self.i_size_len -= 1;
104 let ret = self.i_size as u8;
105 self.i_size >>= 8;
106 Some(Ok(ret))
107 }
108 } else {
109 self.hashlen -= 1;
110 self.hash = Some(hash >> 8);
111 Some(Ok(hash as u8))
112 }
113 } else {
114 let mut crc32 = mem::replace(&mut self.crc32, None);
115 let mut i_size = self.i_size;
116 let ret = self.inflater.next(
117 &mut ScanIterator::<I, _, _>::new(iter, |x: &u8| {
118 crc32.as_mut().unwrap().write_u8(*x);
119 i_size += 1;
120 }),
121 action,
122 );
123 self.i_size = i_size;
124 let _ = mem::replace(&mut self.crc32, crc32);
125 if ret.is_none() {
126 let hash = self.crc32.as_mut().unwrap().finish() as u32;
127 let ret = hash as u8;
128 self.hash = Some(hash >> 8);
129 Some(Ok(ret))
130 } else {
131 ret
132 }
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::traits::encoder::EncodeExt;
141 #[cfg(not(feature = "std"))]
142 #[allow(unused_imports)]
143 use alloc::vec;
144 #[cfg(not(feature = "std"))]
145 use alloc::vec::Vec;
146
147 #[test]
148 fn test_unit() {
149 let mut encoder = GZipEncoder::new();
150 let ret = b"a"
151 .iter()
152 .cloned()
153 .encode(&mut encoder, Action::Finish)
154 .collect::<Result<Vec<_>, _>>();
155
156 assert_eq!(
157 ret,
158 Ok(vec![
159 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
160 0x4b, 0x04, 0x00, 0x43, 0xbe, 0xb7, 0xe8, 0x01, 0x00, 0x00,
161 0x00,
162 ])
163 );
164 }
165}