/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 | 258 | pub(crate) fn decompress_failed<T>(msg: ErrorMessage) -> Result<T, DecompressError> { |
142 | 258 | Err(DecompressError(DecompressErrorInner::General { msg })) |
143 | 258 | } |
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 | 0 | pub fn new(level: Compression, zlib_header: bool) -> Compress { |
200 | 0 | Compress { |
201 | 0 | inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8), |
202 | 0 | } |
203 | 0 | } |
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 | 0 | pub fn total_in(&self) -> u64 { |
258 | 0 | self.inner.total_in() |
259 | 0 | } |
260 | | |
261 | | /// Returns the total number of output bytes which have been produced by |
262 | | /// this compression object. |
263 | 0 | pub fn total_out(&self) -> u64 { |
264 | 0 | self.inner.total_out() |
265 | 0 | } |
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 | 0 | pub fn compress_uninit( |
365 | 0 | &mut self, |
366 | 0 | input: &[u8], |
367 | 0 | output: &mut [MaybeUninit<u8>], |
368 | 0 | flush: FlushCompress, |
369 | 0 | ) -> Result<Status, CompressError> { |
370 | 0 | self.inner.compress_uninit(input, output, flush) |
371 | 0 | } |
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 | 0 | pub fn compress_vec( |
382 | 0 | &mut self, |
383 | 0 | input: &[u8], |
384 | 0 | output: &mut Vec<u8>, |
385 | 0 | flush: FlushCompress, |
386 | 0 | ) -> Result<Status, CompressError> { |
387 | | // SAFETY: bytes_written is the number of bytes written into `out` |
388 | | unsafe { |
389 | 0 | write_to_spare_capacity_of_vec(output, |out| { |
390 | 0 | let before = self.total_out(); |
391 | 0 | let ret = self.compress_uninit(input, out, flush); |
392 | 0 | let bytes_written = self.total_out() - before; |
393 | 0 | (bytes_written as usize, ret) |
394 | 0 | }) |
395 | | } |
396 | 0 | } |
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 | 2.75k | pub fn new(zlib_header: bool) -> Decompress { |
405 | 2.75k | Decompress { |
406 | 2.75k | inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8), |
407 | 2.75k | } |
408 | 2.75k | } |
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 | 250k | pub fn total_in(&self) -> u64 { |
454 | 250k | self.inner.total_in() |
455 | 250k | } |
456 | | |
457 | | /// Returns the total number of output bytes which have been produced by |
458 | | /// this decompression object. |
459 | 250k | pub fn total_out(&self) -> u64 { |
460 | 250k | self.inner.total_out() |
461 | 250k | } |
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 | 125k | pub fn decompress( |
486 | 125k | &mut self, |
487 | 125k | input: &[u8], |
488 | 125k | output: &mut [u8], |
489 | 125k | flush: FlushDecompress, |
490 | 125k | ) -> Result<Status, DecompressError> { |
491 | 125k | self.inner.decompress(input, output, flush) |
492 | 125k | } |
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 | 0 | unsafe fn write_to_spare_capacity_of_vec<T>( |
648 | 0 | output: &mut Vec<u8>, |
649 | 0 | writer: impl FnOnce(&mut [MaybeUninit<u8>]) -> (usize, T), |
650 | 0 | ) -> T { |
651 | 0 | let cap = output.capacity(); |
652 | 0 | let len = output.len(); |
653 | | |
654 | 0 | let (bytes_written, ret) = writer(output.spare_capacity_mut()); |
655 | 0 | output.set_len(cap.min(len + bytes_written)); // Sanitizes `bytes_written`. |
656 | | |
657 | 0 | ret |
658 | 0 | } Unexecuted instantiation: flate2::mem::write_to_spare_capacity_of_vec::<core::result::Result<flate2::mem::Status, flate2::mem::CompressError>, <flate2::mem::Compress>::compress_vec::{closure#0}>Unexecuted instantiation: flate2::mem::write_to_spare_capacity_of_vec::<core::result::Result<flate2::mem::Status, flate2::mem::DecompressError>, <flate2::mem::Decompress>::decompress_vec::{closure#0}> |
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 | | } |