Coverage Report

Created: 2026-11-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/flate2-1.1.11/src/mem.rs
Line
Count
Source
1
use crate::error::Error;
2
use crate::io;
3
use alloc::vec::Vec;
4
use core::fmt;
5
use core::mem::MaybeUninit;
6
7
use crate::ffi::{self, Backend, Deflate, DeflateBackend, ErrorMessage, Inflate, InflateBackend};
8
use crate::Compression;
9
10
/// Raw in-memory compression stream for blocks of data.
11
///
12
/// This type is the building block for the I/O streams in the rest of this
13
/// crate. It requires more management than the [`Read`]/[`Write`] API but is
14
/// maximally flexible in terms of accepting input from any source and being
15
/// able to produce output to any memory location.
16
///
17
/// It is recommended to use the I/O stream adaptors over this type as they're
18
/// easier to use.
19
///
20
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
21
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
22
#[derive(Debug)]
23
pub struct Compress {
24
    inner: Deflate,
25
}
26
27
/// Raw in-memory decompression stream for blocks of data.
28
///
29
/// This type is the building block for the I/O streams in the rest of this
30
/// crate. It requires more management than the [`Read`]/[`Write`] API but is
31
/// maximally flexible in terms of accepting input from any source and being
32
/// able to produce output to any memory location.
33
///
34
/// It is recommended to use the I/O stream adaptors over this type as they're
35
/// easier to use.
36
///
37
/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
38
/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
39
#[derive(Debug)]
40
pub struct Decompress {
41
    inner: Inflate,
42
}
43
44
/// Values which indicate the form of flushing to be used when compressing
45
/// in-memory data.
46
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
47
#[non_exhaustive]
48
#[allow(clippy::unnecessary_cast)]
49
pub enum FlushCompress {
50
    /// A typical parameter for passing to compression/decompression functions,
51
    /// this indicates that the underlying stream to decide how much data to
52
    /// accumulate before producing output in order to maximize compression.
53
    None = ffi::MZ_NO_FLUSH as isize,
54
55
    /// All pending output is flushed to the output buffer, but the output is
56
    /// not aligned to a byte boundary.
57
    ///
58
    /// All input data so far will be available to the decompressor (as with
59
    /// `Flush::Sync`). This completes the current deflate block and follows it
60
    /// with an empty fixed codes block that is 10 bits long, and it assures
61
    /// that enough bytes are output in order for the decompressor to finish the
62
    /// block before the empty fixed code block.
63
    Partial = ffi::MZ_PARTIAL_FLUSH as isize,
64
65
    /// All pending output is flushed to the output buffer and the output is
66
    /// aligned on a byte boundary so that the decompressor can get all input
67
    /// data available so far.
68
    ///
69
    /// Flushing may degrade compression for some compression algorithms and so
70
    /// it should only be used when necessary. This will complete the current
71
    /// deflate block and follow it with an empty stored block.
72
    Sync = ffi::MZ_SYNC_FLUSH as isize,
73
74
    /// All output is flushed as with `Flush::Sync` and the compression state is
75
    /// reset so decompression can restart from this point if previous
76
    /// compressed data has been damaged or if random access is desired.
77
    ///
78
    /// Using this option too often can seriously degrade compression.
79
    Full = ffi::MZ_FULL_FLUSH as isize,
80
81
    /// Pending input is processed and pending output is flushed.
82
    ///
83
    /// The return value may indicate that the stream is not yet done and more
84
    /// data has yet to be processed.
85
    Finish = ffi::MZ_FINISH as isize,
86
}
87
88
/// Values which indicate the form of flushing to be used when
89
/// decompressing in-memory data.
90
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
91
#[non_exhaustive]
92
#[allow(clippy::unnecessary_cast)]
93
pub enum FlushDecompress {
94
    /// A typical parameter for passing to compression/decompression functions,
95
    /// this indicates that the underlying stream to decide how much data to
96
    /// accumulate before producing output in order to maximize compression.
97
    None = ffi::MZ_NO_FLUSH as isize,
98
99
    /// All pending output is flushed to the output buffer and the output is
100
    /// aligned on a byte boundary so that the decompressor can get all input
101
    /// data available so far.
102
    ///
103
    /// Flushing may degrade compression for some compression algorithms and so
104
    /// it should only be used when necessary. This will complete the current
105
    /// deflate block and follow it with an empty stored block.
106
    Sync = ffi::MZ_SYNC_FLUSH as isize,
107
108
    /// Pending input is processed and pending output is flushed.
109
    ///
110
    /// The return value may indicate that the stream is not yet done and more
111
    /// data has yet to be processed.
112
    Finish = ffi::MZ_FINISH as isize,
113
}
114
115
/// The inner state for an error when decompressing
116
#[derive(Clone, Debug)]
117
pub(crate) enum DecompressErrorInner {
118
    General { msg: ErrorMessage },
119
    NeedsDictionary(u32),
120
}
121
122
/// Error returned when a decompression object finds that the input stream of
123
/// bytes was not a valid input stream of bytes.
124
#[derive(Clone, Debug)]
125
pub struct DecompressError(pub(crate) DecompressErrorInner);
126
127
impl DecompressError {
128
    /// Indicates whether decompression failed due to requiring a dictionary.
129
    ///
130
    /// The resulting integer is the Adler-32 checksum of the dictionary
131
    /// required.
132
0
    pub fn needs_dictionary(&self) -> Option<u32> {
133
0
        match self.0 {
134
0
            DecompressErrorInner::NeedsDictionary(adler) => Some(adler),
135
0
            _ => None,
136
        }
137
0
    }
138
}
139
140
#[inline]
141
3.82k
pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> {
142
3.82k
    Err(DecompressError(DecompressErrorInner::General { msg }))
143
3.82k
}
144
145
#[inline]
146
0
pub(crate) fn decompress_need_dict<T>(adler: u32) -> Result<T, DecompressError> {
147
0
    Err(DecompressError(DecompressErrorInner::NeedsDictionary(
148
0
        adler,
149
0
    )))
150
0
}
151
152
/// Error returned when a compression object is used incorrectly or otherwise
153
/// generates an error.
154
#[derive(Clone, Debug)]
155
pub struct CompressError {
156
    pub(crate) msg: ErrorMessage,
157
}
158
159
#[inline]
160
0
pub(crate) fn compress_failed<T>(msg: ErrorMessage) -> Result<T, CompressError> {
161
0
    Err(CompressError { msg })
162
0
}
163
164
/// Possible status results of compressing some data or successfully
165
/// decompressing a block of data.
166
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
167
pub enum Status {
168
    /// Indicates success.
169
    ///
170
    /// Means that more input may be needed but isn't available
171
    /// and/or there's more output to be written but the output buffer is full.
172
    Ok,
173
174
    /// Indicates that forward progress is not possible due to input or output
175
    /// buffers being empty.
176
    ///
177
    /// For compression it means the input buffer needs some more data or the
178
    /// output buffer needs to be freed up before trying again.
179
    ///
180
    /// For decompression this means that more input is needed to continue or
181
    /// the output buffer isn't large enough to contain the result. The function
182
    /// can be called again after fixing both.
183
    BufError,
184
185
    /// Indicates that all input has been consumed and all output bytes have
186
    /// been written. Decompression/compression should not be called again.
187
    ///
188
    /// For decompression with zlib streams the adler-32 of the decompressed
189
    /// data has also been verified.
190
    StreamEnd,
191
}
192
193
impl Compress {
194
    /// Creates a new object ready for compressing data that it's given.
195
    ///
196
    /// The `level` argument here indicates what level of compression is going
197
    /// to be performed, and the `zlib_header` argument indicates whether the
198
    /// output data should have a zlib header or not.
199
21.2k
    pub fn new(level: Compression, zlib_header: bool) -> Compress {
200
21.2k
        Compress {
201
21.2k
            inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
202
21.2k
        }
203
21.2k
    }
204
205
    /// Creates a new object ready for compressing data that it's given.
206
    ///
207
    /// The `level` argument here indicates what level of compression is going
208
    /// to be performed, and the `zlib_header` argument indicates whether the
209
    /// output data should have a zlib header or not. The `window_bits` parameter
210
    /// indicates the base-2 logarithm of the sliding window size and must be
211
    /// between 9 and 15.
212
    ///
213
    /// # Panics
214
    ///
215
    /// If `window_bits` does not fall into the range 9 ..= 15,
216
    /// this function will panic.
217
    #[cfg(feature = "any_zlib")]
218
    pub fn new_with_window_bits(
219
        level: Compression,
220
        zlib_header: bool,
221
        window_bits: u8,
222
    ) -> Compress {
223
        assert!(
224
            window_bits > 8 && window_bits < 16,
225
            "window_bits must be within 9 ..= 15"
226
        );
227
        Compress {
228
            inner: Deflate::make(level, zlib_header, window_bits),
229
        }
230
    }
231
232
    /// Creates a new object ready for compressing data that it's given.
233
    ///
234
    /// The `level` argument here indicates what level of compression is going
235
    /// to be performed.
236
    ///
237
    /// The Compress object produced by this constructor outputs gzip headers
238
    /// for the compressed data.
239
    ///
240
    /// # Panics
241
    ///
242
    /// If `window_bits` does not fall into the range 9 ..= 15,
243
    /// this function will panic.
244
    #[cfg(feature = "any_zlib")]
245
    pub fn new_gzip(level: Compression, window_bits: u8) -> Compress {
246
        assert!(
247
            window_bits > 8 && window_bits < 16,
248
            "window_bits must be within 9 ..= 15"
249
        );
250
        Compress {
251
            inner: Deflate::make(level, true, window_bits + 16),
252
        }
253
    }
254
255
    /// Returns the total number of input bytes which have been processed by
256
    /// this compression object.
257
42.4k
    pub fn total_in(&self) -> u64 {
258
42.4k
        self.inner.total_in()
259
42.4k
    }
260
261
    /// Returns the total number of output bytes which have been produced by
262
    /// this compression object.
263
106k
    pub fn total_out(&self) -> u64 {
264
106k
        self.inner.total_out()
265
106k
    }
266
267
    /// Specifies the compression dictionary to use.
268
    ///
269
    /// Returns the Adler-32 checksum of the dictionary.
270
    #[cfg(feature = "any_c_zlib")]
271
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
272
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
273
        // since it points to a cyclic structure. No copies of `inner` can be
274
        // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
275
        let stream = self.inner.inner.stream_wrapper.inner;
276
        let rc = unsafe {
277
            (*stream).msg = core::ptr::null_mut();
278
            assert!(dictionary.len() < ffi::uInt::MAX as usize);
279
            ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
280
        };
281
282
        match rc {
283
            ffi::MZ_STREAM_ERROR => compress_failed(self.inner.inner.msg()),
284
            #[allow(clippy::unnecessary_cast)]
285
            ffi::MZ_OK => Ok(unsafe { (*stream).adler } as u32),
286
            c => panic!("unknown return code: {}", c),
287
        }
288
    }
