• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::error::Error;
2 use std::fmt;
3 use std::io;
4 use std::slice;
5 
6 use crate::ffi::{self, Backend, Deflate, DeflateBackend, ErrorMessage, Inflate, InflateBackend};
7 use crate::Compression;
8 
9 /// Raw in-memory compression stream for blocks of data.
10 ///
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.
15 ///
16 /// It is recommended to use the I/O stream adaptors over this type as they're
17 /// easier to use.
18 ///
19 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
20 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
21 #[derive(Debug)]
22 pub struct Compress {
23     inner: Deflate,
24 }
25 
26 /// Raw in-memory decompression stream for blocks of data.
27 ///
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.
32 ///
33 /// It is recommended to use the I/O stream adaptors over this type as they're
34 /// easier to use.
35 ///
36 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
37 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
38 #[derive(Debug)]
39 pub struct Decompress {
40     inner: Inflate,
41 }
42 
43 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
44 /// Values which indicate the form of flushing to be used when compressing
45 /// in-memory data.
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 decompessor 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     #[doc(hidden)]
85     _Nonexhaustive,
86 }
87 
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,
96 
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.
100     ///
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,
105 
106     /// Pending input is processed and pending output is flushed.
107     ///
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,
111 
112     #[doc(hidden)]
113     _Nonexhaustive,
114 }
115 
116 /// The inner state for an error when decompressing
117 #[derive(Debug)]
118 pub(crate) enum DecompressErrorInner {
119     General { msg: ErrorMessage },
120     NeedsDictionary(u32),
121 }
122 
123 /// Error returned when a decompression object finds that the input stream of
124 /// bytes was not a valid input stream of bytes.
125 #[derive(Debug)]
126 pub struct DecompressError(pub(crate) DecompressErrorInner);
127 
128 impl DecompressError {
129     /// Indicates whether decompression failed due to requiring a dictionary.
130     ///
131     /// The resulting integer is the Adler-32 checksum of the dictionary
132     /// required.
needs_dictionary(&self) -> Option<u32>133     pub fn needs_dictionary(&self) -> Option<u32> {
134         match self.0 {
135             DecompressErrorInner::NeedsDictionary(adler) => Some(adler),
136             _ => None,
137         }
138     }
139 }
140 
141 #[inline]
decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError>142 pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> {
143     Err(DecompressError(DecompressErrorInner::General { msg }))
144 }
145 
146 #[inline]
decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError>147 pub(crate) fn decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError> {
148     Err(DecompressError(DecompressErrorInner::NeedsDictionary(
149         adler,
150     )))
151 }
152 
153 /// Error returned when a compression object is used incorrectly or otherwise
154 /// generates an error.
155 #[derive(Debug)]
156 pub struct CompressError {
157     pub(crate) msg: ErrorMessage,
158 }
159 
160 #[inline]
compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError>161 pub(crate) fn compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError> {
162     Err(CompressError { msg })
163 }
164 
165 /// Possible status results of compressing some data or successfully
166 /// decompressing a block of data.
167 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
168 pub enum Status {
169     /// Indicates success.
170     ///
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.
173     Ok,
174 
175     /// Indicates that forward progress is not possible due to input or output
176     /// buffers being empty.
177     ///
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.
180     ///
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.
184     BufError,
185 
186     /// Indicates that all input has been consumed and all output bytes have
187     /// been written. Decompression/compression should not be called again.
188     ///
189     /// For decompression with zlib streams the adler-32 of the decompressed
190     /// data has also been verified.
191     StreamEnd,
192 }
193 
194 impl Compress {
195     /// Creates a new object ready for compressing data that it's given.
196     ///
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.
new(level: Compression, zlib_header: bool) -> Compress200     pub fn new(level: Compression, zlib_header: bool) -> Compress {
201         Compress {
202             inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
203         }
204     }
205 
206     /// Creates a new object ready for compressing data that it's given.
207     ///
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.
213     ///
214     /// # Panics
215     ///
216     /// If `window_bits` does not fall into the range 9 ..= 15,
217     /// `new_with_window_bits` will panic.
218     ///
219     /// # Note
220     ///
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")]
new_with_window_bits( level: Compression, zlib_header: bool, window_bits: u8, ) -> Compress224     pub fn new_with_window_bits(
225         level: Compression,
226         zlib_header: bool,
227         window_bits: u8,
228     ) -> Compress {
229         assert!(
230             window_bits > 8 && window_bits < 16,
231             "window_bits must be within 9 ..= 15"
232         );
233         Compress {
234             inner: Deflate::make(level, zlib_header, window_bits),
235         }
236     }
237 
238     /// Creates a new object ready for compressing data that it's given.
239     ///
240     /// The `level` argument here indicates what level of compression is going
241     /// to be performed.
242     ///
243     /// The Compress object produced by this constructor outputs gzip headers
244     /// for the compressed data.
245     ///
246     /// # Panics
247     ///
248     /// If `window_bits` does not fall into the range 9 ..= 15,
249     /// `new_with_window_bits` will panic.
250     ///
251     /// # Note
252     ///
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")]
new_gzip(level: Compression, window_bits: u8) -> Compress256     pub fn new_gzip(level: Compression, window_bits: u8) -> Compress {
257         assert!(
258             window_bits > 8 && window_bits < 16,
259             "window_bits must be within 9 ..= 15"
260         );
261         Compress {
262             inner: Deflate::make(level, true, window_bits + 16),
263         }
264     }
265 
266     /// Returns the total number of input bytes which have been processed by
267     /// this compression object.
total_in(&self) -> u64268     pub fn total_in(&self) -> u64 {
269         self.inner.total_in()
270     }
271 
272     /// Returns the total number of output bytes which have been produced by
273     /// this compression object.
total_out(&self) -> u64274     pub fn total_out(&self) -> u64 {
275         self.inner.total_out()
276     }
277 
278     /// Specifies the compression dictionary to use.
279     ///
280     /// Returns the Adler-32 checksum of the dictionary.
281     #[cfg(feature = "any_zlib")]
set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError>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();
285         let rc = unsafe {
286             assert!(dictionary.len() < ffi::uInt::max_value() as usize);
287             ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
288         };
289 
290         match rc {
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),
294         }
295     }
296 
297     /// Quickly resets this compressor without having to reallocate anything.
298     ///
299     /// This is equivalent to dropping this object and then creating a new one.
reset(&mut self)300     pub fn reset(&mut self) {
301         self.inner.reset();
302     }
303 
304     /// Dynamically updates the compression level.
305     ///
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.
309     ///
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")]
set_level(&mut self, level: Compression) -> Result<(), CompressError>315     pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
316         use libc::c_int;
317         let stream = &mut *self.inner.inner.stream_wrapper;
318         stream.msg = std::ptr::null_mut();
319 
320         let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
321 
322         match rc {
323             ffi::MZ_OK => Ok(()),
324             ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
325             c => panic!("unknown return code: {}", c),
326         }
327     }
328 
329     /// Compresses the input data into the output, consuming only as much
330     /// input as needed and writing as much output as possible.
331     ///
332     /// The flush option can be any of the available `FlushCompress` parameters.
333     ///
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.
compress( &mut self, input: &[u8], output: &mut [u8], flush: FlushCompress, ) -> Result<Status, CompressError>336     pub fn compress(
337         &mut self,
338         input: &[u8],
339         output: &mut [u8],
340         flush: FlushCompress,
341     ) -> Result<Status, CompressError> {
342         self.inner.compress(input, output, flush)
343     }
344 
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.
347     ///
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
352     /// function.
compress_vec( &mut self, input: &[u8], output: &mut Vec<u8>, flush: FlushCompress, ) -> Result<Status, CompressError>353     pub fn compress_vec(
354         &mut self,
355         input: &[u8],
356         output: &mut Vec<u8>,
357         flush: FlushCompress,
358     ) -> Result<Status, CompressError> {
359         let cap = output.capacity();
360         let len = output.len();
361 
362         unsafe {
363             let before = self.total_out();
364             let ret = {
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)
368             };
369             output.set_len((self.total_out() - before) as usize + len);
370             return ret;
371         }
372     }
373 }
374 
375 impl Decompress {
376     /// Creates a new object ready for decompressing data that it's given.
377     ///
378     /// The `zlib_header` argument indicates whether the input data is expected
379     /// to have a zlib header or not.
new(zlib_header: bool) -> Decompress380     pub fn new(zlib_header: bool) -> Decompress {
381         Decompress {
382             inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
383         }
384     }
385 
386     /// Creates a new object ready for decompressing data that it's given.
387     ///
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.
391     ///
392     /// # Panics
393     ///
394     /// If `window_bits` does not fall into the range 9 ..= 15,
395     /// `new_with_window_bits` will panic.
396     ///
397     /// # Note
398     ///
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")]
new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress402     pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
403         assert!(
404             window_bits > 8 && window_bits < 16,
405             "window_bits must be within 9 ..= 15"
406         );
407         Decompress {
408             inner: Inflate::make(zlib_header, window_bits),
409         }
410     }
411 
412     /// Creates a new object ready for decompressing data that it's given.
413     ///
414     /// The Deompress object produced by this constructor expects gzip headers
415     /// for the compressed data.
416     ///
417     /// # Panics
418     ///
419     /// If `window_bits` does not fall into the range 9 ..= 15,
420     /// `new_with_window_bits` will panic.
421     ///
422     /// # Note
423     ///
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")]
new_gzip(window_bits: u8) -> Decompress427     pub fn new_gzip(window_bits: u8) -> Decompress {
428         assert!(
429             window_bits > 8 && window_bits < 16,
430             "window_bits must be within 9 ..= 15"
431         );
432         Decompress {
433             inner: Inflate::make(true, window_bits + 16),
434         }
435     }
436 
437     /// Returns the total number of input bytes which have been processed by
438     /// this decompression object.
total_in(&self) -> u64439     pub fn total_in(&self) -> u64 {
440         self.inner.total_in()
441     }
442 
443     /// Returns the total number of output bytes which have been produced by
444     /// this decompression object.
total_out(&self) -> u64445     pub fn total_out(&self) -> u64 {
446         self.inner.total_out()
447     }
448 
449     /// Decompresses the input data into the output, consuming only as much
450     /// input as needed and writing as much output as possible.
451     ///
452     /// The flush option can be any of the available `FlushDecompress` parameters.
453     ///
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.
457     ///
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.
462     ///
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.
465     ///
466     /// # Errors
467     ///
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.
decompress( &mut self, input: &[u8], output: &mut [u8], flush: FlushDecompress, ) -> Result<Status, DecompressError>471     pub fn decompress(
472         &mut self,
473         input: &[u8],
474         output: &mut [u8],
475         flush: FlushDecompress,
476     ) -> Result<Status, DecompressError> {
477         self.inner.decompress(input, output, flush)
478     }
479 
480     /// Decompresses the input data into the extra space in the output vector
481     /// specified by `output`.
482     ///
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
487     /// function.
488     ///
489     /// # Errors
490     ///
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.
decompress_vec( &mut self, input: &[u8], output: &mut Vec<u8>, flush: FlushDecompress, ) -> Result<Status, DecompressError>494     pub fn decompress_vec(
495         &mut self,
496         input: &[u8],
497         output: &mut Vec<u8>,
498         flush: FlushDecompress,
499     ) -> Result<Status, DecompressError> {
500         let cap = output.capacity();
501         let len = output.len();
502 
503         unsafe {
504             let before = self.total_out();
505             let ret = {
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)
509             };
510             output.set_len((self.total_out() - before) as usize + len);
511             return ret;
512         }
513     }
514 
515     /// Specifies the decompression dictionary to use.
516     #[cfg(feature = "any_zlib")]
set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError>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();
520         let rc = unsafe {
521             assert!(dictionary.len() < ffi::uInt::max_value() as usize);
522             ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
523         };
524 
525         match rc {
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),
530         }
531     }
532 
533     /// Performs the equivalent of replacing this decompression state with a
534     /// freshly allocated copy.
535     ///
536     /// This function may not allocate memory, though, and attempts to reuse any
537     /// previously existing resources.
538     ///
539     /// The argument provided here indicates whether the reset state will
540     /// attempt to decode a zlib header first or not.
reset(&mut self, zlib_header: bool)541     pub fn reset(&mut self, zlib_header: bool) {
542         self.inner.reset(zlib_header);
543     }
544 }
545 
546 impl Error for DecompressError {}
547 
548 impl DecompressError {
549     /// Retrieve the implementation's message about why the operation failed, if one exists.
message(&self) -> Option<&str>550     pub fn message(&self) -> Option<&str> {
551         match &self.0 {
552             DecompressErrorInner::General { msg } => msg.get(),
553             _ => None,
554         }
555     }
556 }
557 
558 impl From<DecompressError> for io::Error {
from(data: DecompressError) -> io::Error559     fn from(data: DecompressError) -> io::Error {
560         io::Error::new(io::ErrorKind::Other, data)
561     }
562 }
563 
564 impl fmt::Display for DecompressError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result565     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"),
569         };
570         match msg {
571             Some(msg) => write!(f, "deflate decompression error: {}", msg),
572             None => write!(f, "deflate decompression error"),
573         }
574     }
575 }
576 
577 impl Error for CompressError {}
578 
579 impl CompressError {
580     /// Retrieve the implementation's message about why the operation failed, if one exists.
message(&self) -> Option<&str>581     pub fn message(&self) -> Option<&str> {
582         self.msg.get()
583     }
584 }
585 
586 impl From<CompressError> for io::Error {
from(data: CompressError) -> io::Error587     fn from(data: CompressError) -> io::Error {
588         io::Error::new(io::ErrorKind::Other, data)
589     }
590 }
591 
592 impl fmt::Display for CompressError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result593     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"),
597         }
598     }
599 }
600 
601 #[cfg(test)]
602 mod tests {
603     use std::io::Write;
604 
605     use crate::write;
606     use crate::{Compression, Decompress, FlushDecompress};
607 
608     #[cfg(feature = "any_zlib")]
609     use crate::{Compress, FlushCompress};
610 
611     #[test]
issue51()612     fn issue51() {
613         let data = vec![
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,
624         ];
625 
626         let mut decoded = Vec::with_capacity(data.len() * 2);
627 
628         let mut d = Decompress::new(false);
629         // decompressed whole deflate stream
630         assert!(d
631             .decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish)
632             .is_ok());
633 
634         // decompress data that has nothing to do with the deflate stream (this
635         // used to panic)
636         drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
637     }
638 
639     #[test]
reset()640     fn reset() {
641         let string = "hello world".as_bytes();
642         let mut zlib = Vec::new();
643         let mut deflate = Vec::new();
644 
645         let comp = Compression::default();
646         write::ZlibEncoder::new(&mut zlib, comp)
647             .write_all(string)
648             .unwrap();
649         write::DeflateEncoder::new(&mut deflate, comp)
650             .write_all(string)
651             .unwrap();
652 
653         let mut dst = [0; 1024];
654         let mut decoder = Decompress::new(true);
655         decoder
656             .decompress(&zlib, &mut dst, FlushDecompress::Finish)
657             .unwrap();
658         assert_eq!(decoder.total_out(), string.len() as u64);
659         assert!(dst.starts_with(string));
660 
661         decoder.reset(false);
662         decoder
663             .decompress(&deflate, &mut dst, FlushDecompress::Finish)
664             .unwrap();
665         assert_eq!(decoder.total_out(), string.len() as u64);
666         assert!(dst.starts_with(string));
667     }
668 
669     #[cfg(feature = "any_zlib")]
670     #[test]
set_dictionary_with_zlib_header()671     fn set_dictionary_with_zlib_header() {
672         let string = "hello, hello!".as_bytes();
673         let dictionary = "hello".as_bytes();
674 
675         let mut encoded = Vec::with_capacity(1024);
676 
677         let mut encoder = Compress::new(Compression::default(), true);
678 
679         let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap();
680 
681         encoder
682             .compress_vec(string, &mut encoded, FlushCompress::Finish)
683             .unwrap();
684 
685         assert_eq!(encoder.total_in(), string.len() as u64);
686         assert_eq!(encoder.total_out(), encoded.len() as u64);
687 
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");
693 
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");
696 
697         assert_eq!(required_adler, dictionary_adler,
698             "the Adler-32 checksum should match the value when the dictionary was set on the compressor");
699 
700         let actual_adler = decoder.set_dictionary(&dictionary).unwrap();
701 
702         assert_eq!(required_adler, actual_adler);
703 
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();
707 
708         let decompress_result = decoder.decompress(
709             &encoded[total_in as usize..],
710             &mut decoded[total_out as usize..],
711             FlushDecompress::Finish,
712         );
713         assert!(decompress_result.is_ok());
714 
715         assert_eq!(&decoded[..decoder.total_out() as usize], string);
716     }
717 
718     #[cfg(feature = "any_zlib")]
719     #[test]
set_dictionary_raw()720     fn set_dictionary_raw() {
721         let string = "hello, hello!".as_bytes();
722         let dictionary = "hello".as_bytes();
723 
724         let mut encoded = Vec::with_capacity(1024);
725 
726         let mut encoder = Compress::new(Compression::default(), false);
727 
728         encoder.set_dictionary(&dictionary).unwrap();
729 
730         encoder
731             .compress_vec(string, &mut encoded, FlushCompress::Finish)
732             .unwrap();
733 
734         assert_eq!(encoder.total_in(), string.len() as u64);
735         assert_eq!(encoder.total_out(), encoded.len() as u64);
736 
737         let mut decoder = Decompress::new(false);
738 
739         decoder.set_dictionary(&dictionary).unwrap();
740 
741         let mut decoded = [0; 1024];
742         let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish);
743 
744         assert!(decompress_result.is_ok());
745 
746         assert_eq!(&decoded[..decoder.total_out() as usize], string);
747     }
748 
749     #[cfg(feature = "any_zlib")]
750     #[test]
test_gzip_flate()751     fn test_gzip_flate() {
752         let string = "hello, hello!".as_bytes();
753 
754         let mut encoded = Vec::with_capacity(1024);
755 
756         let mut encoder = Compress::new_gzip(Compression::default(), 9);
757 
758         encoder
759             .compress_vec(string, &mut encoded, FlushCompress::Finish)
760             .unwrap();
761 
762         assert_eq!(encoder.total_in(), string.len() as u64);
763         assert_eq!(encoder.total_out(), encoded.len() as u64);
764 
765         let mut decoder = Decompress::new_gzip(9);
766 
767         let mut decoded = [0; 1024];
768         decoder
769             .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
770             .unwrap();
771 
772         assert_eq!(&decoded[..decoder.total_out() as usize], string);
773     }
774 
775     #[cfg(feature = "any_zlib")]
776     #[test]
test_error_message()777     fn test_error_message() {
778         let mut decoder = Decompress::new(false);
779         let mut decoded = [0; 128];
780         let garbage = b"xbvxzi";
781 
782         let err = decoder
783             .decompress(&*garbage, &mut decoded, FlushDecompress::Finish)
784             .unwrap_err();
785 
786         assert_eq!(err.message(), Some("invalid stored block lengths"));
787     }
788 }
789