Coverage Report

Created: 2025-06-02 07:01

/rust/registry/src/index.crates.io-6f17d22bba15001f/flate2-1.0.30/src/mem.rs
Line
Count
Source (jump to first uncovered line)
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.
128
0
    pub fn needs_dictionary(&self) -> Option<u32> {
129
0
        match self.0 {
130
0
            DecompressErrorInner::NeedsDictionary(adler) => Some(adler),
131
0
            _ => None,
132
        }
133
0
    }
134
}
135
136
#[inline]
137
0
pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> {
138
0
    Err(DecompressError(DecompressErrorInner::General { msg }))
139
0
}
140
141
#[inline]
142
0
pub(crate) fn decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError> {
143
0
    Err(DecompressError(DecompressErrorInner::NeedsDictionary(
144
0
        adler,
145
0
    )))
146
0
}
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]
156
0
pub(crate) fn compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError> {
157
0
    Err(CompressError { msg })
158
0
}
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.
195
0
    pub fn new(level: Compression, zlib_header: bool) -> Compress {
196
0
        Compress {
197
0
            inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
198
0
        }
199
0
    }
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")]
214
    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")]
241
    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.
253
0
    pub fn total_in(&self) -> u64 {
254
0
        self.inner.total_in()
255
0
    }
256
257
    /// Returns the total number of output bytes which have been produced by
258
    /// this compression object.
259
0
    pub fn total_out(&self) -> u64 {
260
0
        self.inner.total_out()
261
0
    }
262
263
    /// Specifies the compression dictionary to use.
264
    ///
265
    /// Returns the Adler-32 checksum of the dictionary.
266
    #[cfg(feature = "any_zlib")]
267
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
268
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
269
        // since it points to a cyclic structure. No copies of `inner` can be
270
        // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
271
        let stream = self.inner.inner.stream_wrapper.inner;
272
        let rc = unsafe {
273
            (*stream).msg = std::ptr::null_mut();
274
            assert!(dictionary.len() < ffi::uInt::MAX as usize);
275
            ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
276
        };
277
278
        match rc {
279
            ffi::MZ_STREAM_ERROR => compress_failed(self.inner.inner.msg()),
280
            ffi::MZ_OK => Ok(unsafe { (*stream).adler } as u32),
281
            c => panic!("unknown return code: {}", c),
282
        }
283
    }
284
285
    /// Quickly resets this compressor without having to reallocate anything.
286
    ///
287
    /// This is equivalent to dropping this object and then creating a new one.
288
0
    pub fn reset(&mut self) {
289
0
        self.inner.reset();
290
0
    }
291
292
    /// Dynamically updates the compression level.
293
    ///
294
    /// This can be used to switch between compression levels for different
295
    /// kinds of data, or it can be used in conjunction with a call to reset
296
    /// to reuse the compressor.
297
    ///
298
    /// This may return an error if there wasn't enough output space to complete
299
    /// the compression of the available input data before changing the
300
    /// compression level. Flushing the stream before calling this method
301
    /// ensures that the function will succeed on the first call.
302
    #[cfg(feature = "any_zlib")]
303
    pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
304
        use std::os::raw::c_int;
305
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
306
        // since it points to a cyclic structure. No copies of `inner` can be
307
        // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
308
        let stream = self.inner.inner.stream_wrapper.inner;
309
        unsafe {
310
            (*stream).msg = std::ptr::null_mut();
311
        }
312
        let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
313
314
        match rc {
315
            ffi::MZ_OK => Ok(()),
316
            ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
317
            c => panic!("unknown return code: {}", c),
318
        }
319
    }
320
321
    /// Compresses the input data into the output, consuming only as much
322
    /// input as needed and writing as much output as possible.
323
    ///
324
    /// The flush option can be any of the available `FlushCompress` parameters.
325
    ///
326
    /// To learn how much data was consumed or how much output was produced, use
327
    /// the `total_in` and `total_out` functions before/after this is called.
328
0
    pub fn compress(
329
0
        &mut self,
330
0
        input: &[u8],
331
0
        output: &mut [u8],
332
0
        flush: FlushCompress,
333
0
    ) -> Result<Status, CompressError> {
334
0
        self.inner.compress(input, output, flush)
335
0
    }
