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 {
get(&self) -> Option<&str>24 pub fn get(&self) -> Option<&str> {
25 None
26 }
27 }
28
format_from_bool(zlib_header: bool) -> DataFormat29 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 {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>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 {
make(zlib_header: bool, _window_bits: u8) -> Self54 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
decompress( &mut self, input: &[u8], output: &mut [u8], flush: FlushDecompress, ) -> Result<Status, DecompressError>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
reset(&mut self, zlib_header: bool)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]
total_in(&self) -> u64100 fn total_in(&self) -> u64 {
101 self.total_in
102 }
103
104 #[inline]
total_out(&self) -> u64105 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 {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>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 {
make(level: Compression, zlib_header: bool, _window_bits: u8) -> Self127 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
compress( &mut self, input: &[u8], output: &mut [u8], flush: FlushCompress, ) -> Result<Status, CompressError>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
reset(&mut self)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]
total_in(&self) -> u64175 fn total_in(&self) -> u64 {
176 self.total_in
177 }
178
179 #[inline]
total_out(&self) -> u64180 fn total_out(&self) -> u64 {
181 self.total_out
182 }
183 }
184