Skip to content

Commit 71eb5c5

Browse files
authored
Merge pull request #524 from Byron/complete-zlib-rs
Complete the zlib-rs support without the need for C-bindings
2 parents 6e25a3f + fec67eb commit 71eb5c5

File tree

3 files changed

+123
-27
lines changed

3 files changed

+123
-27
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ exclude = [".*"]
2222
libz-sys = { version = "1.1.20", optional = true, default-features = false }
2323
libz-ng-sys = { version = "1.1.16", optional = true }
2424
# this matches the default features, but we don't want to depend on the default features staying the same
25-
zlib-rs = { version = "0.5.3", optional = true, default-features = false, features = ["std", "rust-allocator"] }
25+
zlib-rs = { version = "0.5.5", optional = true, default-features = false, features = ["std", "rust-allocator"] }
2626
cloudflare-zlib-sys = { version = "0.3.6", optional = true }
2727
## This implementation uses only safe Rust code and doesn't require a C compiler.
2828
## It provides good performance for most use cases while being completely portable.

src/ffi/zlib_rs.rs

Lines changed: 85 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub const MZ_FINISH: isize = DeflateFlush::Finish as isize;
3030
pub const MZ_DEFAULT_WINDOW_BITS: core::ffi::c_int = 15;
3131

3232
use super::*;
33+
use crate::mem::{compress_failed, decompress_failed};
3334

3435
impl From<::zlib_rs::Status> for crate::mem::Status {
3536
fn from(value: ::zlib_rs::Status) -> Self {
@@ -52,15 +53,18 @@ impl ErrorMessage {
5253

5354
pub struct Inflate {
5455
pub(crate) inner: ::zlib_rs::Inflate,
56+
// NOTE: these counts do not count the dictionary.
57+
total_in: u64,
58+
total_out: u64,
5559
}
5660

5761
impl fmt::Debug for Inflate {
5862
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
5963
write!(
6064
f,
6165
"zlib_rs inflate internal state. total_in: {}, total_out: {}",
62-
self.inner.total_in(),
63-
self.inner.total_out(),
66+
self.total_in(),
67+
self.total_out(),
6468
)
6569
}
6670
}
@@ -79,6 +83,8 @@ impl InflateBackend for Inflate {
7983
fn make(zlib_header: bool, window_bits: u8) -> Self {
8084
Inflate {
8185
inner: ::zlib_rs::Inflate::new(zlib_header, window_bits),
86+
total_in: 0,
87+
total_out: 0,
8288
}
8389
}
8490

@@ -94,41 +100,67 @@ impl InflateBackend for Inflate {
94100
FlushDecompress::Finish => InflateFlush::Finish,
95101
};
96102

97-
match self.inner.decompress(input, output, flush) {
103+
let total_in_start = self.inner.total_in();
104+
let total_out_start = self.inner.total_out();
105+
106+
let result = self.inner.decompress(input, output, flush);
107+
108+
self.total_in += self.inner.total_in() - total_in_start;
109+
self.total_out += self.inner.total_out() - total_out_start;
110+
111+
match result {
98112
Ok(status) => Ok(status.into()),
99113
Err(InflateError::NeedDict { dict_id }) => crate::mem::decompress_need_dict(dict_id),
100-
Err(e) => crate::mem::decompress_failed(ErrorMessage(Some(e.as_str()))),
114+
Err(_) => self.decompress_error(),
101115
}
102116
}
103117

104118
fn reset(&mut self, zlib_header: bool) {
119+
self.total_in = 0;
120+
self.total_out = 0;
105121
self.inner.reset(zlib_header);
106122
}
107123
}
108124

109125
impl Backend for Inflate {
110126
#[inline]
111127
fn total_in(&self) -> u64 {
112-
self.inner.total_in()
128+
self.total_in
113129
}
114130

115131
#[inline]
116132
fn total_out(&self) -> u64 {
117-
self.inner.total_out()
133+
self.total_out
134+
}
135+
}
136+
137+
impl Inflate {
138+
fn decompress_error<T>(&self) -> Result<T, DecompressError> {
139+
decompress_failed(ErrorMessage(self.inner.error_message()))
140+
}
141+
142+
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
143+
match self.inner.set_dictionary(dictionary) {
144+
Ok(v) => Ok(v),
145+
Err(_) => self.decompress_error(),
146+
}
118147
}
119148
}
120149

121150
pub struct Deflate {
122151
pub(crate) inner: ::zlib_rs::Deflate,
152+
// NOTE: these counts do not count the dictionary.
153+
total_in: u64,
154+
total_out: u64,
123155
}
124156

125157
impl fmt::Debug for Deflate {
126158
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
127159
write!(
128160
f,
129161
"zlib_rs deflate internal state. total_in: {}, total_out: {}",
130-
self.inner.total_in(),
131-
self.inner.total_out(),
162+
self.total_in(),
163+
self.total_out(),
132164
)
133165
}
134166
}
@@ -140,6 +172,8 @@ impl DeflateBackend for Deflate {
140172

141173
Deflate {
142174
inner: ::zlib_rs::Deflate::new(level.level() as i32, zlib_header, window_bits),
175+
total_in: 0,
176+
total_out: 0,
143177
}
144178
}
145179

