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
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}