1 use std::error::Error;
2 use std::fmt;
3 use std::io;
4 
5 use crate::ffi::{self, Backend, Deflate, DeflateBackend, ErrorMessage, Inflate, InflateBackend};
6 use crate::Compression;
7 
8 /// Raw in-memory compression stream for blocks of data.
9 ///
10 /// This type is the building block for the I/O streams in the rest of this
11 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
12 /// maximally flexible in terms of accepting input from any source and being
13 /// able to produce output to any memory location.
14 ///
15 /// It is recommended to use the I/O stream adaptors over this type as they're
16 /// easier to use.
17 ///
18 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
19 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
20 #[derive(Debug)]
21 pub struct Compress {
22     inner: Deflate,
23 }
24 
25 /// Raw in-memory decompression stream for blocks of data.
26 ///
27 /// This type is the building block for the I/O streams in the rest of this
28 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
29 /// maximally flexible in terms of accepting input from any source and being
30 /// able to produce output to any memory location.
31 ///
32 /// It is recommended to use the I/O stream adaptors over this type as they're
33 /// easier to use.
34 ///
35 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
36 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
37 #[derive(Debug)]
38 pub struct Decompress {
39     inner: Inflate,
40 }
41 
42 /// Values which indicate the form of flushing to be used when compressing
43 /// in-memory data.
44 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
45 #[non_exhaustive]
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,
51 
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.
55     ///
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,
60 
61     /// All pending output is flushed to the output buffer, but the output is
62     /// not aligned to a byte boundary.
63     ///
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,
70 
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.
74     ///
75     /// Using this option too often can seriously degrade compression.
76     Full = ffi::MZ_FULL_FLUSH as isize,
77 
78     /// Pending input is processed and pending output is flushed.
79     ///
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,
83 }
84 
85 /// Values which indicate the form of flushing to be used when
86 /// decompressing in-memory data.
87 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
88 #[non_exhaustive]
89 pub enum FlushDecompress {
90     /// A typical parameter for passing to compression/decompression functions,
91     /// this indicates that the underlying stream to decide how much data to
92     /// accumulate before producing output in order to maximize compression.
93     None = ffi::MZ_NO_FLUSH as isize,
94 
95     /// All pending output is flushed to the output buffer and the output is
96     /// aligned on a byte boundary so that the decompressor can get all input
97     /// data available so far.
98     ///
99     /// Flushing may degrade compression for some compression algorithms and so
100     /// it should only be used when necessary. This will complete the current
101     /// deflate block and follow it with an empty stored block.
102     Sync = ffi::MZ_SYNC_FLUSH as isize,
103 
104     /// Pending input is processed and pending output is flushed.
105     ///
106     /// The return value may indicate that the stream is not yet done and more
107     /// data has yet to be processed.
108     Finish = ffi::MZ_FINISH as isize,
109 }
110 
111 /// The inner state for an error when decompressing
112 #[derive(Debug)]
113 pub(crate) enum DecompressErrorInner {
114     General { msg: ErrorMessage },
115     NeedsDictionary(u32),
116 }
117 
118 /// Error returned when a decompression object finds that the input stream of
119 /// bytes was not a valid input stream of bytes.
120 #[derive(Debug)]
121 pub struct DecompressError(pub(crate) DecompressErrorInner);
122 
123 impl DecompressError {
124     /// Indicates whether decompression failed due to requiring a dictionary.
125     ///
126     /// The resulting integer is the Adler-32 checksum of the dictionary
127     /// required.
needs_dictionary(&self) -> Option<u32>128     pub fn needs_dictionary(&self) -> Option<u32> {
129         match self.0 {
130             DecompressErrorInner::NeedsDictionary(adler) => Some(adler),
131             _ => None,
132         }
133     }
134 }
135 
136 #[inline]
decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError>137 pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> {
138     Err(DecompressError(DecompressErrorInner::General { msg }))
139 }
140 
141 #[inline]
decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError>142 pub(crate) fn decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError> {
143     Err(DecompressError(DecompressErrorInner::NeedsDictionary(
144         adler,
145     )))
146 }
147 
148 /// Error returned when a compression object is used incorrectly or otherwise
149 /// generates an error.
150 #[derive(Debug)]
151 pub struct CompressError {
152     pub(crate) msg: ErrorMessage,
153 }
154 
155 #[inline]
compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError>156 pub(crate) fn compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError> {
157     Err(CompressError { msg })
158 }
159 
160 /// Possible status results of compressing some data or successfully
161 /// decompressing a block of data.
162 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
163 pub enum Status {
164     /// Indicates success.
165     ///
166     /// Means that more input may be needed but isn't available
167     /// and/or there's more output to be written but the output buffer is full.
168     Ok,
169 
170     /// Indicates that forward progress is not possible due to input or output
171     /// buffers being empty.
172     ///
173     /// For compression it means the input buffer needs some more data or the
174     /// output buffer needs to be freed up before trying again.
175     ///
176     /// For decompression this means that more input is needed to continue or
177     /// the output buffer isn't large enough to contain the result. The function
178     /// can be called again after fixing both.
179     BufError,
180 
181     /// Indicates that all input has been consumed and all output bytes have
182     /// been written. Decompression/compression should not be called again.
183     ///
184     /// For decompression with zlib streams the adler-32 of the decompressed
185     /// data has also been verified.
186     StreamEnd,
187 }
188 
189 impl Compress {
190     /// Creates a new object ready for compressing data that it's given.
191     ///
192     /// The `level` argument here indicates what level of compression is going
193     /// to be performed, and the `zlib_header` argument indicates whether the
194     /// output data should have a zlib header or not.
new(level: Compression, zlib_header: bool) -> Compress195     pub fn new(level: Compression, zlib_header: bool) -> Compress {
196         Compress {
197             inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
198         }
199     }
200 
201     /// Creates a new object ready for compressing data that it's given.
202     ///
203     /// The `level` argument here indicates what level of compression is going
204     /// to be performed, and the `zlib_header` argument indicates whether the
205     /// output data should have a zlib header or not. The `window_bits` parameter
206     /// indicates the base-2 logarithm of the sliding window size and must be
207     /// between 9 and 15.
208     ///
209     /// # Panics
210     ///
211     /// If `window_bits` does not fall into the range 9 ..= 15,
212     /// `new_with_window_bits` will panic.
213     #[cfg(feature = "any_zlib")]
new_with_window_bits( level: Compression, zlib_header: bool, window_bits: u8, ) -> Compress214     pub fn new_with_window_bits(
215         level: Compression,
216         zlib_header: bool,
217         window_bits: u8,
218     ) -> Compress {
219         assert!(
220             window_bits > 8 && window_bits < 16,
221             "window_bits must be within 9 ..= 15"
222         );
223         Compress {
224             inner: Deflate::make(level, zlib_header, window_bits),
225         }
226     }
227 
228     /// Creates a new object ready for compressing data that it's given.
229     ///
230     /// The `level` argument here indicates what level of compression is going
231     /// to be performed.
232     ///
233     /// The Compress object produced by this constructor outputs gzip headers
234     /// for the compressed data.
235     ///
236     /// # Panics
237     ///
238     /// If `window_bits` does not fall into the range 9 ..= 15,
239     /// `new_with_window_bits` will panic.
240     #[cfg(feature = "any_zlib")]
new_gzip(level: Compression, window_bits: u8) -> Compress241     pub fn new_gzip(level: Compression, window_bits: u8) -> Compress {
242         assert!(
243             window_bits > 8 && window_bits < 16,
244             "window_bits must be within 9 ..= 15"
245         );
246         Compress {
247             inner: Deflate::make(level, true, window_bits + 16),
248         }
249     }
250 
251     /// Returns the total number of input bytes which have been processed by
252     /// this compression object.
total_in(&self) -> u64253     pub fn total_in(&self) -> u64 {
254         self.inner.total_in()
255     }
256 
257     /// Returns the total number of output bytes which have been produced by
258     /// this compression object.
total_out(&self) -> u64259     pub fn total_out(&self) -> u64 {
260         self.inner.total_out()
261     }
262 
263     /// Specifies the compression dictionary to use.
264     ///
265     /// Returns the Adler-32 checksum of the dictionary.
266     #[cfg(feature = "any_zlib")]
set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError>267     pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
268         let stream = &mut *self.inner.inner.stream_wrapper;
269         stream.msg = std::ptr::null_mut();
270         let rc = unsafe {
271             assert!(dictionary.len() < ffi::uInt::MAX as usize);
272             ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
273         };
274 
275         match rc {
276             ffi::MZ_STREAM_ERROR => compress_failed(self.inner.inner.msg()),
277             ffi::MZ_OK => Ok(stream.adler as u32),
278             c => panic!("unknown return code: {}", c),
279         }
280     }
281 
282     /// Quickly resets this compressor without having to reallocate anything.
283     ///
284     /// This is equivalent to dropping this object and then creating a new one.
reset(&mut self)285     pub fn reset(&mut self) {
286         self.inner.reset();
287     }
288 
289     /// Dynamically updates the compression level.
290     ///
291     /// This can be used to switch between compression levels for different
292     /// kinds of data, or it can be used in conjunction with a call to reset
293     /// to reuse the compressor.
294     ///
295     /// This may return an error if there wasn't enough output space to complete
296     /// the compression of the available input data before changing the
297     /// compression level. Flushing the stream before calling this method
298     /// ensures that the function will succeed on the first call.
299     #[cfg(feature = "any_zlib")]
set_level(&mut self, level: Compression) -> Result<(), CompressError>300     pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
301         use std::os::raw::c_int;
302         let stream = &mut *self.inner.inner.stream_wrapper;
303         stream.msg = std::ptr::null_mut();
304 
305         let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
306 
307         match rc {
308             ffi::MZ_OK => Ok(()),
309             ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
310             c => panic!("unknown return code: {}", c),
311         }
312     }
313 
314     /// Compresses the input data into the output, consuming only as much
315     /// input as needed and writing as much output as possible.
316     ///
317     /// The flush option can be any of the available `FlushCompress` parameters.
318     ///
319     /// To learn how much data was consumed or how much output was produced, use
320     /// the `total_in` and `total_out` functions before/after this is called.
compress( &mut self, input: &[u8], output: &mut [u8], flush: FlushCompress, ) -> Result<Status, CompressError>321     pub fn compress(
322         &mut self,
323         input: &[u8],
324         output: &mut [u8],
325         flush: FlushCompress,
326     ) -> Result<Status, CompressError> {
327         self.inner.compress(input, output, flush)
328     }
329 
330     /// Compresses the input data into the extra space of the output, consuming
331     /// only as much input as needed and writing as much output as possible.
332     ///
333     /// This function has the same semantics as `compress`, except that the
334     /// length of `vec` is managed by this function. This will not reallocate
335     /// the vector provided or attempt to grow it, so space for the output must
336     /// be reserved in the output vector by the caller before calling this
337     /// function.
compress_vec( &mut self, input: &[u8], output: &mut Vec<u8>, flush: FlushCompress, ) -> Result<Status, CompressError>338     pub fn compress_vec(
339         &mut self,
340         input: &[u8],
341         output: &mut Vec<u8>,
342         flush: FlushCompress,
343     ) -> Result<Status, CompressError> {
344         write_to_spare_capacity_of_vec(output, |out| {
345             let before = self.total_out();
346             let ret = self.compress(input, out, flush);
347             let bytes_written = self.total_out() - before;
348             (bytes_written as usize, ret)
349         })
350     }
351 }
352 
353 impl Decompress {
354     /// Creates a new object ready for decompressing data that it's given.
355     ///
356     /// The `zlib_header` argument indicates whether the input data is expected
357     /// to have a zlib header or not.
new(zlib_header: bool) -> Decompress358     pub fn new(zlib_header: bool) -> Decompress {
359         Decompress {
360             inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
361         }
362     }
363 
364     /// Creates a new object ready for decompressing data that it's given.
365     ///
366     /// The `zlib_header` argument indicates whether the input data is expected
367     /// to have a zlib header or not. The `window_bits` parameter indicates the
368     /// base-2 logarithm of the sliding window size and must be between 9 and 15.
369     ///
370     /// # Panics
371     ///
372     /// If `window_bits` does not fall into the range 9 ..= 15,
373     /// `new_with_window_bits` will panic.
374     #[cfg(feature = "any_zlib")]
new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress375     pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
376         assert!(
377             window_bits > 8 && window_bits < 16,
378             "window_bits must be within 9 ..= 15"
379         );
380         Decompress {
381             inner: Inflate::make(zlib_header, window_bits),
382         }
383     }
384 
385     /// Creates a new object ready for decompressing data that it's given.
386     ///
387     /// The Decompress object produced by this constructor expects gzip headers
388     /// for the compressed data.
389     ///
390     /// # Panics
391     ///
392     /// If `window_bits` does not fall into the range 9 ..= 15,
393     /// `new_with_window_bits` will panic.
394     #[cfg(feature = "any_zlib")]
new_gzip(window_bits: u8) -> Decompress395     pub fn new_gzip(window_bits: u8) -> Decompress {
396         assert!(
397             window_bits > 8 && window_bits < 16,
398             "window_bits must be within 9 ..= 15"
399         );
400         Decompress {
401             inner: Inflate::make(true, window_bits + 16),
402         }
403     }
404 
405     /// Returns the total number of input bytes which have been processed by
406     /// this decompression object.
total_in(&self) -> u64407     pub fn total_in(&self) -> u64 {
408         self.inner.total_in()
409     }
410 
411     /// Returns the total number of output bytes which have been produced by
412     /// this decompression object.
total_out(&self) -> u64413     pub fn total_out(&self) -> u64 {
414         self.inner.total_out()
415     }
416 
417     /// Decompresses the input data into the output, consuming only as much
418     /// input as needed and writing as much output as possible.
419     ///
420     /// The flush option can be any of the available `FlushDecompress` parameters.
421     ///
422     /// If the first call passes `FlushDecompress::Finish` it is assumed that
423     /// the input and output buffers are both sized large enough to decompress
424     /// the entire stream in a single call.
425     ///
426     /// A flush value of `FlushDecompress::Finish` indicates that there are no
427     /// more source bytes available beside what's already in the input buffer,
428     /// and the output buffer is large enough to hold the rest of the
429     /// decompressed data.
430     ///
431     /// To learn how much data was consumed or how much output was produced, use
432     /// the `total_in` and `total_out` functions before/after this is called.
433     ///
434     /// # Errors
435     ///
436     /// If the input data to this instance of `Decompress` is not a valid
437     /// zlib/deflate stream then this function may return an instance of
438     /// `DecompressError` to indicate that the stream of input bytes is corrupted.
decompress( &mut self, input: &[u8], output: &mut [u8], flush: FlushDecompress, ) -> Result<Status, DecompressError>439     pub fn decompress(
440         &mut self,
441         input: &[u8],
442         output: &mut [u8],
443         flush: FlushDecompress,
444     ) -> Result<Status, DecompressError> {
445         self.inner.decompress(input, output, flush)
446     }
447 
448     /// Decompresses the input data into the extra space in the output vector
449     /// specified by `output`.
450     ///
451     /// This function has the same semantics as `decompress`, except that the
452     /// length of `vec` is managed by this function. This will not reallocate
453     /// the vector provided or attempt to grow it, so space for the output must
454     /// be reserved in the output vector by the caller before calling this
455     /// function.
456     ///
457     /// # Errors
458     ///
459     /// If the input data to this instance of `Decompress` is not a valid
460     /// zlib/deflate stream then this function may return an instance of
461     /// `DecompressError` to indicate that the stream of input bytes is corrupted.
decompress_vec( &mut self, input: &[u8], output: &mut Vec<u8>, flush: FlushDecompress, ) -> Result<Status, DecompressError>462     pub fn decompress_vec(
463         &mut self,
464         input: &[u8],
465         output: &mut Vec<u8>,
466         flush: FlushDecompress,
467     ) -> Result<Status, DecompressError> {
468         write_to_spare_capacity_of_vec(output, |out| {
469             let before = self.total_out();
470             let ret = self.decompress(input, out, flush);
471             let bytes_written = self.total_out() - before;
472             (bytes_written as usize, ret)
473         })
474     }
475 
476     /// Specifies the decompression dictionary to use.
477     #[cfg(feature = "any_zlib")]
set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError>478     pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
479         let stream = &mut *self.inner.inner.stream_wrapper;
480         stream.msg = std::ptr::null_mut();
481         let rc = unsafe {
482             assert!(dictionary.len() < ffi::uInt::MAX as usize);
483             ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
484         };
485 
486         match rc {
487             ffi::MZ_STREAM_ERROR => decompress_failed(self.inner.inner.msg()),
488             ffi::MZ_DATA_ERROR => decompress_need_dict(stream.adler as u32),
489             ffi::MZ_OK => Ok(stream.adler as u32),
490             c => panic!("unknown return code: {}", c),
491         }
492     }
493 
494     /// Performs the equivalent of replacing this decompression state with a
495     /// freshly allocated copy.
496     ///
497     /// This function may not allocate memory, though, and attempts to reuse any
498     /// previously existing resources.
499     ///
500     /// The argument provided here indicates whether the reset state will
501     /// attempt to decode a zlib header first or not.
reset(&mut self, zlib_header: bool)502     pub fn reset(&mut self, zlib_header: bool) {
503         self.inner.reset(zlib_header);
504     }
505 }
506 
507 impl Error for DecompressError {}
508 
509 impl DecompressError {
510     /// Retrieve the implementation's message about why the operation failed, if one exists.
message(&self) -> Option<&str>511     pub fn message(&self) -> Option<&str> {
512         match &self.0 {
513             DecompressErrorInner::General { msg } => msg.get(),
514             _ => None,
515         }
516     }
517 }
518 
519 impl From<DecompressError> for io::Error {
from(data: DecompressError) -> io::Error520     fn from(data: DecompressError) -> io::Error {
521         io::Error::new(io::ErrorKind::Other, data)
522     }
523 }
524 
525 impl fmt::Display for DecompressError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result526     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
527         let msg = match &self.0 {
528             DecompressErrorInner::General { msg } => msg.get(),
529             DecompressErrorInner::NeedsDictionary { .. } => Some("requires a dictionary"),
530         };
531         match msg {
532             Some(msg) => write!(f, "deflate decompression error: {}", msg),
533             None => write!(f, "deflate decompression error"),
534         }
535     }
536 }
537 
538 impl Error for CompressError {}
539 
540 impl CompressError {
541     /// Retrieve the implementation's message about why the operation failed, if one exists.
message(&self) -> Option<&str>542     pub fn message(&self) -> Option<&str> {
543         self.msg.get()
544     }
545 }
546 
547 impl From<CompressError> for io::Error {
from(data: CompressError) -> io::Error548     fn from(data: CompressError) -> io::Error {
549         io::Error::new(io::ErrorKind::Other, data)
550     }
551 }
552 
553 impl fmt::Display for CompressError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result554     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
555         match self.msg.get() {
556             Some(msg) => write!(f, "deflate compression error: {}", msg),
557             None => write!(f, "deflate compression error"),
558         }
559     }
560 }
561 
562 /// Allows `writer` to write data into the spare capacity of the `output` vector.
563 /// This will not reallocate the vector provided or attempt to grow it, so space
564 /// for the `output` must be reserved by the caller before calling this
565 /// function.
566 ///
567 /// `writer` needs to return the number of bytes written (and can also return
568 /// another arbitrary return value).
write_to_spare_capacity_of_vec<T>( output: &mut Vec<u8>, writer: impl FnOnce(&mut [u8]) -> (usize, T), ) -> T569 fn write_to_spare_capacity_of_vec<T>(
570     output: &mut Vec<u8>,
571     writer: impl FnOnce(&mut [u8]) -> (usize, T),
572 ) -> T {
573     let cap = output.capacity();
574     let len = output.len();
575 
576     output.resize(output.capacity(), 0);
577     let (bytes_written, ret) = writer(&mut output[len..]);
578 
579     let new_len = core::cmp::min(len + bytes_written, cap); // Sanitizes `bytes_written`.
580     output.resize(new_len, 0 /* unused */);
581 
582     ret
583 }
584 
585 #[cfg(test)]
586 mod tests {
587     use std::io::Write;
588 
589     use crate::write;
590     use crate::{Compression, Decompress, FlushDecompress};
591 
592     #[cfg(feature = "any_zlib")]
593     use crate::{Compress, FlushCompress};
594 
595     #[test]
issue51()596     fn issue51() {
597         let data = vec![
598             0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9,
599             0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c,
600             0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f,
601             0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5,
602             0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67,
603             0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
604             0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54,
605             0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21,
606             0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb,
607             0xe4, 0xa8, 0x00, 0x00, 0x00,
608         ];
609 
610         let mut decoded = Vec::with_capacity(data.len() * 2);
611 
612         let mut d = Decompress::new(false);
613         // decompressed whole deflate stream
614         assert!(d
615             .decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish)
616             .is_ok());
617 
618         // decompress data that has nothing to do with the deflate stream (this
619         // used to panic)
620         drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
621     }
622 
623     #[test]
reset()624     fn reset() {
625         let string = "hello world".as_bytes();
626         let mut zlib = Vec::new();
627         let mut deflate = Vec::new();
628 
629         let comp = Compression::default();
630         write::ZlibEncoder::new(&mut zlib, comp)
631             .write_all(string)
632             .unwrap();
633         write::DeflateEncoder::new(&mut deflate, comp)
634             .write_all(string)
635             .unwrap();
636 
637         let mut dst = [0; 1024];
638         let mut decoder = Decompress::new(true);
639         decoder
640             .decompress(&zlib, &mut dst, FlushDecompress::Finish)
641             .unwrap();
642         assert_eq!(decoder.total_out(), string.len() as u64);
643         assert!(dst.starts_with(string));
644 
645         decoder.reset(false);
646         decoder
647             .decompress(&deflate, &mut dst, FlushDecompress::Finish)
648             .unwrap();
649         assert_eq!(decoder.total_out(), string.len() as u64);
650         assert!(dst.starts_with(string));
651     }
652 
653     #[cfg(feature = "any_zlib")]
654     #[test]
set_dictionary_with_zlib_header()655     fn set_dictionary_with_zlib_header() {
656         let string = "hello, hello!".as_bytes();
657         let dictionary = "hello".as_bytes();
658 
659         let mut encoded = Vec::with_capacity(1024);
660 
661         let mut encoder = Compress::new(Compression::default(), true);
662 
663         let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap();
664 
665         encoder
666             .compress_vec(string, &mut encoded, FlushCompress::Finish)
667             .unwrap();
668 
669         assert_eq!(encoder.total_in(), string.len() as u64);
670         assert_eq!(encoder.total_out(), encoded.len() as u64);
671 
672         let mut decoder = Decompress::new(true);
673         let mut decoded = [0; 1024];
674         let decompress_error = decoder
675             .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
676             .expect_err("decompression should fail due to requiring a dictionary");
677 
678         let required_adler = decompress_error.needs_dictionary()
679             .expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum");
680 
681         assert_eq!(required_adler, dictionary_adler,
682             "the Adler-32 checksum should match the value when the dictionary was set on the compressor");
683 
684         let actual_adler = decoder.set_dictionary(&dictionary).unwrap();
685 
686         assert_eq!(required_adler, actual_adler);
687 
688         // Decompress the rest of the input to the remainder of the output buffer
689         let total_in = decoder.total_in();
690         let total_out = decoder.total_out();
691 
692         let decompress_result = decoder.decompress(
693             &encoded[total_in as usize..],
694             &mut decoded[total_out as usize..],
695             FlushDecompress::Finish,
696         );
697         assert!(decompress_result.is_ok());
698 
699         assert_eq!(&decoded[..decoder.total_out() as usize], string);
700     }
701 
702     #[cfg(feature = "any_zlib")]
703     #[test]
set_dictionary_raw()704     fn set_dictionary_raw() {
705         let string = "hello, hello!".as_bytes();
706         let dictionary = "hello".as_bytes();
707 
708         let mut encoded = Vec::with_capacity(1024);
709 
710         let mut encoder = Compress::new(Compression::default(), false);
711 
712         encoder.set_dictionary(&dictionary).unwrap();
713 
714         encoder
715             .compress_vec(string, &mut encoded, FlushCompress::Finish)
716             .unwrap();
717 
718         assert_eq!(encoder.total_in(), string.len() as u64);
719         assert_eq!(encoder.total_out(), encoded.len() as u64);
720 
721         let mut decoder = Decompress::new(false);
722 
723         decoder.set_dictionary(&dictionary).unwrap();
724 
725         let mut decoded = [0; 1024];
726         let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish);
727 
728         assert!(decompress_result.is_ok());
729 
730         assert_eq!(&decoded[..decoder.total_out() as usize], string);
731     }
732 
733     #[cfg(feature = "any_zlib")]
734     #[test]
test_gzip_flate()735     fn test_gzip_flate() {
736         let string = "hello, hello!".as_bytes();
737 
738         let mut encoded = Vec::with_capacity(1024);
739 
740         let mut encoder = Compress::new_gzip(Compression::default(), 9);
741 
742         encoder
743             .compress_vec(string, &mut encoded, FlushCompress::Finish)
744             .unwrap();
745 
746         assert_eq!(encoder.total_in(), string.len() as u64);
747         assert_eq!(encoder.total_out(), encoded.len() as u64);
748 
749         let mut decoder = Decompress::new_gzip(9);
750 
751         let mut decoded = [0; 1024];
752         decoder
753             .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
754             .unwrap();
755 
756         assert_eq!(&decoded[..decoder.total_out() as usize], string);
757     }
758 
759     #[cfg(feature = "any_zlib")]
760     #[test]
test_error_message()761     fn test_error_message() {
762         let mut decoder = Decompress::new(false);
763         let mut decoded = [0; 128];
764         let garbage = b"xbvxzi";
765 
766         let err = decoder
767             .decompress(&*garbage, &mut decoded, FlushDecompress::Finish)
768             .unwrap_err();
769 
770         assert_eq!(err.message(), Some("invalid stored block lengths"));
771     }
772 }
773