@@ -157,25 +191,64 @@ impl DeflateBackend for Deflate {
157191
FlushCompress::Finish => DeflateFlush::Finish,
158192
};
159193

160-
match self.inner.compress(input, output, flush) {
194+
let total_in_start = self.inner.total_in();
195+
let total_out_start = self.inner.total_out();
196+
197+
let result = self.inner.compress(input, output, flush);
198+
199+
self.total_in += self.inner.total_in() - total_in_start;
200+
self.total_out += self.inner.total_out() - total_out_start;
201+
202+
match result {
161203
Ok(status) => Ok(status.into()),
162-
Err(e) => crate::mem::compress_failed(ErrorMessage(Some(e.as_str()))),
204+
Err(_) => self.compress_error(),
163205
}
164206
}
165207

166208
fn reset(&mut self) {
209+
self.total_in = 0;
210+
self.total_out = 0;
167211
self.inner.reset();
168212
}
169213
}
170214

171215
impl Backend for Deflate {
172216
#[inline]
173217
fn total_in(&self) -> u64 {
174-
self.inner.total_in()
218+
self.total_in
175219
}
176220

177221
#[inline]
178222
fn total_out(&self) -> u64 {
179-
self.inner.total_out()
223+
self.total_out
224+
}
225+
}
226+
227+
impl Deflate {
228+
fn compress_error<T>(&self) -> Result<T, CompressError> {
229+
compress_failed(ErrorMessage(self.inner.error_message()))
230+
}
231+
232+
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
233+
match self.inner.set_dictionary(dictionary) {
234+
Ok(v) => Ok(v),
235+
Err(_) => self.compress_error(),
236+
}
237+
}
238+
239+
pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
240+
use ::zlib_rs::Status;
241+
242+
match self.inner.set_level(level.level() as i32) {
243+
Ok(status) => match status {
244+
Status::Ok => Ok(()),
245+
246+
Status::BufError => compress_failed(ErrorMessage(Some("insufficient space"))),
247+
248+
Status::StreamEnd => unreachable!(),
249+
},
250+
251+
Err(_) => self.compress_error(),
252+
}
180253
}
181254
}

src/mem.rs

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,14 @@ impl Compress {
286286
}
287287
}
288288

289+
/// Specifies the compression dictionary to use.
290+
///
291+
/// Returns the Adler-32 checksum of the dictionary.
292+
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
293+
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
294+
self.inner.set_dictionary(dictionary)
295+
}
296+
289297
/// Quickly resets this compressor without having to reallocate anything.
290298
///
291299
/// This is equivalent to dropping this object and then creating a new one.
@@ -303,22 +311,31 @@ impl Compress {
303311
/// the compression of the available input data before changing the
304312
/// compression level. Flushing the stream before calling this method
305313
/// ensures that the function will succeed on the first call.
306-
#[cfg(feature = "any_zlib")]
314+
#[cfg(any(feature = "any_zlib", feature = "zlib-rs"))]
307315
pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
308-
use std::os::raw::c_int;
309-
// SAFETY: The field `inner` must always be accessed as a raw pointer,
310-
// since it points to a cyclic structure. No copies of `inner` can be
311-
// retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
312-
let stream = self.inner.inner.stream_wrapper.inner;
313-
unsafe {
314-
(*stream).msg = std::ptr::null_mut();
316+
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
317+
{
318+
self.inner.set_level(level)
315319
}
316-
let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
317320

318-
match rc {
319-
ffi::MZ_OK => Ok(()),
320-
ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
321-
c => panic!("unknown return code: {}", c),
321+
#[cfg(feature = "any_zlib")]
322+
{
323+
use std::os::raw::c_int;
324+
// SAFETY: The field `inner` must always be accessed as a raw pointer,
325+
// since it points to a cyclic structure. No copies of `inner` can be
326+
// retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
327+
let stream = self.inner.inner.stream_wrapper.inner;
328+
unsafe {
329+
(*stream).msg = std::ptr::null_mut();
330+
}
331+
let rc =
332+
unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
333+
334+
match rc {
335+
ffi::MZ_OK => Ok(()),
336+
ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
337+
c => panic!("unknown return code: {}", c),
338+
}
322339
}
323340
}
324341

@@ -540,6 +557,12 @@ impl Decompress {
540557
}
541558
}
542559

560+
/// Specifies the decompression dictionary to use.
561+
#[cfg(all(not(feature = "any_zlib"), feature = "zlib-rs"))]
562+
pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
563+
self.inner.set_dictionary(dictionary)
564+
}
565+
543566
/// Performs the equivalent of replacing this decompression state with a
544567
/// freshly allocated copy.
545568
///
@@ -806,7 +829,7 @@ mod tests {
806829
assert_eq!(&decoded[..decoder.total_out() as usize], string);
807830
}
808831

809-
#[cfg(feature = "any_zlib")]
832+
#[cfg(any(feature = "any_zlib", feature = "zlib-rs"))]
810833
#[test]
811834
fn test_error_message() {
812835
let mut decoder = Decompress::new(false);

0 commit comments

Comments
 (0)