289
290
    /// Specifies the compression dictionary to use.
291
    ///
292
    /// Returns the Adler-32 checksum of the dictionary.
293
    #[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
294
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
295
        self.inner.set_dictionary(dictionary)
296
    }
297
298
    /// Quickly resets this compressor without having to reallocate anything.
299
    ///
300
    /// This is equivalent to dropping this object and then creating a new one.
301
0
    pub fn reset(&mut self) {
302
0
        self.inner.reset();
303
0
    }
304
305
    /// Dynamically updates the compression level.
306
    ///
307
    /// This can be used to switch between compression levels for different
308
    /// kinds of data, or it can be used in conjunction with a call to reset
309
    /// to reuse the compressor.
310
    ///
311
    /// This may return an error if there wasn't enough output space to complete
312
    /// the compression of the available input data before changing the
313
    /// compression level. Flushing the stream before calling this method
314
    /// ensures that the function will succeed on the first call.
315
    #[cfg(feature = "any_zlib")]
316
    pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
317
        #[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
318
        {
319
            self.inner.set_level(level)
320
        }
321
322
        #[cfg(feature = "any_c_zlib")]
323
        {
324
            use core::ffi::c_int;
325
            // SAFETY: The field `inner` must always be accessed as a raw pointer,
326
            // since it points to a cyclic structure. No copies of `inner` can be
327
            // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
328
            let stream = self.inner.inner.stream_wrapper.inner;
329
            unsafe {
330
                (*stream).msg = core::ptr::null_mut();
331
            }
332
            let rc =
333
                unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
334
335
            match rc {
336
                ffi::MZ_OK => Ok(()),
337
                ffi::MZ_BUF_ERROR => compress_failed(self.inner.inner.msg()),
338
                c => panic!("unknown return code: {}", c),
339
            }
340
        }
