]> git.proxmox.com Git - rustc.git/blob - src/vendor/flate2/src/mem.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / vendor / flate2 / src / mem.rs
1 use std::error::Error;
2 use std::fmt;
3 use std::io;
4 use std::marker;
5 use std::slice;
6
7 use libc::{c_int, c_uint};
8
9 use Compression;
10 use ffi;
11
12 /// Raw in-memory compression stream for blocks of data.
13 ///
14 /// This type is the building block for the I/O streams in the rest of this
15 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
16 /// maximally flexible in terms of accepting input from any source and being
17 /// able to produce output to any memory location.
18 ///
19 /// It is recommended to use the I/O stream adaptors over this type as they're
20 /// easier to use.
21 ///
22 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
23 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
24 #[derive(Debug)]
25 pub struct Compress {
26 inner: Stream<DirCompress>,
27 }
28
29 /// Raw in-memory decompression stream for blocks of data.
30 ///
31 /// This type is the building block for the I/O streams in the rest of this
32 /// crate. It requires more management than the [`Read`]/[`Write`] API but is
33 /// maximally flexible in terms of accepting input from any source and being
34 /// able to produce output to any memory location.
35 ///
36 /// It is recommended to use the I/O stream adaptors over this type as they're
37 /// easier to use.
38 ///
39 /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
40 /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
41 #[derive(Debug)]
42 pub struct Decompress {
43 inner: Stream<DirDecompress>,
44 }
45
46 #[derive(Debug)]
47 struct Stream<D: Direction> {
48 stream_wrapper: ffi::StreamWrapper,
49 total_in: u64,
50 total_out: u64,
51 _marker: marker::PhantomData<D>,
52 }
53
54 unsafe impl<D: Direction> Send for Stream<D> {}
55 unsafe impl<D: Direction> Sync for Stream<D> {}
56
57 trait Direction {
58 unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int;
59 }
60
61 #[derive(Debug)]
62 enum DirCompress {}
63 #[derive(Debug)]
64 enum DirDecompress {}
65
66 /// Values which indicate the form of flushing to be used when compressing or
67 /// decompressing in-memory data.
68 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
69 pub enum Flush {
70 /// A typical parameter for passing to compression/decompression functions,
71 /// this indicates that the underlying stream to decide how much data to
72 /// accumulate before producing output in order to maximize compression.
73 None = ffi::MZ_NO_FLUSH as isize,
74
75 /// All pending output is flushed to the output buffer and the output is
76 /// aligned on a byte boundary so that the decompressor can get all input
77 /// data available so far.
78 ///
79 /// Flushing may degrade compression for some compression algorithms and so
80 /// it should only be used when necessary. This will complete the current
81 /// deflate block and follow it with an empty stored block.
82 Sync = ffi::MZ_SYNC_FLUSH as isize,
83
84 /// All pending output is flushed to the output buffer, but the output is
85 /// not aligned to a byte boundary.
86 ///
87 /// All of the input data so far will be available to the decompressor (as
88 /// with `Flush::Sync`. This completes the current deflate block and follows
89 /// it with an empty fixed codes block that is 10 bites long, and it assures
90 /// that enough bytes are output in order for the decompessor to finish the
91 /// block before the empty fixed code block.
92 Partial = ffi::MZ_PARTIAL_FLUSH as isize,
93
94 /// A deflate block is completed and emitted, as for `Flush::Sync`, but the
95 /// output is not aligned on a byte boundary and up to seven vits of the
96 /// current block are held to be written as the next byte after the next
97 /// deflate block is completed.
98 ///
99 /// In this case the decompressor may not be provided enough bits at this
100 /// point in order to complete decompression of the data provided so far to
101 /// the compressor, it may need to wait for the next block to be emitted.
102 /// This is for advanced applications that need to control the emission of
103 /// deflate blocks.
104 Block = ffi::MZ_BLOCK as isize,
105
106 /// All output is flushed as with `Flush::Sync` and the compression state is
107 /// reset so decompression can restart from this point if previous
108 /// compressed data has been damaged or if random access is desired.
109 ///
110 /// Using this option too often can seriously degrade compression.
111 Full = ffi::MZ_FULL_FLUSH as isize,
112
113 /// Pending input is processed and pending output is flushed.
114 ///
115 /// The return value may indicate that the stream is not yet done and more
116 /// data has yet to be processed.
117 Finish = ffi::MZ_FINISH as isize,
118 }
119
120 /// Error returned when a decompression object finds that the input stream of
121 /// bytes was not a valid input stream of bytes.
122 #[derive(Debug)]
123 pub struct DataError(());
124
125 /// Possible status results of compressing some data or successfully
126 /// decompressing a block of data.
127 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
128 pub enum Status {
129 /// Indicates success.
130 ///
131 /// Means that more input may be needed but isn't available
132 /// and/or there' smore output to be written but the output buffer is full.
133 Ok,
134
135 /// Indicates that forward progress is not possible due to input or output
136 /// buffers being empty.
137 ///
138 /// For compression it means the input buffer needs some more data or the
139 /// output buffer needs to be freed up before trying again.
140 ///
141 /// For decompression this means that more input is needed to continue or
142 /// the output buffer isn't large enough to contain the result. The function
143 /// can be called again after fixing both.
144 BufError,
145
146 /// Indicates that all input has been consumed and all output bytes have
147 /// been written. Decompression/compression should not be called again.
148 ///
149 /// For decompression with zlib streams the adler-32 of the decompressed
150 /// data has also been verified.
151 StreamEnd,
152 }
153
154 impl Compress {
155 /// Creates a new object ready for compressing data that it's given.
156 ///
157 /// The `level` argument here indicates what level of compression is going
158 /// to be performed, and the `zlib_header` argument indicates whether the
159 /// output data should have a zlib header or not.
160 pub fn new(level: Compression, zlib_header: bool) -> Compress {
161 unsafe {
162 let mut state = ffi::StreamWrapper::default();
163 let ret = ffi::mz_deflateInit2(&mut *state,
164 level as c_int,
165 ffi::MZ_DEFLATED,
166 if zlib_header {
167 ffi::MZ_DEFAULT_WINDOW_BITS
168 } else {
169 -ffi::MZ_DEFAULT_WINDOW_BITS
170 },
171 9,
172 ffi::MZ_DEFAULT_STRATEGY);
173 debug_assert_eq!(ret, 0);
174 Compress {
175 inner: Stream {
176 stream_wrapper: state,
177 total_in: 0,
178 total_out: 0,
179 _marker: marker::PhantomData,
180 },
181 }
182 }
183 }
184
185 /// Returns the total number of input bytes which have been processed by
186 /// this compression object.
187 pub fn total_in(&self) -> u64 {
188 self.inner.total_in
189 }
190
191 /// Returns the total number of output bytes which have been produced by
192 /// this compression object.
193 pub fn total_out(&self) -> u64 {
194 self.inner.total_out
195 }
196
197 /// Quickly resets this compressor without having to reallocate anything.
198 ///
199 /// This is equivalent to dropping this object and then creating a new one.
200 pub fn reset(&mut self) {
201 let rc = unsafe { ffi::mz_deflateReset(&mut *self.inner.stream_wrapper) };
202 assert_eq!(rc, ffi::MZ_OK);
203
204 self.inner.total_in = 0;
205 self.inner.total_out = 0;
206 }
207
208 /// Compresses the input data into the output, consuming only as much
209 /// input as needed and writing as much output as possible.
210 ///
211 /// The flush option can be any of the available flushing parameters.
212 ///
213 /// To learn how much data was consumed or how much output was produced, use
214 /// the `total_in` and `total_out` functions before/after this is called.
215 pub fn compress(&mut self,
216 input: &[u8],
217 output: &mut [u8],
218 flush: Flush)
219 -> Status {
220 let raw = &mut *self.inner.stream_wrapper;
221 raw.next_in = input.as_ptr() as *mut _;
222 raw.avail_in = input.len() as c_uint;
223 raw.next_out = output.as_mut_ptr();
224 raw.avail_out = output.len() as c_uint;
225
226 let rc = unsafe { ffi::mz_deflate(raw, flush as c_int) };
227
228 // Unfortunately the total counters provided by zlib might be only
229 // 32 bits wide and overflow while processing large amounts of data.
230 self.inner.total_in += (raw.next_in as usize -
231 input.as_ptr() as usize) as u64;
232 self.inner.total_out += (raw.next_out as usize -
233 output.as_ptr() as usize) as u64;
234
235 match rc {
236 ffi::MZ_OK => Status::Ok,
237 ffi::MZ_BUF_ERROR => Status::BufError,
238 ffi::MZ_STREAM_END => Status::StreamEnd,
239 c => panic!("unknown return code: {}", c),
240 }
241 }
242
243 /// Compresses the input data into the extra space of the output, consuming
244 /// only as much input as needed and writing as much output as possible.
245 ///
246 /// This function has the same semantics as `compress`, except that the
247 /// length of `vec` is managed by this function. This will not reallocate
248 /// the vector provided or attempt to grow it, so space for the output must
249 /// be reserved in the output vector by the caller before calling this
250 /// function.
251 pub fn compress_vec(&mut self,
252 input: &[u8],
253 output: &mut Vec<u8>,
254 flush: Flush)
255 -> Status {
256 let cap = output.capacity();
257 let len = output.len();
258
259 unsafe {
260 let before = self.total_out();
261 let ret = {
262 let ptr = output.as_mut_ptr().offset(len as isize);
263 let out = slice::from_raw_parts_mut(ptr, cap - len);
264 self.compress(input, out, flush)
265 };
266 output.set_len((self.total_out() - before) as usize + len);
267 return ret
268 }
269 }
270 }
271
272 impl Decompress {
273 /// Creates a new object ready for decompressing data that it's given.
274 ///
275 /// The `zlib_header` argument indicates whether the input data is expected
276 /// to have a zlib header or not.
277 pub fn new(zlib_header: bool) -> Decompress {
278 unsafe {
279 let mut state = ffi::StreamWrapper::default();
280 let ret = ffi::mz_inflateInit2(&mut *state,
281 if zlib_header {
282 ffi::MZ_DEFAULT_WINDOW_BITS
283 } else {
284 -ffi::MZ_DEFAULT_WINDOW_BITS
285 });
286 debug_assert_eq!(ret, 0);
287 Decompress {
288 inner: Stream {
289 stream_wrapper: state,
290 total_in: 0,
291 total_out: 0,
292 _marker: marker::PhantomData,
293 },
294 }
295 }
296 }
297
298 /// Returns the total number of input bytes which have been processed by
299 /// this decompression object.
300 pub fn total_in(&self) -> u64 {
301 self.inner.total_in
302 }
303
304 /// Returns the total number of output bytes which have been produced by
305 /// this decompression object.
306 pub fn total_out(&self) -> u64 {
307 self.inner.total_out
308 }
309
310 /// Decompresses the input data into the output, consuming only as much
311 /// input as needed and writing as much output as possible.
312 ///
313 /// The flush option provided can either be `Flush::None`, `Flush::Sync`,
314 /// or `Flush::Finish`. If the first call passes `Flush::Finish` it is
315 /// assumed that the input and output buffers are both sized large enough to
316 /// decompress the entire stream in a single call.
317 ///
318 /// A flush value of `Flush::Finish` indicates that there are no more source
319 /// bytes available beside what's already in the input buffer, and the
320 /// output buffer is large enough to hold the rest of the decompressed data.
321 ///
322 /// To learn how much data was consumed or how much output was produced, use
323 /// the `total_in` and `total_out` functions before/after this is called.
324 ///
325 /// # Errors
326 ///
327 /// If the input data to this instance of `Decompress` is not a valid
328 /// zlib/deflate stream then this function may return an instance of
329 /// `DataError` to indicate that the stream of input bytes is corrupted.
330 pub fn decompress(&mut self,
331 input: &[u8],
332 output: &mut [u8],
333 flush: Flush)
334 -> Result<Status, DataError> {
335 let raw = &mut *self.inner.stream_wrapper;
336 raw.next_in = input.as_ptr() as *mut u8;
337 raw.avail_in = input.len() as c_uint;
338 raw.next_out = output.as_mut_ptr();
339 raw.avail_out = output.len() as c_uint;
340
341 let rc = unsafe { ffi::mz_inflate(raw, flush as c_int) };
342
343 // Unfortunately the total counters provided by zlib might be only
344 // 32 bits wide and overflow while processing large amounts of data.
345 self.inner.total_in += (raw.next_in as usize -
346 input.as_ptr() as usize) as u64;
347 self.inner.total_out += (raw.next_out as usize -
348 output.as_ptr() as usize) as u64;
349
350 match rc {
351 ffi::MZ_DATA_ERROR |
352 ffi::MZ_STREAM_ERROR => Err(DataError(())),
353 ffi::MZ_OK => Ok(Status::Ok),
354 ffi::MZ_BUF_ERROR => Ok(Status::BufError),
355 ffi::MZ_STREAM_END => Ok(Status::StreamEnd),
356 c => panic!("unknown return code: {}", c),
357 }
358 }
359
360 /// Decompresses the input data into the extra space in the output vector
361 /// specified by `output`.
362 ///
363 /// This function has the same semantics as `decompress`, except that the
364 /// length of `vec` is managed by this function. This will not reallocate
365 /// the vector provided or attempt to grow it, so space for the output must
366 /// be reserved in the output vector by the caller before calling this
367 /// function.
368 ///
369 /// # Errors
370 ///
371 /// If the input data to this instance of `Decompress` is not a valid
372 /// zlib/deflate stream then this function may return an instance of
373 /// `DataError` to indicate that the stream of input bytes is corrupted.
374 pub fn decompress_vec(&mut self,
375 input: &[u8],
376 output: &mut Vec<u8>,
377 flush: Flush)
378 -> Result<Status, DataError> {
379 let cap = output.capacity();
380 let len = output.len();
381
382 unsafe {
383 let before = self.total_out();
384 let ret = {
385 let ptr = output.as_mut_ptr().offset(len as isize);
386 let out = slice::from_raw_parts_mut(ptr, cap - len);
387 self.decompress(input, out, flush)
388 };
389 output.set_len((self.total_out() - before) as usize + len);
390 return ret
391 }
392 }
393
394 /// Performs the equivalent of replacing this decompression state with a
395 /// freshly allocated copy.
396 ///
397 /// This function may not allocate memory, though, and attempts to reuse any
398 /// previously existing resources.
399 ///
400 /// The argument provided here indicates whether the reset state will
401 /// attempt to decode a zlib header first or not.
402 pub fn reset(&mut self, zlib_header: bool) {
403 self._reset(zlib_header);
404 }
405
406 #[cfg(feature = "zlib")]
407 fn _reset(&mut self, zlib_header: bool) {
408 let bits = if zlib_header {
409 ffi::MZ_DEFAULT_WINDOW_BITS
410 } else {
411 -ffi::MZ_DEFAULT_WINDOW_BITS
412 };
413 unsafe {
414 ffi::inflateReset2(&mut *self.inner.stream_wrapper, bits);
415 }
416 self.inner.total_out = 0;
417 self.inner.total_in = 0;
418 }
419
420 #[cfg(not(feature = "zlib"))]
421 fn _reset(&mut self, zlib_header: bool) {
422 *self = Decompress::new(zlib_header);
423 }
424 }
425
426 impl Error for DataError {
427 fn description(&self) -> &str { "deflate data error" }
428 }
429
430 impl From<DataError> for io::Error {
431 fn from(data: DataError) -> io::Error {
432 io::Error::new(io::ErrorKind::Other, data)
433 }
434 }
435
436 impl fmt::Display for DataError {
437 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
438 self.description().fmt(f)
439 }
440 }
441
442 impl Direction for DirCompress {
443 unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
444 ffi::mz_deflateEnd(stream)
445 }
446 }
447 impl Direction for DirDecompress {
448 unsafe fn destroy(stream: *mut ffi::mz_stream) -> c_int {
449 ffi::mz_inflateEnd(stream)
450 }
451 }
452
453 impl<D: Direction> Drop for Stream<D> {
454 fn drop(&mut self) {
455 unsafe {
456 let _ = D::destroy(&mut *self.stream_wrapper);
457 }
458 }
459 }
460
461 #[cfg(test)]
462 mod tests {
463 use std::io::Write;
464
465 use write;
466 use {Compression, Decompress, Flush};
467
468 #[test]
469 fn issue51() {
470 let data = vec![
471 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xb3, 0xc9,
472 0x28, 0xc9, 0xcd, 0xb1, 0xe3, 0xe5, 0xb2, 0xc9, 0x48, 0x4d, 0x4c, 0xb1,
473 0xb3, 0x29, 0xc9, 0x2c, 0xc9, 0x49, 0xb5, 0x33, 0x31, 0x30, 0x51, 0xf0,
474 0xcb, 0x2f, 0x51, 0x70, 0xcb, 0x2f, 0xcd, 0x4b, 0xb1, 0xd1, 0x87, 0x08,
475 0xda, 0xe8, 0x83, 0x95, 0x00, 0x95, 0x26, 0xe5, 0xa7, 0x54, 0x2a, 0x24,
476 0xa5, 0x27, 0xe7, 0xe7, 0xe4, 0x17, 0xd9, 0x2a, 0x95, 0x67, 0x64, 0x96,
477 0xa4, 0x2a, 0x81, 0x8c, 0x48, 0x4e, 0xcd, 0x2b, 0x49, 0x2d, 0xb2, 0xb3,
478 0xc9, 0x30, 0x44, 0x37, 0x01, 0x28, 0x62, 0xa3, 0x0f, 0x95, 0x06, 0xd9,
479 0x05, 0x54, 0x04, 0xe5, 0xe5, 0xa5, 0x67, 0xe6, 0x55, 0xe8, 0x1b, 0xea,
480 0x99, 0xe9, 0x19, 0x21, 0xab, 0xd0, 0x07, 0xd9, 0x01, 0x32, 0x53, 0x1f,
481 0xea, 0x3e, 0x00, 0x94, 0x85, 0xeb, 0xe4, 0xa8, 0x00, 0x00, 0x00
482 ];
483
484 let mut decoded = Vec::with_capacity(data.len()*2);
485
486 let mut d = Decompress::new(false);
487 // decompressed whole deflate stream
488 assert!(d.decompress_vec(&data[10..], &mut decoded, Flush::Finish).is_ok());
489
490 // decompress data that has nothing to do with the deflate stream (this
491 // used to panic)
492 drop(d.decompress_vec(&[0], &mut decoded, Flush::None));
493 }
494
495 #[test]
496 fn reset() {
497 let string = "hello world".as_bytes();
498 let mut zlib = Vec::new();
499 let mut deflate = Vec::new();
500
501 let comp = Compression::Default;
502 write::ZlibEncoder::new(&mut zlib, comp).write_all(string).unwrap();
503 write::DeflateEncoder::new(&mut deflate, comp).write_all(string).unwrap();
504
505 let mut dst = [0; 1024];
506 let mut decoder = Decompress::new(true);
507 decoder.decompress(&zlib, &mut dst, Flush::Finish).unwrap();
508 assert_eq!(decoder.total_out(), string.len() as u64);
509 assert!(dst.starts_with(string));
510
511 decoder.reset(false);
512 decoder.decompress(&deflate, &mut dst, Flush::Finish).unwrap();
513 assert_eq!(decoder.total_out(), string.len() as u64);
514 assert!(dst.starts_with(string));
515 }
516 }