Coverage Report

Created: 2026-03-07 06:15

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