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 (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 InflateBackend for Inflate { |
54 | fn make(zlib_header: bool, _window_bits: u8) -> Self { |
55 | let format = format_from_bool(zlib_header); |
56 | |
57 | Inflate { |
58 | inner: InflateState::new_boxed(format), |
59 | total_in: 0, |
60 | total_out: 0, |
61 | } |
62 | } |
63 | |
64 | fn decompress( |
65 | &mut self, |
66 | input: &[u8], |
67 | output: &mut [u8], |
68 | flush: FlushDecompress, |
69 | ) -> Result<Status, DecompressError> { |
70 | let flush = MZFlush::new(flush as i32).unwrap(); |
71 | |
72 | let res = inflate::stream::inflate(&mut self.inner, input, output, flush); |
73 | self.total_in += res.bytes_consumed as u64; |
74 | self.total_out += res.bytes_written as u64; |
75 | |
76 | match res.status { |
77 | Ok(status) => match status { |
78 | MZStatus::Ok => Ok(Status::Ok), |
79 | MZStatus::StreamEnd => Ok(Status::StreamEnd), |
80 | MZStatus::NeedDict => { |
81 | mem::decompress_need_dict(self.inner.decompressor().adler32().unwrap_or(0)) |
82 | } |
83 | }, |
84 | Err(status) => match status { |
85 | MZError::Buf => Ok(Status::BufError), |
86 | _ => mem::decompress_failed(ErrorMessage), |
87 | }, |
88 | } |
89 | } |
90 | |
91 | fn reset(&mut self, zlib_header: bool) { |
92 | self.inner.reset(format_from_bool(zlib_header)); |
93 | self.total_in = 0; |
94 | self.total_out = 0; |
95 | } |
96 | } |
97 | |
98 | impl Backend for Inflate { |
99 | #[inline ] |
100 | fn total_in(&self) -> u64 { |
101 | self.total_in |
102 | } |
103 | |
104 | #[inline ] |
105 | fn total_out(&self) -> u64 { |
106 | self.total_out |
107 | } |
108 | } |
109 | |
110 | pub struct Deflate { |
111 | inner: Box<CompressorOxide>, |
112 | total_in: u64, |
113 | total_out: u64, |
114 | } |
115 | |
116 | impl fmt::Debug for Deflate { |
117 | fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { |
118 | write!( |
119 | f, |
120 | "miniz_oxide deflate internal state. total_in: {}, total_out: {}" , |
121 | self.total_in, self.total_out, |
122 | ) |
123 | } |
124 | } |
125 | |
126 | impl DeflateBackend for Deflate { |
127 | fn make(level: Compression, zlib_header: bool, _window_bits: u8) -> Self { |
128 | // Check in case the integer value changes at some point. |
129 | debug_assert!(level.level() <= 10); |
130 | |
131 | let mut inner: Box<CompressorOxide> = Box::default(); |
132 | let format = format_from_bool(zlib_header); |
133 | inner.set_format_and_level(format, level.level().try_into().unwrap_or(1)); |
134 | |
135 | Deflate { |
136 | inner, |
137 | total_in: 0, |
138 | total_out: 0, |
139 | } |
140 | } |
141 | |
142 | fn compress( |
143 | &mut self, |
144 | input: &[u8], |
145 | output: &mut [u8], |
146 | flush: FlushCompress, |
147 | ) -> Result<Status, CompressError> { |
148 | let flush = MZFlush::new(flush as i32).unwrap(); |
149 | let res = deflate::stream::deflate(&mut self.inner, input, output, flush); |
150 | self.total_in += res.bytes_consumed as u64; |
151 | self.total_out += res.bytes_written as u64; |
152 | |
153 | match res.status { |
154 | Ok(status) => match status { |
155 | MZStatus::Ok => Ok(Status::Ok), |
156 | MZStatus::StreamEnd => Ok(Status::StreamEnd), |
157 | MZStatus::NeedDict => mem::compress_failed(ErrorMessage), |
158 | }, |
159 | Err(status) => match status { |
160 | MZError::Buf => Ok(Status::BufError), |
161 | _ => mem::compress_failed(ErrorMessage), |
162 | }, |
163 | } |
164 | } |
165 | |
166 | fn reset(&mut self) { |
167 | self.total_in = 0; |
168 | self.total_out = 0; |
169 | self.inner.reset(); |
170 | } |
171 | } |
172 | |
173 | impl Backend for Deflate { |
174 | #[inline ] |
175 | fn total_in(&self) -> u64 { |
176 | self.total_in |
177 | } |
178 | |
179 | #[inline ] |
180 | fn total_out(&self) -> u64 { |
181 | self.total_out |
182 | } |
183 | } |
184 | |