]> git.proxmox.com Git - rustc.git/blob - vendor/flate2/src/mem.rs
New upstream version 1.62.1+dfsg1
[rustc.git] / vendor / flate2 / src / mem.rs
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 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 #[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.
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]
142 pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> {
143 Err(DecompressError(DecompressErrorInner::General { msg }))
144 }
145
146 #[inline]
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]
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.
200 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")]
224 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")]
256 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.
268 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.
274 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")]
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 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.
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")]
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.
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.
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 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.
380 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")]
402 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 Decompress 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")]
427 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.
439 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.
445 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.
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.
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 ret
512 }
513 }
514
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();
520 let rc = unsafe {
521 assert!(dictionary.len() < ffi::uInt::MAX 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.
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.
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 {
559 fn from(data: DecompressError) -> io::Error {
560 io::Error::new(io::ErrorKind::Other, data)
561 }
562 }
563
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"),
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.
581 pub fn message(&self) -> Option<&str> {
582 self.msg.get()
583 }
584 }
585
586 impl From<CompressError> for io::Error {
587 fn from(data: CompressError) -> io::Error {
588 io::Error::new(io::ErrorKind::Other, data)
589 }
590 }
591
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"),
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]
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]
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]
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]
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]
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]
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 }