341
    }
342
343
    /// Compresses the input data into the output, consuming only as much
344
    /// input as needed and writing as much output as possible.
345
    ///
346
    /// The flush option can be any of the available `FlushCompress` parameters.
347
    ///
348
    /// To learn how much data was consumed or how much output was produced, use
349
    /// the `total_in` and `total_out` functions before/after this is called.
350
0
    pub fn compress(
351
0
        &mut self,
352
0
        input: &[u8],
353
0
        output: &mut [u8],
354
0
        flush: FlushCompress,
355
0
    ) -> Result<Status, CompressError> {
356
0
        self.inner.compress(input, output, flush)
357
0
    }
358
359
    /// Similar to [`Self::compress`] but accepts uninitialized buffer.
360
    ///
361
    /// If you want to avoid the overhead of zero initializing the
362
    /// buffer and you don't want to use a [`Vec`], then please use
363
    /// this API.
364
42.4k
    pub fn compress_uninit(
365
42.4k
        &mut self,
366
42.4k
        input: &[u8],
367
42.4k
        output: &mut [MaybeUninit<u8>],
368
42.4k
        flush: FlushCompress,
369
42.4k
    ) -> Result<Status, CompressError> {
370
42.4k
        self.inner.compress_uninit(input, output, flush)
371
42.4k
    }