336
337
    /// Compresses the input data into the extra space of the output, consuming
338
    /// only as much input as needed and writing as much output as possible.
339
    ///
340
    /// This function has the same semantics as `compress`, except that the
341
    /// length of `vec` is managed by this function. This will not reallocate
342
    /// the vector provided or attempt to grow it, so space for the output must
343
    /// be reserved in the output vector by the caller before calling this
344
    /// function.
345
0
    pub fn compress_vec(
346
0
        &mut self,
347
0
        input: &[u8],
348
0
        output: &mut Vec<u8>,
349
0
        flush: FlushCompress,
350
0
    ) -> Result<Status, CompressError> {
351
0
        write_to_spare_capacity_of_vec(output, |out| {
352
0
            let before = self.total_out();
353
0
            let ret = self.compress(input, out, flush);
354
0
            let bytes_written = self.total_out() - before;
355
0
            (bytes_written as usize, ret)
356
0
        })
357
0
    }
358
}
359
360
impl Decompress {
361
    /// Creates a new object ready for decompressing data that it's given.
362
    ///
363
    /// The `zlib_header` argument indicates whether the input data is expected
364
    /// to have a zlib header or not.
365
173
    pub fn new(zlib_header: bool) -> Decompress {
366
173
        Decompress {
367
173
            inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
368
173
        }
369
173
    }
370
371
    /// Creates a new object ready for decompressing data that it's given.
372
    ///
373
    /// The `zlib_header` argument indicates whether the input data is expected
374
    /// to have a zlib header or not. The `window_bits` parameter indicates the
375
    /// base-2 logarithm of the sliding window size and must be between 9 and 15.
376
    ///
377
    /// # Panics
378
    ///
379
    /// If `window_bits` does not fall into the range 9 ..= 15,
380
    /// `new_with_window_bits` will panic.
381
    #[cfg(feature = "any_zlib")]
382
    pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
383
        assert!(
384
            window_bits > 8 && window_bits < 16,
385
            "window_bits must be within 9 ..= 15"
386
        );
387
        Decompress {
388
            inner: Inflate::make(zlib_header, window_bits),
389
        }
390
    }
391
392
    /// Creates a new object ready for decompressing data that it's given.
393
    ///
394
    /// The Decompress object produced by this constructor expects gzip headers
395
    /// for the compressed data.
396
    ///
397
    /// # Panics
398
    ///
399
    /// If `window_bits` does not fall into the range 9 ..= 15,
400
    /// `new_with_window_bits` will panic.
401
    #[cfg(feature = "any_zlib")]
402
    pub fn new_gzip(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(true, window_bits + 16),
409
        }
410
    }
411
412
    /// Returns the total number of input bytes which have been processed by
413
    /// this decompression object.
414
1.10M
    pub fn total_in(&self) -> u64 {
415
1.10M
        self.inner.total_in()
416
1.10M
    }
417
418
    /// Returns the total number of output bytes which have been produced by
419
    /// this decompression object.
420
1.10M
    pub fn total_out(&self) -> u64 {
421
1.10M
        self.inner.total_out()
422
1.10M
    }
423
424
    /// Decompresses the input data into the output, consuming only as much
425
    /// input as needed and writing as much output as possible.
426
    ///
427
    /// The flush option can be any of the available `FlushDecompress` parameters.
428
    ///
429
    /// If the first call passes `FlushDecompress::Finish` it is assumed that
430
    /// the input and output buffers are both sized large enough to decompress
431
    /// the entire stream in a single call.
432
    ///
433
    /// A flush value of `FlushDecompress::Finish` indicates that there are no
434
    /// more source bytes available beside what's already in the input buffer,
435
    /// and the output buffer is large enough to hold the rest of the
436
    /// decompressed data.
437
    ///
438
    /// To learn how much data was consumed or how much output was produced, use
439
    /// the `total_in` and `total_out` functions before/after this is called.
440
    ///
441
    /// # Errors
442
    ///
443
    /// If the input data to this instance of `Decompress` is not a valid
