Coverage Report

Created: 2025-12-05 06:56

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