372
373
    /// Compresses the input data into the extra space of the output, consuming
374
    /// only as much input as needed and writing as much output as possible.
375
    ///
376
    /// This function has the same semantics as `compress`, except that the
377
    /// length of `vec` is managed by this function. This will not reallocate
378
    /// the vector provided or attempt to grow it, so space for the output must
379
    /// be reserved in the output vector by the caller before calling this
380
    /// function.
381
42.4k
    pub fn compress_vec(
382
42.4k
        &mut self,
383
42.4k
        input: &[u8],
384
42.4k
        output: &mut Vec<u8>,
385
42.4k
        flush: FlushCompress,
386
42.4k
    ) -> Result<Status, CompressError> {
387
        // SAFETY: bytes_written is the number of bytes written into `out`
388
        unsafe {
389
42.4k
            write_to_spare_capacity_of_vec(output, |out| {
390
42.4k
                let before = self.total_out();
391
42.4k
                let ret = self.compress_uninit(input, out, flush);
392
42.4k
                let bytes_written = self.total_out() - before;
393
42.4k
                (bytes_written as usize, ret)
394
42.4k
            })
395
        }
396
42.4k
    }
397
}
398
399
impl Decompress {
400
    /// Creates a new object ready for decompressing data that it's given.
401
    ///
402
    /// The `zlib_header` argument indicates whether the input data is expected
403
    /// to have a zlib header or not.
404
21.1k
    pub fn new(zlib_header: bool) -> Decompress {
405
21.1k
        Decompress {
406
21.1k
            inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
407
21.1k
        }
408
21.1k
    }
409
410
    /// Creates a new object ready for decompressing data that it's given.
411
    ///
412
    /// The `zlib_header` argument indicates whether the input data is expected
413
    /// to have a zlib header or not. The `window_bits` parameter indicates the
414
    /// base-2 logarithm of the sliding window size and must be between 9 and 15.
415
    ///
416
    /// # Panics
417
    ///
418
    /// If `window_bits` does not fall into the range 9 ..= 15,
419
    /// this function will panic.
420
    #[cfg(feature = "any_zlib")]
421
    pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
422
        assert!(
423
            window_bits > 8 && window_bits < 16,
424
            "window_bits must be within 9 ..= 15"
425
        );
426
        Decompress {
427
            inner: Inflate::make(zlib_header, window_bits),
428
        }
429
    }
430
431
    /// Creates a new object ready for decompressing data that it's given.
432
    ///
433
    /// The Decompress object produced by this constructor expects gzip headers
434
    /// for the compressed data.
435
    ///
436
    /// # Panics
437
    ///
438
    /// If `window_bits` does not fall into the range 9 ..= 15,
439
    /// this function will panic.
440
    #[cfg(feature = "any_zlib")]
441
    pub fn new_gzip(window_bits: u8) -> Decompress {
442
        assert!(
443
            window_bits > 8 && window_bits < 16,
444
            "window_bits must be within 9 ..= 15"
445
        );
446
        Decompress {
447
            inner: Inflate::make(true, window_bits + 16),
448
        }
449
    }
450
451
    /// Returns the total number of input bytes which have been processed by
452
    /// this decompression object.
453
127k
    pub fn total_in(&self) -> u64 {
454
127k
        self.inner.total_in()
455
127k
    }
456
457
    /// Returns the total number of output bytes which have been produced by
458
    /// this decompression object.
459
127k
    pub fn total_out(&self) -> u64 {
460
127k
        self.inner.total_out()
461
127k
    }
462
463
    /// Decompresses the input data into the output, consuming only as much
464
    /// input as needed and writing as much output as possible.
465
    ///
466
    /// The flush option can be any of the available `FlushDecompress` parameters.
467
    ///
468
    /// If the first call passes `FlushDecompress::Finish` it is assumed that
469
    /// the input and output buffers are both sized large enough to decompress
470
    /// the entire stream in a single call.
471
    ///
472
    /// A flush value of `FlushDecompress::Finish` indicates that there are no
