7 use libc
::{c_int, c_uint}
;
12 /// Raw in-memory compression stream for blocks of data.
14 /// This type is the building block for the I/O streams in the rest of this
15 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
16 /// maximally flexible in terms of accepting input from any source and being
17 /// able to produce output to any memory location.
19 /// It is recommended to use the I/O stream adaptors over this type as they're
22 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
23 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
26 inner
: Stream
<DirCompress
>,
29 /// Raw in-memory decompression stream for blocks of data.
31 /// This type is the building block for the I/O streams in the rest of this
32 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
33 /// maximally flexible in terms of accepting input from any source and being
34 /// able to produce output to any memory location.
36 /// It is recommended to use the I/O stream adaptors over this type as they're
39 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
40 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
42 pub struct Decompress
{
43 inner
: Stream
<DirDecompress
>,
47 struct Stream
<D
: Direction
> {
48 stream_wrapper
: ffi
::StreamWrapper
,
51 _marker
: marker
::PhantomData
<D
>,
54 unsafe impl<D
: Direction
> Send
for Stream
<D
> {}
55 unsafe impl<D
: Direction
> Sync
for Stream
<D
> {}
58 unsafe fn destroy(stream
: *mut ffi
::mz_stream
) -> c_int
;
66 /// Values which indicate the form of flushing to be used when compressing or
67 /// decompressing in-memory data.
68 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
70 /// A typical parameter for passing to compression/decompression functions,
71 /// this indicates that the underlying stream to decide how much data to
72 /// accumulate before producing output in order to maximize compression.
73 None
= ffi
::MZ_NO_FLUSH
as isize,
75 /// All pending output is flushed to the output buffer and the output is
76 /// aligned on a byte boundary so that the decompressor can get all input
77 /// data available so far.
79 /// Flushing may degrade compression for some compression algorithms and so
80 /// it should only be used when necessary. This will complete the current
81 /// deflate block and follow it with an empty stored block.
82 Sync
= ffi
::MZ_SYNC_FLUSH
as isize,
84 /// All pending output is flushed to the output buffer, but the output is
85 /// not aligned to a byte boundary.
87 /// All of the input data so far will be available to the decompressor (as
88 /// with `Flush::Sync`. This completes the current deflate block and follows
89 /// it with an empty fixed codes block that is 10 bites long, and it assures
90 /// that enough bytes are output in order for the decompessor to finish the
91 /// block before the empty fixed code block.
92 Partial
= ffi
::MZ_PARTIAL_FLUSH
as isize,
94 /// A deflate block is completed and emitted, as for `Flush::Sync`, but the
95 /// output is not aligned on a byte boundary and up to seven vits of the
96 /// current block are held to be written as the next byte after the next
97 /// deflate block is completed.
99 /// In this case the decompressor may not be provided enough bits at this
100 /// point in order to complete decompression of the data provided so far to
101 /// the compressor, it may need to wait for the next block to be emitted.
102 /// This is for advanced applications that need to control the emission of
104 Block
= ffi
::MZ_BLOCK
as isize,
106 /// All output is flushed as with `Flush::Sync` and the compression state is
107 /// reset so decompression can restart from this point if previous
108 /// compressed data has been damaged or if random access is desired.
110 /// Using this option too often can seriously degrade compression.
111 Full
= ffi
::MZ_FULL_FLUSH
as isize,
113 /// Pending input is processed and pending output is flushed.
115 /// The return value may indicate that the stream is not yet done and more
116 /// data has yet to be processed.
117 Finish
= ffi
::MZ_FINISH
as isize,
120 /// Error returned when a decompression object finds that the input stream of
121 /// bytes was not a valid input stream of bytes.
123 pub struct DataError(());
125 /// Possible status results of compressing some data or successfully
126 /// decompressing a block of data.
127 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
129 /// Indicates success.
131 /// Means that more input may be needed but isn't available
132 /// and/or there' smore output to be written but the output buffer is full.
135 /// Indicates that forward progress is not possible due to input or output
136 /// buffers being empty.
138 /// For compression it means the input buffer needs some more data or the
139 /// output buffer needs to be freed up before trying again.
141 /// For decompression this means that more input is needed to continue or
142 /// the output buffer isn't large enough to contain the result. The function
143 /// can be called again after fixing both.
146 /// Indicates that all input has been consumed and all output bytes have
147 /// been written. Decompression/compression should not be called again.
149 /// For decompression with zlib streams the adler-32 of the decompressed
150 /// data has also been verified.
155 /// Creates a new object ready for compressing data that it's given.
157 /// The `level` argument here indicates what level of compression is going
158 /// to be performed, and the `zlib_header` argument indicates whether the
159 /// output data should have a zlib header or not.
160 pub fn new(level
: Compression
, zlib_header
: bool
) -> Compress
{
162 let mut state
= ffi
::StreamWrapper
::default();
163 let ret
= ffi
::mz_deflateInit2(&mut *state
,
167 ffi
::MZ_DEFAULT_WINDOW_BITS
169 -ffi
::MZ_DEFAULT_WINDOW_BITS
172 ffi
::MZ_DEFAULT_STRATEGY
);
173 debug_assert_eq
!(ret
, 0);
176 stream_wrapper
: state
,
179 _marker
: marker
::PhantomData
,
185 /// Returns the total number of input bytes which have been processed by
186 /// this compression object.
187 pub fn total_in(&self) -> u64 {
191 /// Returns the total number of output bytes which have been produced by
192 /// this compression object.
193 pub fn total_out(&self) -> u64 {
197 /// Quickly resets this compressor without having to reallocate anything.
199 /// This is equivalent to dropping this object and then creating a new one.
200 pub fn reset(&mut self) {
201 let rc
= unsafe { ffi::mz_deflateReset(&mut *self.inner.stream_wrapper) }
;
202 assert_eq
!(rc
, ffi
::MZ_OK
);
204 self.inner
.total_in
= 0;
205 self.inner
.total_out
= 0;
208 /// Compresses the input data into the output, consuming only as much
209 /// input as needed and writing as much output as possible.
211 /// The flush option can be any of the available flushing parameters.
213 /// To learn how much data was consumed or how much output was produced, use
214 /// the `total_in` and `total_out` functions before/after this is called.
215 pub fn compress(&mut self,
220 let raw
= &mut *self.inner
.stream_wrapper
;
221 raw
.next_in
= input
.as_ptr() as *mut _
;
222 raw
.avail_in
= input
.len() as c_uint
;
223 raw
.next_out
= output
.as_mut_ptr();
224 raw
.avail_out
= output
.len() as c_uint
;
226 let rc
= unsafe { ffi::mz_deflate(raw, flush as c_int) }
;
228 // Unfortunately the total counters provided by zlib might be only
229 // 32 bits wide and overflow while processing large amounts of data.
230 self.inner
.total_in
+= (raw
.next_in
as usize -
231 input
.as_ptr() as usize) as u64;
232 self.inner
.total_out
+= (raw
.next_out
as usize -
233 output
.as_ptr() as usize) as u64;
236 ffi
::MZ_OK
=> Status
::Ok
,
237 ffi
::MZ_BUF_ERROR
=> Status
::BufError
,
238 ffi
::MZ_STREAM_END
=> Status
::StreamEnd
,
239 c
=> panic
!("unknown return code: {}", c
),
243 /// Compresses the input data into the extra space of the output, consuming
244 /// only as much input as needed and writing as much output as possible.
246 /// This function has the same semantics as `compress`, except that the
247 /// length of `vec` is managed by this function. This will not reallocate
248 /// the vector provided or attempt to grow it, so space for the output must
249 /// be reserved in the output vector by the caller before calling this
251 pub fn compress_vec(&mut self,
253 output
: &mut Vec
<u8>,
256 let cap
= output
.capacity();
257 let len
= output
.len();
260 let before
= self.total_out();
262 let ptr
= output
.as_mut_ptr().offset(len
as isize);
263 let out
= slice
::from_raw_parts_mut(ptr
, cap
- len
);
264 self.compress(input
, out
, flush
)
266 output
.set_len((self.total_out() - before
) as usize + len
);
273 /// Creates a new object ready for decompressing data that it's given.
275 /// The `zlib_header` argument indicates whether the input data is expected
276 /// to have a zlib header or not.
277 pub fn new(zlib_header
: bool
) -> Decompress
{
279 let mut state
= ffi
::StreamWrapper
::default();
280 let ret
= ffi
::mz_inflateInit2(&mut *state
,
282 ffi
::MZ_DEFAULT_WINDOW_BITS
284 -ffi
::MZ_DEFAULT_WINDOW_BITS
286 debug_assert_eq
!(ret
, 0);
289 stream_wrapper
: state
,
292 _marker
: marker
::PhantomData
,
298 /// Returns the total number of input bytes which have been processed by
299 /// this decompression object.
300 pub fn total_in(&self) -> u64 {
304 /// Returns the total number of output bytes which have been produced by
305 /// this decompression object.
306 pub fn total_out(&self) -> u64 {
310 /// Decompresses the input data into the output, consuming only as much
311 /// input as needed and writing as much output as possible.
313 /// The flush option provided can either be `Flush::None`, `Flush::Sync`,
314 /// or `Flush::Finish`. If the first call passes `Flush::Finish` it is
315 /// assumed that the input and output buffers are both sized large enough to
316 /// decompress the entire stream in a single call.
318 /// A flush value of `Flush::Finish` indicates that there are no more source
319 /// bytes available beside what's already in the input buffer, and the
320 /// output buffer is large enough to hold the rest of the decompressed data.
322 /// To learn how much data was consumed or how much output was produced, use
323 /// the `total_in` and `total_out` functions before/after this is called.
327 /// If the input data to this instance of `Decompress` is not a valid
328 /// zlib/deflate stream then this function may return an instance of
329 /// `DataError` to indicate that the stream of input bytes is corrupted.
330 pub fn decompress(&mut self,
334 -> Result
<Status
, DataError
> {
335 let raw
= &mut *self.inner
.stream_wrapper
;
336 raw
.next_in
= input
.as_ptr() as *mut u8;
337 raw
.avail_in
= input
.len() as c_uint
;
338 raw
.next_out
= output
.as_mut_ptr();
339 raw
.avail_out
= output
.len() as c_uint
;
341 let rc
= unsafe { ffi::mz_inflate(raw, flush as c_int) }
;
343 // Unfortunately the total counters provided by zlib might be only
344 // 32 bits wide and overflow while processing large amounts of data.
345 self.inner
.total_in
+= (raw
.next_in
as usize -
346 input
.as_ptr() as usize) as u64;
347 self.inner
.total_out
+= (raw
.next_out
as usize -
348 output
.as_ptr() as usize) as u64;
352 ffi
::MZ_STREAM_ERROR
=> Err(DataError(())),
353 ffi
::MZ_OK
=> Ok(Status
::Ok
),
354 ffi
::MZ_BUF_ERROR
=> Ok(Status
::BufError
),
355 ffi
::MZ_STREAM_END
=> Ok(Status
::StreamEnd
),
356 c
=> panic
!("unknown return code: {}", c
),
360 /// Decompresses the input data into the extra space in the output vector
361 /// specified by `output`.
363 /// This function has the same semantics as `decompress`, except that the
364 /// length of `vec` is managed by this function. This will not reallocate
365 /// the vector provided or attempt to grow it, so space for the output must
366 /// be reserved in the output vector by the caller before calling this
371 /// If the input data to this instance of `Decompress` is not a valid
372 /// zlib/deflate stream then this function may return an instance of
373 /// `DataError` to indicate that the stream of input bytes is corrupted.
374 pub fn decompress_vec(&mut self,
376 output
: &mut Vec
<u8>,
378 -> Result
<Status
, DataError
> {
379 let cap
= output
.capacity();
380 let len
= output
.len();
383 let before
= self.total_out();
385 let ptr
= output
.as_mut_ptr().offset(len
as isize);
386 let out
= slice
::from_raw_parts_mut(ptr
, cap
- len
);
387 self.decompress(input
, out
, flush
)
389 output
.set_len((self.total_out() - before
) as usize + len
);
394 /// Performs the equivalent of replacing this decompression state with a
395 /// freshly allocated copy.
397 /// This function may not allocate memory, though, and attempts to reuse any
398 /// previously existing resources.
400 /// The argument provided here indicates whether the reset state will
401 /// attempt to decode a zlib header first or not.
402 pub fn reset(&mut self, zlib_header
: bool
) {
403 self._reset(zlib_header
);
406 #[cfg(feature = "zlib")]
407 fn _reset(&mut self, zlib_header
: bool
) {
408 let bits
= if zlib_header
{
409 ffi
::MZ_DEFAULT_WINDOW_BITS
411 -ffi
::MZ_DEFAULT_WINDOW_BITS
414 ffi
::inflateReset2(&mut *self.inner
.stream_wrapper
, bits
);
416 self.inner
.total_out
= 0;
417 self.inner
.total_in
= 0;
420 #[cfg(not(feature = "zlib"))]
421 fn _reset(&mut self, zlib_header
: bool
) {
422 *self = Decompress
::new(zlib_header
);
426 impl Error
for DataError
{
427 fn description(&self) -> &str { "deflate data error" }
430 impl From
<DataError
> for io
::Error
{
431 fn from(data
: DataError
) -> io
::Error
{
432 io
::Error
::new(io
::ErrorKind
::Other
, data
)
436 impl fmt
::Display
for DataError
{
437 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
438 self.description().fmt(f
)
442 impl Direction
for DirCompress
{
443 unsafe fn destroy(stream
: *mut ffi
::mz_stream
) -> c_int
{
444 ffi
::mz_deflateEnd(stream
)
447 impl Direction
for DirDecompress
{
448 unsafe fn destroy(stream
: *mut ffi
::mz_stream
) -> c_int
{
449 ffi
::mz_inflateEnd(stream
)
453 impl<D
: Direction
> Drop
for Stream
<D
> {
456 let _
= D
::destroy(&mut *self.stream_wrapper
);
466 use {Compression, Decompress, Flush}
;
471 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9,
472 0x28, 0xc9, 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1,
473 0xb3, 0x29, 0xc9, 0x2c, 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0,
474 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f, 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08,
475 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5, 0xa7, 0x54, 0x2a, 0x24,
476 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67, 0x64, 0x96,
477 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
478 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9,
479 0x05, 0x54, 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea,
480 0x99, 0xe9, 0x19, 0x21, 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f,
481 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb, 0xe4, 0xa8, 0x00, 0x00, 0x00
484 let mut decoded
= Vec
::with_capacity(data
.len()*2);
486 let mut d
= Decompress
::new(false);
487 // decompressed whole deflate stream
488 assert
!(d
.decompress_vec(&data
[10..], &mut decoded
, Flush
::Finish
).is_ok());
490 // decompress data that has nothing to do with the deflate stream (this
492 drop(d
.decompress_vec(&[0], &mut decoded
, Flush
::None
));
497 let string
= "hello world".as_bytes();
498 let mut zlib
= Vec
::new();
499 let mut deflate
= Vec
::new();
501 let comp
= Compression
::Default
;
502 write
::ZlibEncoder
::new(&mut zlib
, comp
).write_all(string
).unwrap();
503 write
::DeflateEncoder
::new(&mut deflate
, comp
).write_all(string
).unwrap();
505 let mut dst
= [0; 1024];
506 let mut decoder
= Decompress
::new(true);
507 decoder
.decompress(&zlib
, &mut dst
, Flush
::Finish
).unwrap();
508 assert_eq
!(decoder
.total_out(), string
.len() as u64);
509 assert
!(dst
.starts_with(string
));
511 decoder
.reset(false);
512 decoder
.decompress(&deflate
, &mut dst
, Flush
::Finish
).unwrap();
513 assert_eq
!(decoder
.total_out(), string
.len() as u64);
514 assert
!(dst
.starts_with(string
));