6 use crate::ffi
::{self, Backend, Deflate, DeflateBackend, ErrorMessage, Inflate, InflateBackend}
;
7 use crate::Compression
;
9 /// Raw in-memory compression stream for blocks of data.
11 /// This type is the building block for the I/O streams in the rest of this
12 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
13 /// maximally flexible in terms of accepting input from any source and being
14 /// able to produce output to any memory location.
16 /// It is recommended to use the I/O stream adaptors over this type as they're
19 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
20 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
26 /// Raw in-memory decompression stream for blocks of data.
28 /// This type is the building block for the I/O streams in the rest of this
29 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
30 /// maximally flexible in terms of accepting input from any source and being
31 /// able to produce output to any memory location.
33 /// It is recommended to use the I/O stream adaptors over this type as they're
36 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
37 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
39 pub struct Decompress
{
43 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
44 /// Values which indicate the form of flushing to be used when compressing
46 pub enum FlushCompress
{
47 /// A typical parameter for passing to compression/decompression functions,
48 /// this indicates that the underlying stream to decide how much data to
49 /// accumulate before producing output in order to maximize compression.
50 None
= ffi
::MZ_NO_FLUSH
as isize,
52 /// All pending output is flushed to the output buffer and the output is
53 /// aligned on a byte boundary so that the decompressor can get all input
54 /// data available so far.
56 /// Flushing may degrade compression for some compression algorithms and so
57 /// it should only be used when necessary. This will complete the current
58 /// deflate block and follow it with an empty stored block.
59 Sync
= ffi
::MZ_SYNC_FLUSH
as isize,
61 /// All pending output is flushed to the output buffer, but the output is
62 /// not aligned to a byte boundary.
64 /// All of the input data so far will be available to the decompressor (as
65 /// with `Flush::Sync`. This completes the current deflate block and follows
66 /// it with an empty fixed codes block that is 10 bites long, and it assures
67 /// that enough bytes are output in order for the decompressor to finish the
68 /// block before the empty fixed code block.
69 Partial
= ffi
::MZ_PARTIAL_FLUSH
as isize,
71 /// All output is flushed as with `Flush::Sync` and the compression state is
72 /// reset so decompression can restart from this point if previous
73 /// compressed data has been damaged or if random access is desired.
75 /// Using this option too often can seriously degrade compression.
76 Full
= ffi
::MZ_FULL_FLUSH
as isize,
78 /// Pending input is processed and pending output is flushed.
80 /// The return value may indicate that the stream is not yet done and more
81 /// data has yet to be processed.
82 Finish
= ffi
::MZ_FINISH
as isize,
88 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
89 /// Values which indicate the form of flushing to be used when
90 /// decompressing in-memory data.
91 pub enum FlushDecompress
{
92 /// A typical parameter for passing to compression/decompression functions,
93 /// this indicates that the underlying stream to decide how much data to
94 /// accumulate before producing output in order to maximize compression.
95 None
= ffi
::MZ_NO_FLUSH
as isize,
97 /// All pending output is flushed to the output buffer and the output is
98 /// aligned on a byte boundary so that the decompressor can get all input
99 /// data available so far.
101 /// Flushing may degrade compression for some compression algorithms and so
102 /// it should only be used when necessary. This will complete the current
103 /// deflate block and follow it with an empty stored block.
104 Sync
= ffi
::MZ_SYNC_FLUSH
as isize,
106 /// Pending input is processed and pending output is flushed.
108 /// The return value may indicate that the stream is not yet done and more
109 /// data has yet to be processed.
110 Finish
= ffi
::MZ_FINISH
as isize,
116 /// The inner state for an error when decompressing
118 pub(crate) enum DecompressErrorInner
{
119 General { msg: ErrorMessage }
,
120 NeedsDictionary(u32),
123 /// Error returned when a decompression object finds that the input stream of
124 /// bytes was not a valid input stream of bytes.
126 pub struct DecompressError(pub(crate) DecompressErrorInner
);
128 impl DecompressError
{
129 /// Indicates whether decompression failed due to requiring a dictionary.
131 /// The resulting integer is the Adler-32 checksum of the dictionary
133 pub fn needs_dictionary(&self) -> Option
<u32> {
135 DecompressErrorInner
::NeedsDictionary(adler
) => Some(adler
),
142 pub(crate) fn decompress_failed
<T
>(msg
: ErrorMessage
) -> Result
<T
, DecompressError
> {
143 Err(DecompressError(DecompressErrorInner
::General { msg }
))
147 pub(crate) fn decompress_need_dict
<T
>(adler
: u32) -> Result
<T
, DecompressError
> {
148 Err(DecompressError(DecompressErrorInner
::NeedsDictionary(
153 /// Error returned when a compression object is used incorrectly or otherwise
154 /// generates an error.
156 pub struct CompressError
{
157 pub(crate) msg
: ErrorMessage
,
161 pub(crate) fn compress_failed
<T
>(msg
: ErrorMessage
) -> Result
<T
, CompressError
> {
162 Err(CompressError { msg }
)
165 /// Possible status results of compressing some data or successfully
166 /// decompressing a block of data.
167 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
169 /// Indicates success.
171 /// Means that more input may be needed but isn't available
172 /// and/or there's more output to be written but the output buffer is full.
175 /// Indicates that forward progress is not possible due to input or output
176 /// buffers being empty.
178 /// For compression it means the input buffer needs some more data or the
179 /// output buffer needs to be freed up before trying again.
181 /// For decompression this means that more input is needed to continue or
182 /// the output buffer isn't large enough to contain the result. The function
183 /// can be called again after fixing both.
186 /// Indicates that all input has been consumed and all output bytes have
187 /// been written. Decompression/compression should not be called again.
189 /// For decompression with zlib streams the adler-32 of the decompressed
190 /// data has also been verified.
195 /// Creates a new object ready for compressing data that it's given.
197 /// The `level` argument here indicates what level of compression is going
198 /// to be performed, and the `zlib_header` argument indicates whether the
199 /// output data should have a zlib header or not.
200 pub fn new(level
: Compression
, zlib_header
: bool
) -> Compress
{
202 inner
: Deflate
::make(level
, zlib_header
, ffi
::MZ_DEFAULT_WINDOW_BITS
as u8),
206 /// Creates a new object ready for compressing data that it's given.
208 /// The `level` argument here indicates what level of compression is going
209 /// to be performed, and the `zlib_header` argument indicates whether the
210 /// output data should have a zlib header or not. The `window_bits` parameter
211 /// indicates the base-2 logarithm of the sliding window size and must be
212 /// between 9 and 15.
216 /// If `window_bits` does not fall into the range 9 ..= 15,
217 /// `new_with_window_bits` will panic.
221 /// This constructor is only available when the `zlib` feature is used.
222 /// Other backends currently do not support custom window bits.
223 #[cfg(feature = "any_zlib")]
224 pub fn new_with_window_bits(
230 window_bits
> 8 && window_bits
< 16,
231 "window_bits must be within 9 ..= 15"
234 inner
: Deflate
::make(level
, zlib_header
, window_bits
),
238 /// Creates a new object ready for compressing data that it's given.
240 /// The `level` argument here indicates what level of compression is going
243 /// The Compress object produced by this constructor outputs gzip headers
244 /// for the compressed data.
248 /// If `window_bits` does not fall into the range 9 ..= 15,
249 /// `new_with_window_bits` will panic.
253 /// This constructor is only available when the `zlib` feature is used.
254 /// Other backends currently do not support gzip headers for Compress.
255 #[cfg(feature = "any_zlib")]
256 pub fn new_gzip(level
: Compression
, window_bits
: u8) -> Compress
{
258 window_bits
> 8 && window_bits
< 16,
259 "window_bits must be within 9 ..= 15"
262 inner
: Deflate
::make(level
, true, window_bits
+ 16),
266 /// Returns the total number of input bytes which have been processed by
267 /// this compression object.
268 pub fn total_in(&self) -> u64 {
269 self.inner
.total_in()
272 /// Returns the total number of output bytes which have been produced by
273 /// this compression object.
274 pub fn total_out(&self) -> u64 {
275 self.inner
.total_out()
278 /// Specifies the compression dictionary to use.
280 /// Returns the Adler-32 checksum of the dictionary.
281 #[cfg(feature = "any_zlib")]
282 pub fn set_dictionary(&mut self, dictionary
: &[u8]) -> Result
<u32, CompressError
> {
283 let stream
= &mut *self.inner
.inner
.stream_wrapper
;
284 stream
.msg
= std
::ptr
::null_mut();
286 assert
!(dictionary
.len() < ffi
::uInt
::MAX
as usize);
287 ffi
::deflateSetDictionary(stream
, dictionary
.as_ptr(), dictionary
.len() as ffi
::uInt
)
291 ffi
::MZ_STREAM_ERROR
=> compress_failed(self.inner
.inner
.msg()),
292 ffi
::MZ_OK
=> Ok(stream
.adler
as u32),
293 c
=> panic
!("unknown return code: {}", c
),
297 /// Quickly resets this compressor without having to reallocate anything.
299 /// This is equivalent to dropping this object and then creating a new one.
300 pub fn reset(&mut self) {
304 /// Dynamically updates the compression level.
306 /// This can be used to switch between compression levels for different
307 /// kinds of data, or it can be used in conjunction with a call to reset
308 /// to reuse the compressor.
310 /// This may return an error if there wasn't enough output space to complete
311 /// the compression of the available input data before changing the
312 /// compression level. Flushing the stream before calling this method
313 /// ensures that the function will succeed on the first call.
314 #[cfg(feature = "any_zlib")]
315 pub fn set_level(&mut self, level
: Compression
) -> Result
<(), CompressError
> {
317 let stream
= &mut *self.inner
.inner
.stream_wrapper
;
318 stream
.msg
= std
::ptr
::null_mut();
320 let rc
= unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) }
;
323 ffi
::MZ_OK
=> Ok(()),
324 ffi
::MZ_BUF_ERROR
=> compress_failed(self.inner
.inner
.msg()),
325 c
=> panic
!("unknown return code: {}", c
),
329 /// Compresses the input data into the output, consuming only as much
330 /// input as needed and writing as much output as possible.
332 /// The flush option can be any of the available `FlushCompress` parameters.
334 /// To learn how much data was consumed or how much output was produced, use
335 /// the `total_in` and `total_out` functions before/after this is called.
340 flush
: FlushCompress
,
341 ) -> Result
<Status
, CompressError
> {
342 self.inner
.compress(input
, output
, flush
)
345 /// Compresses the input data into the extra space of the output, consuming
346 /// only as much input as needed and writing as much output as possible.
348 /// This function has the same semantics as `compress`, except that the
349 /// length of `vec` is managed by this function. This will not reallocate
350 /// the vector provided or attempt to grow it, so space for the output must
351 /// be reserved in the output vector by the caller before calling this
356 output
: &mut Vec
<u8>,
357 flush
: FlushCompress
,
358 ) -> Result
<Status
, CompressError
> {
359 let cap
= output
.capacity();
360 let len
= output
.len();
363 let before
= self.total_out();
365 let ptr
= output
.as_mut_ptr().offset(len
as isize);
366 let out
= slice
::from_raw_parts_mut(ptr
, cap
- len
);
367 self.compress(input
, out
, flush
)
369 output
.set_len((self.total_out() - before
) as usize + len
);
376 /// Creates a new object ready for decompressing data that it's given.
378 /// The `zlib_header` argument indicates whether the input data is expected
379 /// to have a zlib header or not.
380 pub fn new(zlib_header
: bool
) -> Decompress
{
382 inner
: Inflate
::make(zlib_header
, ffi
::MZ_DEFAULT_WINDOW_BITS
as u8),
386 /// Creates a new object ready for decompressing data that it's given.
388 /// The `zlib_header` argument indicates whether the input data is expected
389 /// to have a zlib header or not. The `window_bits` parameter indicates the
390 /// base-2 logarithm of the sliding window size and must be between 9 and 15.
394 /// If `window_bits` does not fall into the range 9 ..= 15,
395 /// `new_with_window_bits` will panic.
399 /// This constructor is only available when the `zlib` feature is used.
400 /// Other backends currently do not support custom window bits.
401 #[cfg(feature = "any_zlib")]
402 pub fn new_with_window_bits(zlib_header
: bool
, window_bits
: u8) -> Decompress
{
404 window_bits
> 8 && window_bits
< 16,
405 "window_bits must be within 9 ..= 15"
408 inner
: Inflate
::make(zlib_header
, window_bits
),
412 /// Creates a new object ready for decompressing data that it's given.
414 /// The Decompress object produced by this constructor expects gzip headers
415 /// for the compressed data.
419 /// If `window_bits` does not fall into the range 9 ..= 15,
420 /// `new_with_window_bits` will panic.
424 /// This constructor is only available when the `zlib` feature is used.
425 /// Other backends currently do not support gzip headers for Decompress.
426 #[cfg(feature = "any_zlib")]
427 pub fn new_gzip(window_bits
: u8) -> Decompress
{
429 window_bits
> 8 && window_bits
< 16,
430 "window_bits must be within 9 ..= 15"
433 inner
: Inflate
::make(true, window_bits
+ 16),
437 /// Returns the total number of input bytes which have been processed by
438 /// this decompression object.
439 pub fn total_in(&self) -> u64 {
440 self.inner
.total_in()
443 /// Returns the total number of output bytes which have been produced by
444 /// this decompression object.
445 pub fn total_out(&self) -> u64 {
446 self.inner
.total_out()
449 /// Decompresses the input data into the output, consuming only as much
450 /// input as needed and writing as much output as possible.
452 /// The flush option can be any of the available `FlushDecompress` parameters.
454 /// If the first call passes `FlushDecompress::Finish` it is assumed that
455 /// the input and output buffers are both sized large enough to decompress
456 /// the entire stream in a single call.
458 /// A flush value of `FlushDecompress::Finish` indicates that there are no
459 /// more source bytes available beside what's already in the input buffer,
460 /// and the output buffer is large enough to hold the rest of the
461 /// decompressed data.
463 /// To learn how much data was consumed or how much output was produced, use
464 /// the `total_in` and `total_out` functions before/after this is called.
468 /// If the input data to this instance of `Decompress` is not a valid
469 /// zlib/deflate stream then this function may return an instance of
470 /// `DecompressError` to indicate that the stream of input bytes is corrupted.
475 flush
: FlushDecompress
,
476 ) -> Result
<Status
, DecompressError
> {
477 self.inner
.decompress(input
, output
, flush
)
480 /// Decompresses the input data into the extra space in the output vector
481 /// specified by `output`.
483 /// This function has the same semantics as `decompress`, except that the
484 /// length of `vec` is managed by this function. This will not reallocate
485 /// the vector provided or attempt to grow it, so space for the output must
486 /// be reserved in the output vector by the caller before calling this
491 /// If the input data to this instance of `Decompress` is not a valid
492 /// zlib/deflate stream then this function may return an instance of
493 /// `DecompressError` to indicate that the stream of input bytes is corrupted.
494 pub fn decompress_vec(
497 output
: &mut Vec
<u8>,
498 flush
: FlushDecompress
,
499 ) -> Result
<Status
, DecompressError
> {
500 let cap
= output
.capacity();
501 let len
= output
.len();
504 let before
= self.total_out();
506 let ptr
= output
.as_mut_ptr().offset(len
as isize);
507 let out
= slice
::from_raw_parts_mut(ptr
, cap
- len
);
508 self.decompress(input
, out
, flush
)
510 output
.set_len((self.total_out() - before
) as usize + len
);
515 /// Specifies the decompression dictionary to use.
516 #[cfg(feature = "any_zlib")]
517 pub fn set_dictionary(&mut self, dictionary
: &[u8]) -> Result
<u32, DecompressError
> {
518 let stream
= &mut *self.inner
.inner
.stream_wrapper
;
519 stream
.msg
= std
::ptr
::null_mut();
521 assert
!(dictionary
.len() < ffi
::uInt
::MAX
as usize);
522 ffi
::inflateSetDictionary(stream
, dictionary
.as_ptr(), dictionary
.len() as ffi
::uInt
)
526 ffi
::MZ_STREAM_ERROR
=> decompress_failed(self.inner
.inner
.msg()),
527 ffi
::MZ_DATA_ERROR
=> decompress_need_dict(stream
.adler
as u32),
528 ffi
::MZ_OK
=> Ok(stream
.adler
as u32),
529 c
=> panic
!("unknown return code: {}", c
),
533 /// Performs the equivalent of replacing this decompression state with a
534 /// freshly allocated copy.
536 /// This function may not allocate memory, though, and attempts to reuse any
537 /// previously existing resources.
539 /// The argument provided here indicates whether the reset state will
540 /// attempt to decode a zlib header first or not.
541 pub fn reset(&mut self, zlib_header
: bool
) {
542 self.inner
.reset(zlib_header
);
546 impl Error
for DecompressError {}
548 impl DecompressError
{
549 /// Retrieve the implementation's message about why the operation failed, if one exists.
550 pub fn message(&self) -> Option
<&str> {
552 DecompressErrorInner
::General { msg }
=> msg
.get(),
558 impl From
<DecompressError
> for io
::Error
{
559 fn from(data
: DecompressError
) -> io
::Error
{
560 io
::Error
::new(io
::ErrorKind
::Other
, data
)
564 impl fmt
::Display
for DecompressError
{
565 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
566 let msg
= match &self.0 {
567 DecompressErrorInner
::General { msg }
=> msg
.get(),
568 DecompressErrorInner
::NeedsDictionary { .. }
=> Some("requires a dictionary"),
571 Some(msg
) => write
!(f
, "deflate decompression error: {}", msg
),
572 None
=> write
!(f
, "deflate decompression error"),
577 impl Error
for CompressError {}
580 /// Retrieve the implementation's message about why the operation failed, if one exists.
581 pub fn message(&self) -> Option
<&str> {
586 impl From
<CompressError
> for io
::Error
{
587 fn from(data
: CompressError
) -> io
::Error
{
588 io
::Error
::new(io
::ErrorKind
::Other
, data
)
592 impl fmt
::Display
for CompressError
{
593 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
594 match self.msg
.get() {
595 Some(msg
) => write
!(f
, "deflate compression error: {}", msg
),
596 None
=> write
!(f
, "deflate compression error"),
606 use crate::{Compression, Decompress, FlushDecompress}
;
608 #[cfg(feature = "any_zlib")]
609 use crate::{Compress, FlushCompress}
;
614 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9,
615 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c,
616 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f,
617 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5,
618 0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67,
619 0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
620 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54,
621 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21,
622 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb,
623 0xe4, 0xa8, 0x00, 0x00, 0x00,
626 let mut decoded
= Vec
::with_capacity(data
.len() * 2);
628 let mut d
= Decompress
::new(false);
629 // decompressed whole deflate stream
631 .decompress_vec(&data
[10..], &mut decoded
, FlushDecompress
::Finish
)
634 // decompress data that has nothing to do with the deflate stream (this
636 drop(d
.decompress_vec(&[0], &mut decoded
, FlushDecompress
::None
));
641 let string
= "hello world".as_bytes();
642 let mut zlib
= Vec
::new();
643 let mut deflate
= Vec
::new();
645 let comp
= Compression
::default();
646 write
::ZlibEncoder
::new(&mut zlib
, comp
)
649 write
::DeflateEncoder
::new(&mut deflate
, comp
)
653 let mut dst
= [0; 1024];
654 let mut decoder
= Decompress
::new(true);
656 .decompress(&zlib
, &mut dst
, FlushDecompress
::Finish
)
658 assert_eq
!(decoder
.total_out(), string
.len() as u64);
659 assert
!(dst
.starts_with(string
));
661 decoder
.reset(false);
663 .decompress(&deflate
, &mut dst
, FlushDecompress
::Finish
)
665 assert_eq
!(decoder
.total_out(), string
.len() as u64);
666 assert
!(dst
.starts_with(string
));
669 #[cfg(feature = "any_zlib")]
671 fn set_dictionary_with_zlib_header() {
672 let string
= "hello, hello!".as_bytes();
673 let dictionary
= "hello".as_bytes();
675 let mut encoded
= Vec
::with_capacity(1024);
677 let mut encoder
= Compress
::new(Compression
::default(), true);
679 let dictionary_adler
= encoder
.set_dictionary(&dictionary
).unwrap();
682 .compress_vec(string
, &mut encoded
, FlushCompress
::Finish
)
685 assert_eq
!(encoder
.total_in(), string
.len() as u64);
686 assert_eq
!(encoder
.total_out(), encoded
.len() as u64);
688 let mut decoder
= Decompress
::new(true);
689 let mut decoded
= [0; 1024];
690 let decompress_error
= decoder
691 .decompress(&encoded
, &mut decoded
, FlushDecompress
::Finish
)
692 .expect_err("decompression should fail due to requiring a dictionary");
694 let required_adler
= decompress_error
.needs_dictionary()
695 .expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum");
697 assert_eq
!(required_adler
, dictionary_adler
,
698 "the Adler-32 checksum should match the value when the dictionary was set on the compressor");
700 let actual_adler
= decoder
.set_dictionary(&dictionary
).unwrap();
702 assert_eq
!(required_adler
, actual_adler
);
704 // Decompress the rest of the input to the remainder of the output buffer
705 let total_in
= decoder
.total_in();
706 let total_out
= decoder
.total_out();
708 let decompress_result
= decoder
.decompress(
709 &encoded
[total_in
as usize..],
710 &mut decoded
[total_out
as usize..],
711 FlushDecompress
::Finish
,
713 assert
!(decompress_result
.is_ok());
715 assert_eq
!(&decoded
[..decoder
.total_out() as usize], string
);
718 #[cfg(feature = "any_zlib")]
720 fn set_dictionary_raw() {
721 let string
= "hello, hello!".as_bytes();
722 let dictionary
= "hello".as_bytes();
724 let mut encoded
= Vec
::with_capacity(1024);
726 let mut encoder
= Compress
::new(Compression
::default(), false);
728 encoder
.set_dictionary(&dictionary
).unwrap();
731 .compress_vec(string
, &mut encoded
, FlushCompress
::Finish
)
734 assert_eq
!(encoder
.total_in(), string
.len() as u64);
735 assert_eq
!(encoder
.total_out(), encoded
.len() as u64);
737 let mut decoder
= Decompress
::new(false);
739 decoder
.set_dictionary(&dictionary
).unwrap();
741 let mut decoded
= [0; 1024];
742 let decompress_result
= decoder
.decompress(&encoded
, &mut decoded
, FlushDecompress
::Finish
);
744 assert
!(decompress_result
.is_ok());
746 assert_eq
!(&decoded
[..decoder
.total_out() as usize], string
);
749 #[cfg(feature = "any_zlib")]
751 fn test_gzip_flate() {
752 let string
= "hello, hello!".as_bytes();
754 let mut encoded
= Vec
::with_capacity(1024);
756 let mut encoder
= Compress
::new_gzip(Compression
::default(), 9);
759 .compress_vec(string
, &mut encoded
, FlushCompress
::Finish
)
762 assert_eq
!(encoder
.total_in(), string
.len() as u64);
763 assert_eq
!(encoder
.total_out(), encoded
.len() as u64);
765 let mut decoder
= Decompress
::new_gzip(9);
767 let mut decoded
= [0; 1024];
769 .decompress(&encoded
, &mut decoded
, FlushDecompress
::Finish
)
772 assert_eq
!(&decoded
[..decoder
.total_out() as usize], string
);
775 #[cfg(feature = "any_zlib")]
777 fn test_error_message() {
778 let mut decoder
= Decompress
::new(false);
779 let mut decoded
= [0; 128];
780 let garbage
= b
"xbvxzi";
783 .decompress(&*garbage
, &mut decoded
, FlushDecompress
::Finish
)
786 assert_eq
!(err
.message(), Some("invalid stored block lengths"));