473
    /// more source bytes available beside what's already in the input buffer,
474
    /// and the output buffer is large enough to hold the rest of the
475
    /// decompressed data.
476
    ///
477
    /// To learn how much data was consumed or how much output was produced, use
478
    /// the `total_in` and `total_out` functions before/after this is called.
479
    ///
480
    /// # Errors
481
    ///
482
    /// If the input data to this instance of `Decompress` is not a valid
483
    /// zlib/deflate stream then this function may return an instance of
484
    /// `DecompressError` to indicate that the stream of input bytes is corrupted.
485
63.5k
    pub fn decompress(
486
63.5k
        &mut self,
487
63.5k
        input: &[u8],
488
63.5k
        output: &mut [u8],
489
63.5k
        flush: FlushDecompress,
490
63.5k
    ) -> Result<Status, DecompressError> {
491
63.5k
        self.inner.decompress(input, output, flush)
492
63.5k
    }
493
494
    /// Similar to [`Self::decompress`] but accepts uninitialized buffer
495
    ///
496
    /// If you want to avoid the overhead of zero initializing the
497
    /// buffer and you don't want to use a [`Vec`], then please use
498
    /// this API.
499
0
    pub fn decompress_uninit(
500
0
        &mut self,
501
0
        input: &[u8],
502
0
        output: &mut [MaybeUninit<u8>],
503
0
        flush: FlushDecompress,
504
0
    ) -> Result<Status, DecompressError> {
505
0
        self.inner.decompress_uninit(input, output, flush)
506
0
    }
507
508
    /// Decompresses the input data into the extra space in the output vector
509
    /// specified by `output`.
510
    ///
511
    /// This function has the same semantics as `decompress`, except that the
512
    /// length of `vec` is managed by this function. This will not reallocate
513
    /// the vector provided or attempt to grow it, so space for the output must
514
    /// be reserved in the output vector by the caller before calling this
515
    /// function.
516
    ///
517
    /// # Errors
518
    ///
519
    /// If the input data to this instance of `Decompress` is not a valid
520
    /// zlib/deflate stream then this function may return an instance of
521
    /// `DecompressError` to indicate that the stream of input bytes is corrupted.
522
0
    pub fn decompress_vec(
523
0
        &mut self,
524
0
        input: &[u8],
525
0
        output: &mut Vec<u8>,
526
0
        flush: FlushDecompress,
527
0
    ) -> Result<Status, DecompressError> {
528
        // SAFETY: bytes_written is the number of bytes written into `out`
529
        unsafe {
530
0
            write_to_spare_capacity_of_vec(output, |out| {
531
0
                let before = self.total_out();
532
0
                let ret = self.decompress_uninit(input, out, flush);
533
0
                let bytes_written = self.total_out() - before;
534
0
                (bytes_written as usize, ret)
535
0
            })
536
        }
537
0
    }
538
539
    /// Specifies the decompression dictionary to use.
540
    #[cfg(feature = "any_c_zlib")]
541
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
542
        // SAFETY: The field `inner` must always be accessed as a raw pointer,
543
        // since it points to a cyclic structure. No copies of `inner` can be
544
        // retained for longer than the lifetime of `self.inner.inner.stream_wrapper`.
545
        let stream = self.inner.inner.stream_wrapper.inner;
546
        let rc = unsafe {
547
            (*stream).msg = core::ptr::null_mut();
548
            assert!(dictionary.len() < ffi::uInt::MAX as usize);
549
            ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
550
        };
551
552
        #[allow(clippy::unnecessary_cast)]
553
        match rc {
554
            ffi::MZ_STREAM_ERROR => decompress_failed(self.inner.inner.msg()),
555
            ffi::MZ_DATA_ERROR => decompress_need_dict(unsafe { (*stream).adler } as u32),
556
            ffi::MZ_OK => Ok(unsafe { (*stream).adler } as u32),
557
            c => panic!("unknown return code: {}", c),
558
        }
559
    }
560
561
    /// Specifies the decompression dictionary to use.
562
    #[cfg(all(not(feature = "any_c_zlib"), feature = "zlib-rs"))]
563
    pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
564
        self.inner.set_dictionary(dictionary)
565
    }
566
567
    /// Performs the equivalent of replacing this decompression state with a
568
    /// freshly allocated copy.
569
    ///
570
    /// This function may not allocate memory, though, and attempts to reuse any
571
    /// previously existing resources.
572
    ///
573
    /// The argument provided here indicates whether the reset state will
574
    /// attempt to decode a zlib header first or not.