444
    /// zlib/deflate stream then this function may return an instance of
445
    /// `DecompressError` to indicate that the stream of input bytes is corrupted.
446
554k
    pub fn decompress(
447
554k
        &mut self,
448
554k
        input: &[u8],
449
554k
        output: &mut [u8],
450
554k
        flush: FlushDecompress,
451
554k
    ) -> Result<Status, DecompressError> {
452
554k
        self.inner.decompress(input, output, flush)
453
554k
    }
454
455
    /// Decompresses the input data into the extra space in the output vector
456
    /// specified by `output`.
457
    ///
458
    /// This function has the same semantics as `decompress`, except that the
459
    /// length of `vec` is managed by this function. This will not reallocate
460
    /// the vector provided or attempt to grow it, so space for the output must
461
    /// be reserved in the output vector by the caller before calling this
462
    /// function.
463
    ///
464
    /// # Errors
465
    ///
466
    /// If the input data to this instance of `Decompress` is not a valid
467
    /// zlib/deflate stream then this function may return an instance of
468
    /// `DecompressError` to indicate that the stream of input bytes is corrupted.
469
0
    pub fn decompress_vec(
470
0
        &mut self,
471
0
        input: &[u8],
472
0
        output: &mut Vec<u8>,
473
0
        flush: FlushDecompress,
474
0
    ) -> Result<Status, DecompressError> {
475
0
        write_to_spare_capacity_of_vec(output, |out| {
476
0
            let before = self.total_out();
477
0
            let ret = self.decompress(input, out, flush);
478
0
            let bytes_written = self.total_out() - before;
479
0
            (bytes_written as usize, ret)
480
0
        })
481
0
    }
482
483
    /// Specifies the decompression dictionary to use.
484
    #[cfg(feature = "any_zlib")]
485
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
486
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
487
        // since it points to a cyclic structure. No copies of `inner` can be
488
        // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
489
        let stream = self.inner.inner.stream_wrapper.inner;
490
        let rc = unsafe {
491
            (*stream).msg = std::ptr::null_mut();
492
            assert!(dictionary.len() < ffi::uInt::MAX as usize);
493
            ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
494
        };
495
496
        match rc {
497
            ffi::MZ_STREAM_ERROR => decompress_failed(self.inner.inner.msg()),
498
            ffi::MZ_DATA_ERROR => decompress_need_dict(unsafe { (*stream).adler } as u32),
499
            ffi::MZ_OK => Ok(unsafe { (*stream).adler } as u32),
500
            c => panic!("unknown return code: {}", c),
501
        }
502
    }
503
504
    /// Performs the equivalent of replacing this decompression state with a
505
    /// freshly allocated copy.
506
    ///
507
    /// This function may not allocate memory, though, and attempts to reuse any
508
    /// previously existing resources.
509
    ///
510
    /// The argument provided here indicates whether the reset state will
511
    /// attempt to decode a zlib header first or not.
512
0
    pub fn reset(&mut self, zlib_header: bool) {
513
0
        self.inner.reset(zlib_header);
514
0
    }
515
}
516
517
impl Error for DecompressError {}
518
519
impl DecompressError {
520
    /// Retrieve the implementation's message about why the operation failed, if one exists.
521
0
    pub fn message(&self) -> Option<&str> {
522
0
        match &self.0 {
523
0
            DecompressErrorInner::General { msg } => msg.get(),
524
0
            _ => None,
525
        }
526
0
    }
527
}
528
529
impl From<DecompressError> for io::Error {
530
0
    fn from(data: DecompressError) -> io::Error {
531
0
        io::Error::new(io::ErrorKind::Other, data)
532
0
    }
533
}
534
535
impl fmt::Display for DecompressError {
536
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537
0
        let msg = match &self.0 {
538
0
            DecompressErrorInner::General { msg } => msg.get(),
539
0
            DecompressErrorInner::NeedsDictionary { .. } => Some("requires a dictionary"),
540
        };
541
0
        match msg {
542
0
            Some(msg) => write!(f, "deflate decompression error: {}", msg),
543
0
            None => write!(f, "deflate decompression error"),
544
        }
545
0
    }
