1 | //! Implementation for `miniz_oxide` rust backend. |
2 | |
3 | use std::convert::TryInto; |
4 | use std::fmt; |
5 | |
6 | use miniz_oxide::deflate::core::CompressorOxide; |
7 | use miniz_oxide::inflate::stream::InflateState; |
8 | pub use miniz_oxide::*; |
9 | |
10 | pub const MZ_NO_FLUSH: isize = MZFlush::None as isize; |
11 | pub const MZ_PARTIAL_FLUSH: isize = MZFlush::Partial as isize; |
12 | pub const MZ_SYNC_FLUSH: isize = MZFlush::Sync as isize; |
13 | pub const MZ_FULL_FLUSH: isize = MZFlush::Full as isize; |
14 | pub const MZ_FINISH: isize = MZFlush::Finish as isize; |
15 | |
16 | use super::*; |
17 | use crate::mem; |
18 | |
19 | // miniz_oxide doesn't provide any error messages (yet?) |
20 | #[derive (Clone, Default)] |
21 | pub struct ErrorMessage; |
22 | |
23 | impl ErrorMessage { |
24 | pub fn get(&self) -> Option<&str> { |
25 | None |
26 | } |
27 | } |
28 | |
29 | fn format_from_bool(zlib_header: bool) -> DataFormat { |
30 | if zlib_header { |
31 | DataFormat::Zlib |
32 | } else { |
33 | DataFormat::Raw |
34 | } |
35 | } |
36 | |
37 | pub struct Inflate { |
38 | inner: Box<InflateState>, |
39 | total_in: u64, |
40 | total_out: u64, |
41 | } |
42 | |
43 | impl fmt::Debug for Inflate { |
44 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
45 | write!( |
46 | f, |
47 | "miniz_oxide inflate internal state. total_in: {}, total_out: {}" , |
48 | self.total_in, self.total_out, |
49 | ) |
50 | } |
51 | } |
52 | |
53 | impl From<FlushDecompress> for MZFlush { |
54 | fn from(value: FlushDecompress) -> Self { |
55 | match value { |
56 | FlushDecompress::None => Self::None, |
57 | FlushDecompress::Sync => Self::Sync, |
58 | FlushDecompress::Finish => Self::Finish, |
59 | } |
60 | } |
61 | } |
62 | |
63 | impl InflateBackend for Inflate { |
64 | fn make(zlib_header: bool, _window_bits: u8) -> Self { |
65 | let format = format_from_bool(zlib_header); |
66 | |
67 | Inflate { |
68 | inner: InflateState::new_boxed(format), |
69 | total_in: 0, |
70 | total_out: 0, |
71 | } |
72 | } |
73 | |
74 | fn decompress( |
75 | &mut self, |
76 | input: &[u8], |
77 | output: &mut [u8], |
78 | flush: FlushDecompress, |
79 | ) -> Result<Status, DecompressError> { |
80 | let mz_flush = flush.into(); |
81 | let res = inflate::stream::inflate(&mut self.inner, input, output, mz_flush); |
82 | self.total_in += res.bytes_consumed as u64; |
83 | self.total_out += res.bytes_written as u64; |
84 | |
85 | match res.status { |
86 | Ok(status) => match status { |
87 | MZStatus::Ok => Ok(Status::Ok), |
88 | MZStatus::StreamEnd => Ok(Status::StreamEnd), |
89 | MZStatus::NeedDict => { |
90 | mem::decompress_need_dict(self.inner.decompressor().adler32().unwrap_or(0)) |
91 | } |
92 | }, |
93 | Err(status) => match status { |
94 | MZError::Buf => Ok(Status::BufError), |
95 | _ => mem::decompress_failed(ErrorMessage), |
96 | }, |
97 | } |
98 | } |
99 | |
100 | fn reset(&mut self, zlib_header: bool) { |
101 | self.inner.reset(format_from_bool(zlib_header)); |
102 | self.total_in = 0; |
103 | self.total_out = 0; |
104 | } |
105 | } |
106 | |
107 | impl Backend for Inflate { |
108 | #[inline ] |
109 | fn total_in(&self) -> u64 { |
110 | self.total_in |
111 | } |
112 | |
113 | #[inline ] |
114 | fn total_out(&self) -> u64 { |
115 | self.total_out |
116 | } |
117 | } |
118 | |
119 | pub struct Deflate { |
120 | inner: Box<CompressorOxide>, |
121 | total_in: u64, |
122 | total_out: u64, |
123 | } |
124 | |
125 | impl fmt::Debug for Deflate { |
126 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
127 | write!( |
128 | f, |
129 | "miniz_oxide deflate internal state. total_in: {}, total_out: {}" , |
130 | self.total_in, self.total_out, |
131 | ) |
132 | } |
133 | } |
134 | |
135 | impl From<FlushCompress> for MZFlush { |
136 | fn from(value: FlushCompress) -> Self { |
137 | match value { |
138 | FlushCompress::None => Self::None, |
139 | FlushCompress::Partial | FlushCompress::Sync => Self::Sync, |
140 | FlushCompress::Full => Self::Full, |
141 | FlushCompress::Finish => Self::Finish, |
142 | } |
143 | } |
144 | } |
145 | |
146 | impl DeflateBackend for Deflate { |
147 | fn make(level: Compression, zlib_header: bool, _window_bits: u8) -> Self { |
148 | // Check in case the integer value changes at some point. |
149 | debug_assert!(level.level() <= 10); |
150 | |
151 | let mut inner: Box<CompressorOxide> = Box::default(); |
152 | let format = format_from_bool(zlib_header); |
153 | inner.set_format_and_level(format, level.level().try_into().unwrap_or(1)); |
154 | |
155 | Deflate { |
156 | inner, |
157 | total_in: 0, |
158 | total_out: 0, |
159 | } |
160 | } |
161 | |
162 | fn compress( |
163 | &mut self, |
164 | input: &[u8], |
165 | output: &mut [u8], |
166 | flush: FlushCompress, |
167 | ) -> Result<Status, CompressError> { |
168 | let mz_flush = flush.into(); |
169 | let res = deflate::stream::deflate(&mut self.inner, input, output, mz_flush); |
170 | self.total_in += res.bytes_consumed as u64; |
171 | self.total_out += res.bytes_written as u64; |
172 | |
173 | match res.status { |
174 | Ok(status) => match status { |
175 | MZStatus::Ok => Ok(Status::Ok), |
176 | MZStatus::StreamEnd => Ok(Status::StreamEnd), |
177 | MZStatus::NeedDict => mem::compress_failed(ErrorMessage), |
178 | }, |
179 | Err(status) => match status { |
180 | MZError::Buf => Ok(Status::BufError), |
181 | _ => mem::compress_failed(ErrorMessage), |
182 | }, |
183 | } |
184 | } |
185 | |
186 | fn reset(&mut self) { |
187 | self.total_in = 0; |
188 | self.total_out = 0; |
189 | self.inner.reset(); |
190 | } |
191 | } |
192 | |
193 | impl Backend for Deflate { |
194 | #[inline ] |
195 | fn total_in(&self) -> u64 { |
196 | self.total_in |
197 | } |
198 | |
199 | #[inline ] |
200 | fn total_out(&self) -> u64 { |
201 | self.total_out |
202 | } |
203 | } |
204 | |