575
0
    pub fn reset(&mut self, zlib_header: bool) {
576
0
        self.inner.reset(zlib_header);
577
0
    }
578
}
579
580
impl Error for DecompressError {}
581
582
impl DecompressError {
583
    /// Retrieve the implementation's message about why the operation failed, if one exists.
584
0
    pub fn message(&self) -> Option<&str> {
585
0
        match &self.0 {
586
0
            DecompressErrorInner::General { msg } => msg.get(),
587
0
            _ => None,
588
        }
589
0
    }
590
}
591
592
impl From<DecompressError> for io::Error {
593
0
    fn from(data: DecompressError) -> io::Error {
594
0
        io::Error::new(io::ErrorKind::Other, data)
595
0
    }
596
}
597
598
impl fmt::Display for DecompressError {
599
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
600
0
        let msg = match &self.0 {
601
0
            DecompressErrorInner::General { msg } => msg.get(),
602
0
            DecompressErrorInner::NeedsDictionary { .. } => Some("requires a dictionary"),
603
        };
604
0
        match msg {
605
0
            Some(msg) => write!(f, "deflate decompression error: {msg}"),
606
0
            None => write!(f, "deflate decompression error"),
607
        }
608
0
    }
609
}
610
611
impl Error for CompressError {}
612
613
impl CompressError {
614
    /// Retrieve the implementation's message about why the operation failed, if one exists.
615
0
    pub fn message(&self) -> Option<&str> {
616
0
        self.msg.get()
617
0
    }
618
}
619
620
impl From<CompressError> for io::Error {
621
0
    fn from(data: CompressError) -> io::Error {
622
0
        io::Error::new(io::ErrorKind::Other, data)
623
0
    }
624
}
625
626
impl fmt::Display for CompressError {
627
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
628
0
        match self.msg.get() {
629
0
            Some(msg) => write!(f, "deflate compression error: {msg}"),
630
0
            None => write!(f, "deflate compression error"),
631
        }
632
0
    }
633
}
634
635
/// Allows `writer` to write data into the spare capacity of the `output` vector.
636
/// This will not reallocate the vector provided or attempt to grow it, so space
637
/// for the `output` must be reserved by the caller before calling this
638
/// function.
639
///
640
/// `writer` needs to return the number of bytes written (and can also return
641
/// another arbitrary return value).
642
///
643
/// # Safety:
644
///
645
/// The length returned by the `writer` must be equal to actual number of bytes written
646
/// to the uninitialized slice passed in and initialized.
647
42.4k
unsafe fn write_to_spare_capacity_of_vec<T>(
648
42.4k
    output: &mut Vec<u8>,
649
42.4k
    writer: impl FnOnce(&mut [MaybeUninit<u8>]) -> (usize, T),
650
42.4k
) -> T {
651
42.4k
    let cap = output.capacity();
652
42.4k
    let len = output.len();
653
654
42.4k
    let (bytes_written, ret) = writer(output.spare_capacity_mut());
655
42.4k
    output.set_len(cap.min(len + bytes_written)); // Sanitizes `bytes_written`.
656
657
42.4k
    ret
658
42.4k
}
flate2::mem::write_to_spare_capacity_of_vec::<core::result::Result<flate2::mem::Status, flate2::mem::CompressError>, <flate2::mem::Compress>::compress_vec::{closure#0}>
Line
Count
Source
647
42.4k
unsafe fn write_to_spare_capacity_of_vec<T>(
648
42.4k
    output: &mut Vec<u8>,
649
42.4k
    writer: impl FnOnce(&mut [MaybeUninit<u8>]) -> (usize, T),
650
42.4k
) -> T {
651
42.4k
    let cap = output.capacity();
652
42.4k
    let len = output.len();
653
654
42.4k
    let (bytes_written, ret) = writer(output.spare_capacity_mut());
655
42.4k
    output.set_len(cap.min(len + bytes_written)); // Sanitizes `bytes_written`.
656
657
42.4k
    ret
658
42.4k
}
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}>
659
660
#[cfg(test)]
661
mod tests {
662
    use crate::io::Write;
663
    use alloc::vec::Vec;
664
665
    use crate::write;
666
    use crate::{Compression, Decompress, FlushDecompress};
667
668
    use crate::{Compress, FlushCompress};
669
670
    #[test]
671
    fn issue51() {
672
        let data = [
673
            0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9,
674
            0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c,
675
            0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f,
676
            0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5,
677
            0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67,
678
            0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
679
            0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54,
680
            0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21,
681
            0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb,
682
            0xe4, 0xa8, 0x00, 0x00, 0x00,
683
        ];
684
685
        let mut decoded = Vec::with_capacity(data.len() * 2);
686
687
        let mut d = Decompress::new(false);
688
        // decompressed whole deflate stream
689
        d.decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish)
690
            .unwrap();
691
692
        // decompress data that has nothing to do with the deflate stream (this
693
        // used to panic)
694
        drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
695
    }
