]> git.proxmox.com Git - rustc.git/blame - vendor/flate2/src/mem.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / vendor / flate2 / src / mem.rs
CommitLineData
7cac9316
XL
1use std::error::Error;
2use std::fmt;
3use std::io;
7cac9316
XL
4use std::slice;
5
60c5eb7d
XL
6use crate::ffi::{self, Backend, Deflate, DeflateBackend, Inflate, InflateBackend};
7use crate::Compression;
7cac9316
XL
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
ea8adc8c 12/// crate. It requires more management than the [`Read`]/[`Write`] API but is
7cac9316
XL
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.
ea8adc8c
XL
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)]
7cac9316 22pub struct Compress {
60c5eb7d 23 inner: Deflate,
7cac9316
XL
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
ea8adc8c 29/// crate. It requires more management than the [`Read`]/[`Write`] API but is
7cac9316
XL
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.
ea8adc8c
XL
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)]
7cac9316 39pub struct Decompress {
60c5eb7d 40 inner: Inflate,
7cac9316
XL
41}
42
ea8adc8c 43#[derive(Copy, Clone, PartialEq, Eq, Debug)]
ff7c6d11
XL
44/// Values which indicate the form of flushing to be used when compressing
45/// in-memory data.
46pub enum FlushCompress {
7cac9316
XL
47 /// A typical parameter for passing to compression/decompression functions,
48 /// this indicates that the underlying stream to decide how much data to
49 /// accumulate before producing output in order to maximize compression.
50 None = ffi::MZ_NO_FLUSH as isize,
51
52 /// All pending output is flushed to the output buffer and the output is
53 /// aligned on a byte boundary so that the decompressor can get all input
54 /// data available so far.
55 ///
56 /// Flushing may degrade compression for some compression algorithms and so
57 /// it should only be used when necessary. This will complete the current
58 /// deflate block and follow it with an empty stored block.
59 Sync = ffi::MZ_SYNC_FLUSH as isize,
60
61 /// All pending output is flushed to the output buffer, but the output is
62 /// not aligned to a byte boundary.
63 ///
64 /// All of the input data so far will be available to the decompressor (as
65 /// with `Flush::Sync`. This completes the current deflate block and follows
66 /// it with an empty fixed codes block that is 10 bites long, and it assures
67 /// that enough bytes are output in order for the decompessor to finish the
68 /// block before the empty fixed code block.
69 Partial = ffi::MZ_PARTIAL_FLUSH as isize,
70
7cac9316
XL
71 /// All output is flushed as with `Flush::Sync` and the compression state is
72 /// reset so decompression can restart from this point if previous
73 /// compressed data has been damaged or if random access is desired.
74 ///
75 /// Using this option too often can seriously degrade compression.
76 Full = ffi::MZ_FULL_FLUSH as isize,
77
78 /// Pending input is processed and pending output is flushed.
79 ///
80 /// The return value may indicate that the stream is not yet done and more
81 /// data has yet to be processed.
82 Finish = ffi::MZ_FINISH as isize,
ff7c6d11
XL
83
84 #[doc(hidden)]
b7449926 85 _Nonexhaustive,
ff7c6d11
XL
86}
87
88#[derive(Copy, Clone, PartialEq, Eq, Debug)]
89/// Values which indicate the form of flushing to be used when
90/// decompressing in-memory data.
91pub enum FlushDecompress {
92 /// A typical parameter for passing to compression/decompression functions,
93 /// this indicates that the underlying stream to decide how much data to
94 /// accumulate before producing output in order to maximize compression.
95 None = ffi::MZ_NO_FLUSH as isize,
96
97 /// All pending output is flushed to the output buffer and the output is
98 /// aligned on a byte boundary so that the decompressor can get all input
99 /// data available so far.
100 ///
101 /// Flushing may degrade compression for some compression algorithms and so
102 /// it should only be used when necessary. This will complete the current
103 /// deflate block and follow it with an empty stored block.
104 Sync = ffi::MZ_SYNC_FLUSH as isize,
105
106 /// Pending input is processed and pending output is flushed.
107 ///
108 /// The return value may indicate that the stream is not yet done and more
109 /// data has yet to be processed.
110 Finish = ffi::MZ_FINISH as isize,
111
112 #[doc(hidden)]
b7449926
XL
113 _Nonexhaustive,
114}
115
116/// The inner state for an error when decompressing
117#[derive(Debug, Default)]
60c5eb7d
XL
118pub(crate) struct DecompressErrorInner {
119 pub(crate) needs_dictionary: Option<u32>,
7cac9316
XL
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(Debug)]
60c5eb7d 125pub struct DecompressError(pub(crate) DecompressErrorInner);
b7449926
XL
126
127impl 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 pub fn needs_dictionary(&self) -> Option<u32> {
133 self.0.needs_dictionary
134 }
135}
ff7c6d11 136
60c5eb7d
XL
137#[inline]
138pub(crate) fn decompress_failed() -> Result<Status, DecompressError> {
139 Err(DecompressError(Default::default()))
140}
141
142#[inline]
143pub(crate) fn decompress_need_dict(adler: u32) -> Result<Status, DecompressError> {
144 Err(DecompressError(DecompressErrorInner {
145 needs_dictionary: Some(adler),
146 }))
147}
148
ff7c6d11
XL
149/// Error returned when a compression object is used incorrectly or otherwise
150/// generates an error.
151#[derive(Debug)]
60c5eb7d 152pub struct CompressError(pub(crate) ());
7cac9316
XL
153
154/// Possible status results of compressing some data or successfully
155/// decompressing a block of data.
ea8adc8c 156#[derive(Copy, Clone, PartialEq, Eq, Debug)]
7cac9316
XL
157pub enum Status {
158 /// Indicates success.
159 ///
160 /// Means that more input may be needed but isn't available
ff7c6d11 161 /// and/or there's more output to be written but the output buffer is full.
7cac9316
XL
162 Ok,
163
164 /// Indicates that forward progress is not possible due to input or output
165 /// buffers being empty.
166 ///
167 /// For compression it means the input buffer needs some more data or the
168 /// output buffer needs to be freed up before trying again.
169 ///
170 /// For decompression this means that more input is needed to continue or
171 /// the output buffer isn't large enough to contain the result. The function
172 /// can be called again after fixing both.
173 BufError,
174
175 /// Indicates that all input has been consumed and all output bytes have
176 /// been written. Decompression/compression should not be called again.
177 ///
178 /// For decompression with zlib streams the adler-32 of the decompressed
179 /// data has also been verified.
180 StreamEnd,
181}
182
183impl Compress {
184 /// Creates a new object ready for compressing data that it's given.
185 ///
186 /// The `level` argument here indicates what level of compression is going
187 /// to be performed, and the `zlib_header` argument indicates whether the
188 /// output data should have a zlib header or not.
189 pub fn new(level: Compression, zlib_header: bool) -> Compress {
60c5eb7d
XL
190 Compress {
191 inner: Deflate::make(level, zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
192 }
193 }
194
195 /// Creates a new object ready for compressing data that it's given.
196 ///
197 /// The `level` argument here indicates what level of compression is going
198 /// to be performed, and the `zlib_header` argument indicates whether the
199 /// output data should have a zlib header or not. The `window_bits` parameter
200 /// indicates the base-2 logarithm of the sliding window size and must be
201 /// between 9 and 15.
202 ///
203 /// # Panics
204 ///
205 /// If `window_bits` does not fall into the range 9 ..= 15,
206 /// `new_with_window_bits` will panic.
207 ///
208 /// # Note
209 ///
210 /// This constructor is only available when the `zlib` feature is used.
211 /// Other backends currently do not support custom window bits.
212 #[cfg(feature = "zlib")]
213 pub fn new_with_window_bits(
214 level: Compression,
215 zlib_header: bool,
216 window_bits: u8,
217 ) -> Compress {
218 Compress {
219 inner: Deflate::make(level, zlib_header, window_bits),
7cac9316
XL
220 }
221 }
222
223 /// Returns the total number of input bytes which have been processed by
224 /// this compression object.
225 pub fn total_in(&self) -> u64 {
60c5eb7d 226 self.inner.total_in()
7cac9316
XL
227 }
228
229 /// Returns the total number of output bytes which have been produced by
230 /// this compression object.
231 pub fn total_out(&self) -> u64 {
60c5eb7d 232 self.inner.total_out()
7cac9316
XL
233 }
234
b7449926
XL
235 /// Specifies the compression dictionary to use.
236 ///
237 /// Returns the Adler-32 checksum of the dictionary.
238 #[cfg(feature = "zlib")]
239 pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, CompressError> {
60c5eb7d 240 let stream = &mut *self.inner.inner.stream_wrapper;
b7449926 241 let rc = unsafe {
60c5eb7d 242 assert!(dictionary.len() < ffi::uInt::max_value() as usize);
b7449926
XL
243 ffi::deflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
244 };
245
246 match rc {
247 ffi::MZ_STREAM_ERROR => Err(CompressError(())),
248 ffi::MZ_OK => Ok(stream.adler as u32),
249 c => panic!("unknown return code: {}", c),
250 }
251 }
252
7cac9316
XL
253 /// Quickly resets this compressor without having to reallocate anything.
254 ///
255 /// This is equivalent to dropping this object and then creating a new one.
256 pub fn reset(&mut self) {
60c5eb7d 257 self.inner.reset();
7cac9316
XL
258 }
259
b7449926
XL
260 /// Dynamically updates the compression level.
261 ///
262 /// This can be used to switch between compression levels for different
263 /// kinds of data, or it can be used in conjunction with a call to reset
264 /// to reuse the compressor.
265 ///
266 /// This may return an error if there wasn't enough output space to complete
267 /// the compression of the available input data before changing the
268 /// compression level. Flushing the stream before calling this method
269 /// ensures that the function will succeed on the first call.
270 #[cfg(feature = "zlib")]
271 pub fn set_level(&mut self, level: Compression) -> Result<(), CompressError> {
60c5eb7d
XL
272 use libc::c_int;
273 let stream = &mut *self.inner.inner.stream_wrapper;
b7449926
XL
274
275 let rc = unsafe { ffi::deflateParams(stream, level.0 as c_int, ffi::MZ_DEFAULT_STRATEGY) };
276
277 match rc {
278 ffi::MZ_OK => Ok(()),
279 ffi::MZ_BUF_ERROR => Err(CompressError(())),
280 c => panic!("unknown return code: {}", c),
281 }
282 }
283
7cac9316
XL
284 /// Compresses the input data into the output, consuming only as much
285 /// input as needed and writing as much output as possible.
286 ///
ff7c6d11 287 /// The flush option can be any of the available `FlushCompress` parameters.
7cac9316
XL
288 ///
289 /// To learn how much data was consumed or how much output was produced, use
290 /// the `total_in` and `total_out` functions before/after this is called.
b7449926
XL
291 pub fn compress(
292 &mut self,
293 input: &[u8],
294 output: &mut [u8],
295 flush: FlushCompress,
296 ) -> Result<Status, CompressError> {
60c5eb7d 297 self.inner.compress(input, output, flush)
7cac9316
XL
298 }
299
300 /// Compresses the input data into the extra space of the output, consuming
301 /// only as much input as needed and writing as much output as possible.
302 ///
303 /// This function has the same semantics as `compress`, except that the
304 /// length of `vec` is managed by this function. This will not reallocate
305 /// the vector provided or attempt to grow it, so space for the output must
306 /// be reserved in the output vector by the caller before calling this
307 /// function.
b7449926
XL
308 pub fn compress_vec(
309 &mut self,
310 input: &[u8],
311 output: &mut Vec<u8>,
312 flush: FlushCompress,
313 ) -> Result<Status, CompressError> {
7cac9316
XL
314 let cap = output.capacity();
315 let len = output.len();
316
317 unsafe {
318 let before = self.total_out();
319 let ret = {
320 let ptr = output.as_mut_ptr().offset(len as isize);
321 let out = slice::from_raw_parts_mut(ptr, cap - len);
322 self.compress(input, out, flush)
323 };
324 output.set_len((self.total_out() - before) as usize + len);
b7449926 325 return ret;
7cac9316
XL
326 }
327 }
328}
329
330impl Decompress {
331 /// Creates a new object ready for decompressing data that it's given.
332 ///
333 /// The `zlib_header` argument indicates whether the input data is expected
334 /// to have a zlib header or not.
335 pub fn new(zlib_header: bool) -> Decompress {
60c5eb7d
XL
336 Decompress {
337 inner: Inflate::make(zlib_header, ffi::MZ_DEFAULT_WINDOW_BITS as u8),
338 }
339 }
340
341 /// Creates a new object ready for decompressing data that it's given.
342 ///
343 /// The `zlib_header` argument indicates whether the input data is expected
344 /// to have a zlib header or not. The `window_bits` parameter indicates the
345 /// base-2 logarithm of the sliding window size and must be between 9 and 15.
346 ///
347 /// # Panics
348 ///
349 /// If `window_bits` does not fall into the range 9 ..= 15,
350 /// `new_with_window_bits` will panic.
351 ///
352 /// # Note
353 ///
354 /// This constructor is only available when the `zlib` feature is used.
355 /// Other backends currently do not support custom window bits.
356 #[cfg(feature = "zlib")]
357 pub fn new_with_window_bits(zlib_header: bool, window_bits: u8) -> Decompress {
358 Decompress {
359 inner: Inflate::make(zlib_header, window_bits),
7cac9316
XL
360 }
361 }
362
363 /// Returns the total number of input bytes which have been processed by
364 /// this decompression object.
365 pub fn total_in(&self) -> u64 {
60c5eb7d 366 self.inner.total_in()
7cac9316
XL
367 }
368
369 /// Returns the total number of output bytes which have been produced by
370 /// this decompression object.
371 pub fn total_out(&self) -> u64 {
60c5eb7d 372 self.inner.total_out()
7cac9316
XL
373 }
374
375 /// Decompresses the input data into the output, consuming only as much
376 /// input as needed and writing as much output as possible.
377 ///
ff7c6d11
XL
378 /// The flush option can be any of the available `FlushDecompress` parameters.
379 ///
380 /// If the first call passes `FlushDecompress::Finish` it is assumed that
381 /// the input and output buffers are both sized large enough to decompress
382 /// the entire stream in a single call.
7cac9316 383 ///
ff7c6d11
XL
384 /// A flush value of `FlushDecompress::Finish` indicates that there are no
385 /// more source bytes available beside what's already in the input buffer,
386 /// and the output buffer is large enough to hold the rest of the
387 /// decompressed data.
7cac9316
XL
388 ///
389 /// To learn how much data was consumed or how much output was produced, use
390 /// the `total_in` and `total_out` functions before/after this is called.
ea8adc8c
XL
391 ///
392 /// # Errors
393 ///
394 /// If the input data to this instance of `Decompress` is not a valid
395 /// zlib/deflate stream then this function may return an instance of
ff7c6d11 396 /// `DecompressError` to indicate that the stream of input bytes is corrupted.
b7449926
XL
397 pub fn decompress(
398 &mut self,
399 input: &[u8],
400 output: &mut [u8],
401 flush: FlushDecompress,
402 ) -> Result<Status, DecompressError> {
60c5eb7d 403 self.inner.decompress(input, output, flush)
7cac9316
XL
404 }
405
406 /// Decompresses the input data into the extra space in the output vector
407 /// specified by `output`.
408 ///
409 /// This function has the same semantics as `decompress`, except that the
410 /// length of `vec` is managed by this function. This will not reallocate
411 /// the vector provided or attempt to grow it, so space for the output must
412 /// be reserved in the output vector by the caller before calling this
413 /// function.
ea8adc8c
XL
414 ///
415 /// # Errors
416 ///
417 /// If the input data to this instance of `Decompress` is not a valid
418 /// zlib/deflate stream then this function may return an instance of
ff7c6d11 419 /// `DecompressError` to indicate that the stream of input bytes is corrupted.
b7449926
XL
420 pub fn decompress_vec(
421 &mut self,
422 input: &[u8],
423 output: &mut Vec<u8>,
424 flush: FlushDecompress,
425 ) -> Result<Status, DecompressError> {
7cac9316
XL
426 let cap = output.capacity();
427 let len = output.len();
428
429 unsafe {
430 let before = self.total_out();
431 let ret = {
432 let ptr = output.as_mut_ptr().offset(len as isize);
433 let out = slice::from_raw_parts_mut(ptr, cap - len);
434 self.decompress(input, out, flush)
435 };
436 output.set_len((self.total_out() - before) as usize + len);
b7449926
XL
437 return ret;
438 }
439 }
440
441 /// Specifies the decompression dictionary to use.
442 #[cfg(feature = "zlib")]
443 pub fn set_dictionary(&mut self, dictionary: &[u8]) -> Result<u32, DecompressError> {
60c5eb7d 444 let stream = &mut *self.inner.inner.stream_wrapper;
b7449926 445 let rc = unsafe {
60c5eb7d 446 assert!(dictionary.len() < ffi::uInt::max_value() as usize);
b7449926
XL
447 ffi::inflateSetDictionary(stream, dictionary.as_ptr(), dictionary.len() as ffi::uInt)
448 };
449
450 match rc {
451 ffi::MZ_STREAM_ERROR => Err(DecompressError(Default::default())),
452 ffi::MZ_DATA_ERROR => Err(DecompressError(DecompressErrorInner {
453 needs_dictionary: Some(stream.adler as u32),
454 })),
455 ffi::MZ_OK => Ok(stream.adler as u32),
456 c => panic!("unknown return code: {}", c),
7cac9316
XL
457 }
458 }
459
460 /// Performs the equivalent of replacing this decompression state with a
461 /// freshly allocated copy.
462 ///
463 /// This function may not allocate memory, though, and attempts to reuse any
464 /// previously existing resources.
465 ///
466 /// The argument provided here indicates whether the reset state will
467 /// attempt to decode a zlib header first or not.
468 pub fn reset(&mut self, zlib_header: bool) {
60c5eb7d 469 self.inner.reset(zlib_header);
7cac9316
XL
470 }
471}
472
ff7c6d11 473impl Error for DecompressError {
b7449926
XL
474 fn description(&self) -> &str {
475 "deflate decompression error"
476 }
ff7c6d11
XL
477}
478
479impl From<DecompressError> for io::Error {
480 fn from(data: DecompressError) -> io::Error {
481 io::Error::new(io::ErrorKind::Other, data)
482 }
483}
484
485impl fmt::Display for DecompressError {
486 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
487 self.description().fmt(f)
488 }
489}
490
491impl Error for CompressError {
b7449926
XL
492 fn description(&self) -> &str {
493 "deflate compression error"
494 }
7cac9316
XL
495}
496
ff7c6d11
XL
497impl From<CompressError> for io::Error {
498 fn from(data: CompressError) -> io::Error {
7cac9316
XL
499 io::Error::new(io::ErrorKind::Other, data)
500 }
501}
502
ff7c6d11 503impl fmt::Display for CompressError {
7cac9316
XL
504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505 self.description().fmt(f)
506 }
507}
508
7cac9316
XL
509#[cfg(test)]
510mod tests {
511 use std::io::Write;
512
60c5eb7d
XL
513 use crate::write;
514 use crate::{Compression, Decompress, FlushDecompress};
7cac9316 515
b7449926 516 #[cfg(feature = "zlib")]
60c5eb7d 517 use crate::{Compress, FlushCompress};
b7449926 518
7cac9316
XL
519 #[test]
520 fn issue51() {
521 let data = vec![
b7449926
XL
522 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9, 0x28, 0xc9,
523 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1, 0xb3, 0x29, 0xc9, 0x2c,
524 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0, 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f,
525 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08, 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5,
526 0xa7, 0x54, 0x2a, 0x24, 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67,
527 0x64, 0x96, 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
528 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9, 0x05, 0x54,
529 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea, 0x99, 0xe9, 0x19, 0x21,
530 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f, 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb,
531 0xe4, 0xa8, 0x00, 0x00, 0x00,
7cac9316
XL
532 ];
533
b7449926 534 let mut decoded = Vec::with_capacity(data.len() * 2);
7cac9316
XL
535
536 let mut d = Decompress::new(false);
537 // decompressed whole deflate stream
60c5eb7d
XL
538 assert!(d
539 .decompress_vec(&data[10..], &mut decoded, FlushDecompress::Finish)
540 .is_ok());
7cac9316
XL
541
542 // decompress data that has nothing to do with the deflate stream (this
543 // used to panic)
ff7c6d11 544 drop(d.decompress_vec(&[0], &mut decoded, FlushDecompress::None));
7cac9316
XL
545 }
546
547 #[test]
548 fn reset() {
549 let string = "hello world".as_bytes();
550 let mut zlib = Vec::new();
551 let mut deflate = Vec::new();
552
ff7c6d11 553 let comp = Compression::default();
b7449926
XL
554 write::ZlibEncoder::new(&mut zlib, comp)
555 .write_all(string)
556 .unwrap();
557 write::DeflateEncoder::new(&mut deflate, comp)
558 .write_all(string)
559 .unwrap();
7cac9316
XL
560
561 let mut dst = [0; 1024];
562 let mut decoder = Decompress::new(true);
b7449926
XL
563 decoder
564 .decompress(&zlib, &mut dst, FlushDecompress::Finish)
565 .unwrap();
7cac9316
XL
566 assert_eq!(decoder.total_out(), string.len() as u64);
567 assert!(dst.starts_with(string));
568
569 decoder.reset(false);
b7449926
XL
570 decoder
571 .decompress(&deflate, &mut dst, FlushDecompress::Finish)
572 .unwrap();
7cac9316
XL
573 assert_eq!(decoder.total_out(), string.len() as u64);
574 assert!(dst.starts_with(string));
575 }
b7449926
XL
576
577 #[cfg(feature = "zlib")]
578 #[test]
579 fn set_dictionary_with_zlib_header() {
580 let string = "hello, hello!".as_bytes();
581 let dictionary = "hello".as_bytes();
582
583 let mut encoded = Vec::with_capacity(1024);
584
585 let mut encoder = Compress::new(Compression::default(), true);
586
587 let dictionary_adler = encoder.set_dictionary(&dictionary).unwrap();
588
589 encoder
590 .compress_vec(string, &mut encoded, FlushCompress::Finish)
591 .unwrap();
592
593 assert_eq!(encoder.total_in(), string.len() as u64);
594 assert_eq!(encoder.total_out(), encoded.len() as u64);
595
596 let mut decoder = Decompress::new(true);
597 let mut decoded = [0; 1024];
598 let decompress_error = decoder
599 .decompress(&encoded, &mut decoded, FlushDecompress::Finish)
600 .expect_err("decompression should fail due to requiring a dictionary");
601
602 let required_adler = decompress_error.needs_dictionary()
603 .expect("the first call to decompress should indicate a dictionary is required along with the required Adler-32 checksum");
604
605 assert_eq!(required_adler, dictionary_adler,
606 "the Adler-32 checksum should match the value when the dictionary was set on the compressor");
607
608 let actual_adler = decoder.set_dictionary(&dictionary).unwrap();
609
610 assert_eq!(required_adler, actual_adler);
611
612 // Decompress the rest of the input to the remainder of the output buffer
613 let total_in = decoder.total_in();
614 let total_out = decoder.total_out();
615
616 let decompress_result = decoder.decompress(
617 &encoded[total_in as usize..],
618 &mut decoded[total_out as usize..],
619 FlushDecompress::Finish,
620 );
621 assert!(decompress_result.is_ok());
622
623 assert_eq!(&decoded[..decoder.total_out() as usize], string);
624 }
625
626 #[cfg(feature = "zlib")]
627 #[test]
628 fn set_dictionary_raw() {
629 let string = "hello, hello!".as_bytes();
630 let dictionary = "hello".as_bytes();
631
632 let mut encoded = Vec::with_capacity(1024);
633
634 let mut encoder = Compress::new(Compression::default(), false);
635
636 encoder.set_dictionary(&dictionary).unwrap();
637
638 encoder
639 .compress_vec(string, &mut encoded, FlushCompress::Finish)
640 .unwrap();
641
642 assert_eq!(encoder.total_in(), string.len() as u64);
643 assert_eq!(encoder.total_out(), encoded.len() as u64);
644
645 let mut decoder = Decompress::new(false);
646
647 decoder.set_dictionary(&dictionary).unwrap();
648
649 let mut decoded = [0; 1024];
650 let decompress_result = decoder.decompress(&encoded, &mut decoded, FlushDecompress::Finish);
651
652 assert!(decompress_result.is_ok());
653
654 assert_eq!(&decoded[..decoder.total_out() as usize], string);
655 }
7cac9316 656}