1//! Implementation for `miniz_oxide` rust backend.
2
3use std::convert::TryInto;
4use std::fmt;
5
6use miniz_oxide::deflate::core::CompressorOxide;
7use miniz_oxide::inflate::stream::InflateState;
8pub use miniz_oxide::*;
9
10pub const MZ_NO_FLUSH: isize = MZFlush::None as isize;
11pub const MZ_PARTIAL_FLUSH: isize = MZFlush::Partial as isize;
12pub const MZ_SYNC_FLUSH: isize = MZFlush::Sync as isize;
13pub const MZ_FULL_FLUSH: isize = MZFlush::Full as isize;
14pub const MZ_FINISH: isize = MZFlush::Finish as isize;
15
16use super::*;
17use crate::mem;
18
19// miniz_oxide doesn't provide any error messages (yet?)
20#[derive(Default)]
21pub struct ErrorMessage;
22
23impl ErrorMessage {
24 pub fn get(&self) -> Option<&str> {
25 None
26 }
27}
28
29fn format_from_bool(zlib_header: bool) -> DataFormat {
30 if zlib_header {
31 DataFormat::Zlib
32 } else {
33 DataFormat::Raw
34 }
35}
36
37pub struct Inflate {
38 inner: Box<InflateState>,
39 total_in: u64,
40 total_out: u64,
41}
42
43impl 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
53impl 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
98impl 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
110pub struct Deflate {
111 inner: Box<CompressorOxide>,
112 total_in: u64,
113 total_out: u64,
114}
115
116impl 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
126impl 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
173impl 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