696
697
    #[test]
698
    fn reset() {
699
        let string = "hello world".as_bytes();
700
        let mut zlib = Vec::new();
701
        let mut deflate = Vec::new();
702
703
        let comp = Compression::default();
704
        write::ZlibEncoder::new(&mut zlib, comp)
705
            .write_all(string)
706
            .unwrap();
707
        write::DeflateEncoder::new(&mut deflate, comp)
708
            .write_all(string)
709
            .unwrap();
710
711
        let mut dst = [0; 1024];
712
        let mut decoder = Decompress::new(true);
713
        decoder
714
            .decompress(&zlib, &mut dst, FlushDecompress::Finish)
715
            .unwrap();
716
        assert_eq!(decoder.total_out(), string.len() as u64);
717
        assert!(dst.starts_with(string));
718
719
        decoder.reset(false);
720
        decoder
721
            .decompress(&deflate, &mut dst, FlushDecompress::Finish)
722
            .unwrap();
723
        assert_eq!(decoder.total_out(), string.len() as u64);
724
        assert!(dst.starts_with(string));
725
    }
726
727
    #[cfg(all(not(feature = "any_zlib"), feature = "miniz_oxide"))]
728
    #[test]
729
    fn reset_clears_miniz_oxide_dictionary() {
730
        let secret = [b'A'; 32 * 1024];
731
        // A raw DEFLATE stream containing one final, uncompressed (stored) block:
732
        // 0x01 sets BFINAL=1 and BTYPE=00, followed by padding to a byte boundary.
733
        // LEN is the payload length; NLEN is its one's complement.
734
        // The payload fills the entire 32 KiB dictionary with secret bytes.
735
        let len = secret.len() as u16;
736
        let nlen = !len;
737
        let mut victim_stream = Vec::with_capacity(secret.len() + 5);
738
        victim_stream.push(0x01);
739
        victim_stream.extend_from_slice(&len.to_le_bytes());
740
        victim_stream.extend_from_slice(&nlen.to_le_bytes());
741
        victim_stream.extend_from_slice(&secret);
742
743
        let mut decoder = Decompress::new(false);
744
        let mut victim_output = [0; 32 * 1024];
745
        decoder
746
            .decompress(&victim_stream, &mut victim_output, FlushDecompress::None)
747
            .unwrap();
748
        assert_eq!(
749
            victim_output, secret,
750
            "the first stream must fill the 32 KiB dictionary with secret bytes"
751
        );
752
753
        decoder.reset(false);
754
755
        let mut attacker_output = [0; 258];
756
        let _ = decoder.decompress(
757
            &[0x1b, 0xbd, 0xff, 0x1f, 0x00],
758
            &mut attacker_output,
759
            FlushDecompress::None,
760
        );
761
        assert!(
762
            !attacker_output.contains(&b'A'),
763
            "reset must clear the dictionary: a distance-32768 match leaked bytes \
764
             from the previous stream; both FullReset and the current upstream \
765
             reset() prevent this, but MinReset does not"
766
        );
767
    }
768
769
    #[test]
770
    fn unfinished_compressor_can_be_dropped() {
771
        let mut encoder = Compress::new(Compression::default(), false);
772
        encoder
773
            .compress(b"hello", &mut [0; 1024], FlushCompress::None)
774
            .unwrap();
775
        assert_eq!(encoder.total_in(), 5);
776
    }
777
778
    #[cfg(feature = "any_zlib")]
779
    #[test]
780
    fn reset_preserves_gzip_configuration() {
781
        let string = "hello, hello!".as_bytes();
782
783
        let mut encoded = Vec::with_capacity(1024);
784
        let mut encoder = Compress::new_gzip(Compression::default(), 9);
785
        encoder
786
            .compress_vec(string, &mut encoded, FlushCompress::Finish)
787
            .unwrap();
788
789
        let mut decoder = Decompress::new_gzip(9);
790
        let mut decoded = [0; 1024];
791
        decoder
792
            .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
793
            .unwrap();
794
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
795
796
        decoder.reset(true);
797
        let mut decoded = [0; 1024];
798
        decoder
799
            .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
800
            .expect("reset must preserve the gzip wrapper selected at construction");
801
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
802
    }
803
804
    #[cfg(feature = "any_zlib")]
