flate2/ffi/
rust.rs

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
19fn format_from_bool(zlib_header: bool) -> DataFormat {
20    if zlib_header {
21        DataFormat::Zlib
22    } else {
23        DataFormat::Raw
24    }
25}
26
27pub struct Inflate {
28    inner: Box<InflateState>,
29    total_in: u64,
30    total_out: u64,
31}
32
33impl fmt::Debug for Inflate {
34    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
35        write!(
36            f,
37            "miniz_oxide inflate internal state. total_in: {}, total_out: {}",
38            self.total_in, self.total_out,
39        )
40    }
41}
42
43impl InflateBackend for Inflate {
44    fn make(zlib_header: bool, window_bits: u8) -> Self {
45        assert!(
46            window_bits > 8 && window_bits < 16,
47            "window_bits must be within 9 ..= 15"
48        );
49
50        let format = format_from_bool(zlib_header);
51
52        Inflate {
53            inner: InflateState::new_boxed(format),
54            total_in: 0,
55            total_out: 0,
56        }
57    }
58
59    fn decompress(
60        &mut self,
61        input: &[u8],
62        output: &mut [u8],
63        flush: FlushDecompress,
64    ) -> Result<Status, DecompressError> {
65        let flush = MZFlush::new(flush as i32).unwrap();
66
67        let res = inflate::stream::inflate(&mut self.inner, input, output, flush);
68        self.total_in += res.bytes_consumed as u64;
69        self.total_out += res.bytes_written as u64;
70
71        match res.status {
72            Ok(status) => match status {
73                MZStatus::Ok => Ok(Status::Ok),
74                MZStatus::StreamEnd => Ok(Status::StreamEnd),
75                MZStatus::NeedDict => {
76                    mem::decompress_need_dict(self.inner.decompressor().adler32().unwrap_or(0))
77                }
78            },
79            Err(status) => match status {
80                MZError::Buf => Ok(Status::BufError),
81                _ => mem::decompress_failed(),
82            },
83        }
84    }
85
86    fn reset(&mut self, zlib_header: bool) {
87        self.inner.reset(format_from_bool(zlib_header));
88        self.total_in = 0;
89        self.total_out = 0;
90    }
91}
92
93impl Backend for Inflate {
94    #[inline]
95    fn total_in(&self) -> u64 {
96        self.total_in
97    }
98
99    #[inline]
100    fn total_out(&self) -> u64 {
101        self.total_out
102    }
103}
104
105pub struct Deflate {
106    inner: Box<CompressorOxide>,
107    total_in: u64,
108    total_out: u64,
109}
110
111impl fmt::Debug for Deflate {
112    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
113        write!(
114            f,
115            "miniz_oxide deflate internal state. total_in: {}, total_out: {}",
116            self.total_in, self.total_out,
117        )
118    }
119}
120
121impl DeflateBackend for Deflate {
122    fn make(level: Compression, zlib_header: bool, window_bits: u8) -> Self {
123        assert!(
124            window_bits > 8 && window_bits < 16,
125            "window_bits must be within 9 ..= 15"
126        );
127
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 => Err(CompressError(())),
158            },
159            Err(status) => match status {
160                MZError::Buf => Ok(Status::BufError),
161                _ => Err(CompressError(())),
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}