546
}
547
548
impl Error for CompressError {}
549
550
impl CompressError {
551
    /// Retrieve the implementation's message about why the operation failed, if one exists.
552
0
    pub fn message(&self) -> Option<&str> {
553
0
        self.msg.get()
554
0
    }
555
}
556
557
impl From<CompressError> for io::Error {
558
0
    fn from(data: CompressError) -> io::Error {
559
0
        io::Error::new(io::ErrorKind::Other, data)
560
0
    }
561
}
562
563
impl fmt::Display for CompressError {
564
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565
0
        match self.msg.get() {
566
0
            Some(msg) => write!(f, "deflate compression error: {}", msg),
567
0
            None => write!(f, "deflate compression error"),
568
        }
569
0
    }
570
}
571
572
/// Allows `writer` to write data into the spare capacity of the `output` vector.
573
/// This will not reallocate the vector provided or attempt to grow it, so space
574
/// for the `output` must be reserved by the caller before calling this
575
/// function.
576
///
577
/// `writer` needs to return the number of bytes written (and can also return
578
/// another arbitrary return value).
579
0
fn write_to_spare_capacity_of_vec<T>(
580
0
    output: &mut Vec<u8>,
581
0
    writer: impl FnOnce(&mut [u8]) -> (usize, T),
582
0
) -> T {
583
0
    let cap = output.capacity();
584
0
    let len = output.len();
585
0
586
0
    output.resize(output.capacity(), 0);
587
0
    let (bytes_written, ret) = writer(&mut output[len..]);
588
0
589
0
    let new_len = core::cmp::min(len + bytes_written, cap); // Sanitizes `bytes_written`.
590
0
    output.resize(new_len, 0 /* unused */);
591
0
592
0
    ret
593
0
}
Unexecuted instantiation: flate2::mem::write_to_spare_capacity_of_vec::<core::result::Result<flate2::mem::Status, flate2::mem::CompressError>, <flate2::mem::Compress>::compress_vec::{closure#0}>
Unexecuted instantiation: flate2::mem::write_to_spare_capacity_of_vec::<core::result::Result<flate2::mem::Status, flate2::mem::DecompressError>, <flate2::mem::Decompress>::decompress_vec::{closure#0}>
594
595
#[cfg(test)]
596
mod tests {
597
    use std::io::Write;
598
599
    use crate::write;
600
    use crate::{Compression, Decompress, FlushDecompress};
601
602
    #[cfg(feature = "any_zlib")]
603
    use crate::{Compress, FlushCompress};
604
605
    #[test]
606
    fn issue51() {
607
        let data = vec![
608
            0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9,
609
            0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c,
610
            0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f,
611
            0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5,
612
            0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67,
613
            0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
614
            0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54,
615
            0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21,
616
            0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb,
617
            0xe4, 0xa8, 0x00, 0x00, 0x00,
618
        ];
619
620
        let mut decoded = Vec::with_capacity(data.len() * 2);
621
622
        let mut d = Decompress::new(false);
623
        // decompressed whole deflate stream
624
        assert!(d
625
            .decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish)
626
            .is_ok());
627
628
        // decompress data that has nothing to do with the deflate stream (this
629
        // used to panic)
630
        drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
631
    }
632
633
    #[test]
634
    fn reset() {
635
        let string = "hello world".as_bytes();
636
        let mut zlib = Vec::new();
637
        let mut deflate = Vec::new();
638
639
        let comp = Compression::default();
640
        write::ZlibEncoder::new(&mut zlib, comp)
641
            .write_all(string)
642
            .unwrap();
643
        write::DeflateEncoder::new(&mut deflate, comp)
644
            .write_all(string)
645
            .unwrap();
646
647
        let mut dst = [0; 1024];
648
        let mut decoder = Decompress::new(true);
649
        decoder
650
            .decompress(&zlib, &mut dst, FlushDecompress::Finish)
651
            .unwrap();
652
        assert_eq!(decoder.total_out(), string.len() as u64);
653
        assert!(dst.starts_with(string));
654
655
        decoder.reset(false);
656
        decoder
657
            .decompress(&deflate, &mut dst, FlushDecompress::Finish)
658
            .unwrap();
659
        assert_eq!(decoder.total_out(), string.len() as u64);
660
        assert!(dst.starts_with(string));
661
    }
662
663
    #[cfg(feature = "any_zlib")]
664
    #[test]
665
    fn set_dictionary_with_zlib_header() {
666
        let string = "hello, hello!".as_bytes();
667
        let dictionary = "hello".as_bytes();
668
669
        let mut encoded = Vec::with_capacity(1024);
670
671
        let mut encoder = Compress::new(Compression::default(), true);
672
673
        let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap();
674
675
        encoder
676
            .compress_vec(string, &mut encoded, FlushCompress::Finish)
677
            .unwrap();
678
679
        assert_eq!(encoder.total_in(), string.len() as u64);
680
        assert_eq!(encoder.total_out(), encoded.len() as u64);
681
682
        let mut decoder = Decompress::new(true);
683
        let mut decoded = [0; 1024];
684
        let decompress_error = decoder
685
            .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
686
            .expect_err("decompression should fail due to requiring a dictionary");
687
688
        let required_adler = decompress_error.needs_dictionary()
689
            .expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum");
690
691
        assert_eq!(required_adler, dictionary_adler,
692
            "the Adler-32 checksum should match the value when the dictionary was set on the compressor");
693
694
        let actual_adler = decoder.set_dictionary(&dictionary).unwrap();
695
696
        assert_eq!(required_adler, actual_adler);
697
698
        // Decompress the rest of the input to the remainder of the output buffer
699
        let total_in = decoder.total_in();
700
        let total_out = decoder.total_out();
701
702
        let decompress_result = decoder.decompress(
703
            &encoded[total_in as usize..],
704
            &mut decoded[total_out as usize..],
705
            FlushDecompress::Finish,
706
        );
707
        assert!(decompress_result.is_ok());
708
709
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
710
    }
711
712
    #[cfg(feature = "any_zlib")]
713
    #[test]
714
    fn set_dictionary_raw() {
715
        let string = "hello, hello!".as_bytes();
716
        let dictionary = "hello".as_bytes();
717
718
        let mut encoded = Vec::with_capacity(1024);
719
720
        let mut encoder = Compress::new(Compression::default(), false);
721
722
        encoder.set_dictionary(&dictionary).unwrap();
723
724
        encoder
725
            .compress_vec(string, &mut encoded, FlushCompress::Finish)
726
            .unwrap();
727
728
        assert_eq!(encoder.total_in(), string.len() as u64);
729
        assert_eq!(encoder.total_out(), encoded.len() as u64);
730
731
        let mut decoder = Decompress::new(false);
732
733
        decoder.set_dictionary(&dictionary).unwrap();
734
735
        let mut decoded = [0; 1024];
736
        let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish);
737
738
        assert!(decompress_result.is_ok());
739
740
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
741
    }
742
743
    #[cfg(feature = "any_zlib")]
744
    #[test]
745
    fn test_gzip_flate() {
746
        let string = "hello, hello!".as_bytes();
747
748
        let mut encoded = Vec::with_capacity(1024);
749
750
        let mut encoder = Compress::new_gzip(Compression::default(), 9);
751
752
        encoder
753
            .compress_vec(string, &mut encoded, FlushCompress::Finish)
754
            .unwrap();
755
756
        assert_eq!(encoder.total_in(), string.len() as u64);
757
        assert_eq!(encoder.total_out(), encoded.len() as u64);
758
759
        let mut decoder = Decompress::new_gzip(9);
760
761
        let mut decoded = [0; 1024];
762
        decoder
763
            .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
764
            .unwrap();
765
766
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
767
    }
768
769
    #[cfg(feature = "any_zlib")]
770
    #[test]
771
    fn test_error_message() {
772
        let mut decoder = Decompress::new(false);
773
        let mut decoded = [0; 128];
774
        let garbage = b"xbvxzi";
775
776
        let err = decoder
777
            .decompress(&*garbage, &mut decoded, FlushDecompress::Finish)
778
            .unwrap_err();
779
780
        assert_eq!(err.message(), Some("invalid stored block lengths"));
781
    }
782
}