805
    #[test]
806
    fn reset_preserves_window_bits() {
807
        // A valid zlib header declaring a 32 KiB (15-bit) window: CMF 0x78, FLG 0x9c.
808
        let header_15_bit_window = [0x78, 0x9c];
809
        let mut decoded = [0; 64];
810
811
        let mut decoder = Decompress::new_with_window_bits(true, 9);
812
        decoder
813
            .decompress(&header_15_bit_window, &mut decoded, FlushDecompress::None)
814
            .expect_err("a 15-bit-window stream must be rejected by a 9-bit-window decoder");
815
816
        decoder.reset(true);
817
        decoder
818
            .decompress(&header_15_bit_window, &mut decoded, FlushDecompress::None)
819
            .expect_err("reset must preserve the window size selected at construction");
820
    }
821
822
    #[cfg(feature = "any_zlib")]
823
    #[test]
824
    fn test_gzip_flate() {
825
        let string = "hello, hello!".as_bytes();
826
827
        let mut encoded = Vec::with_capacity(1024);
828
829
        let mut encoder = Compress::new_gzip(Compression::default(), 9);
830
831
        encoder
832
            .compress_vec(string, &mut encoded, FlushCompress::Finish)
833
            .unwrap();
834
835
        assert_eq!(encoder.total_in(), string.len() as u64);
836
        assert_eq!(encoder.total_out(), encoded.len() as u64);
837
838
        let mut decoder = Decompress::new_gzip(9);
839
840
        let mut decoded = [0; 1024];
841
        decoder
842
            .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
843
            .unwrap();
844
845
        assert_eq!(&decoded[..decoder.total_out() as usize], string);
846
    }
847
848
    #[cfg(feature = "any_zlib")]
849
    #[test]
850
    fn test_error_message() {
851
        let mut decoder = Decompress::new(false);
852
        let mut decoded = [0; 128];
853
        let garbage = b"xbvxzi";
854
855
        let err = decoder
856
            .decompress(garbage, &mut decoded, FlushDecompress::Finish)
857
            .unwrap_err();
858
859
        assert_eq!(err.message(), Some("invalid stored block lengths"));
860
    }
861
862
    fn compress_with_flush(flush: FlushCompress) -> Vec<u8> {
863
        let incompressible = (0..=255).collect::<Vec<u8>>();
864
        let mut output = vec![0; 1024];
865
866
        // Feed in the incompressible data followed by the indicated flush type.
867
        let mut w = Compress::new(Compression::default(), false);
868
        w.compress(&incompressible, &mut output, flush).unwrap();
869
870
        if flush != FlushCompress::None {
871
            // The first instance of incompressible input should have been written uncompressed.
872
            assert!(w.total_out() >= 261);
873
            assert_eq!(&output[0..5], &[0, 0, 1, 0xff, !1]);
874
            assert_eq!(&output[5..261], &incompressible);
875
        }
876
877
        // Feed in the same data again.
878
        let len = w.total_out() as usize;
879
        w.compress(&incompressible, &mut output[len..], FlushCompress::Finish)
880
            .unwrap();
881
882
        if flush != FlushCompress::Full {
883
            // This time, the data should have been compressed (because it is an exact duplicate of
884
            // the earlier block).
885
            assert!(w.total_out() < 300);
886
        }
887
888
        // Assert that all input has been processed.
889
        assert_eq!(w.total_in(), 256 * 2);
890
891
        output.resize(w.total_out() as usize, 0);
892
        output
893
    }
894
895
    #[test]
896
    fn test_partial_flush() {
897
        let output = compress_with_flush(FlushCompress::Partial);
898
899
        // Check for partial flush marker.
900
        assert_eq!(output[261], 0x2);
901
        assert_eq!(output[262] & 0x7, 0x4);
902
    }
903
904
    #[test]
905
    fn test_sync_flush() {
906
        let output = compress_with_flush(FlushCompress::Sync);
907
908
        // Check for sync flush marker.
909
        assert_eq!(&output[261..][..5], &[0, 0, 0, 0xff, 0xff]);
910
    }
911
912
    #[test]
913
    fn test_full_flush() {
914
        let output = compress_with_flush(FlushCompress::Full);
915
        assert_eq!(output.len(), 527);
916
917
        // Check for sync flush marker.
918
        assert_eq!(&output[261..][..5], &[0, 0, 0, 0xff, 0xff]);
919
920
        // Check that the second instance of incompressible input was also written uncompressed.
921
        assert_eq!(&output[266..][..5], &[1, 0, 1, 0xff, !1]);
922
    }
923
}