1 | //! A DEFLATE-based stream compression/decompression library |
2 | //! |
3 | //! This library provides support for compression and decompression of |
4 | //! DEFLATE-based streams: |
5 | //! |
6 | //! * the DEFLATE format itself |
7 | //! * the zlib format |
8 | //! * gzip |
9 | //! |
10 | //! These three formats are all closely related and largely only differ in their |
11 | //! headers/footers. This crate has three types in each submodule for dealing |
12 | //! with these three formats. |
13 | //! |
14 | //! # Implementation |
15 | //! |
16 | //! In addition to supporting three formats, this crate supports several different |
17 | //! backends, controlled through this crate's features: |
18 | //! |
19 | //! * `default`, or `rust_backend` - this implementation uses the `miniz_oxide` |
20 | //! crate which is a port of `miniz.c` (below) to Rust. This feature does not |
21 | //! require a C compiler and only requires Rust code. |
22 | //! |
23 | //! * `zlib` - this feature will enable linking against the `libz` library, typically found on most |
24 | //! Linux systems by default. If the library isn't found to already be on the system it will be |
25 | //! compiled from source (this is a C library). |
26 | //! |
27 | //! There's various tradeoffs associated with each implementation, but in general you probably |
28 | //! won't have to tweak the defaults. The default choice is selected to avoid the need for a C |
29 | //! compiler at build time. `zlib-ng-compat` is useful if you're using zlib for compatibility but |
30 | //! want performance via zlib-ng's zlib-compat mode. `zlib` is useful if something else in your |
31 | //! dependencies links the original zlib so you cannot use zlib-ng-compat. The compression ratios |
32 | //! and performance of each of these feature should be roughly comparable, but you'll likely want |
33 | //! to run your own tests if you're curious about the performance. |
34 | //! |
35 | //! # Organization |
36 | //! |
37 | //! This crate consists mainly of three modules, [`read`], [`write`], and |
38 | //! [`bufread`]. Each module contains a number of types used to encode and |
39 | //! decode various streams of data. |
40 | //! |
41 | //! All types in the [`write`] module work on instances of [`Write`][write], |
42 | //! whereas all types in the [`read`] module work on instances of |
43 | //! [`Read`][read] and [`bufread`] works with [`BufRead`][bufread]. If you |
44 | //! are decoding directly from a `&[u8]`, use the [`bufread`] types. |
45 | //! |
46 | //! ``` |
47 | //! use flate2::write::GzEncoder; |
48 | //! use flate2::Compression; |
49 | //! use std::io; |
50 | //! use std::io::prelude::*; |
51 | //! |
52 | //! # fn main() { let _ = run(); } |
53 | //! # fn run() -> io::Result<()> { |
54 | //! let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); |
55 | //! encoder.write_all(b"Example" )?; |
56 | //! # Ok(()) |
57 | //! # } |
58 | //! ``` |
59 | //! |
60 | //! |
61 | //! Other various types are provided at the top-level of the crate for |
62 | //! management and dealing with encoders/decoders. Also note that types which |
63 | //! operate over a specific trait often implement the mirroring trait as well. |
64 | //! For example a `flate2::read::DeflateDecoder<T>` *also* implements the |
65 | //! `Write` trait if `T: Write`. That is, the "dual trait" is forwarded directly |
66 | //! to the underlying object if available. |
67 | //! |
68 | //! # About multi-member Gzip files |
69 | //! |
70 | //! While most `gzip` files one encounters will have a single *member* that can be read |
71 | //! with the [`GzDecoder`], there may be some files which have multiple members. |
72 | //! |
73 | //! A [`GzDecoder`] will only read the first member of gzip data, which may unexpectedly |
74 | //! provide partial results when a multi-member gzip file is encountered. `GzDecoder` is appropriate |
75 | //! for data that is designed to be read as single members from a multi-member file. `bufread::GzDecoder` |
76 | //! and `write::GzDecoder` also allow non-gzip data following gzip data to be handled. |
77 | //! |
78 | //! The [`MultiGzDecoder`] on the other hand will decode all members of a `gzip` file |
79 | //! into one consecutive stream of bytes, which hides the underlying *members* entirely. |
80 | //! If a file contains contains non-gzip data after the gzip data, MultiGzDecoder will |
81 | //! emit an error after decoding the gzip data. This behavior matches the `gzip`, |
82 | //! `gunzip`, and `zcat` command line tools. |
83 | //! |
84 | //! [`read`]: read/index.html |
85 | //! [`bufread`]: bufread/index.html |
86 | //! [`write`]: write/index.html |
87 | //! [read]: https://doc.rust-lang.org/std/io/trait.Read.html |
88 | //! [write]: https://doc.rust-lang.org/std/io/trait.Write.html |
89 | //! [bufread]: https://doc.rust-lang.org/std/io/trait.BufRead.html |
90 | //! [`GzDecoder`]: read/struct.GzDecoder.html |
91 | //! [`MultiGzDecoder`]: read/struct.MultiGzDecoder.html |
92 | #![doc (html_root_url = "https://docs.rs/flate2/0.2" )] |
93 | #![deny (missing_docs)] |
94 | #![deny (missing_debug_implementations)] |
95 | #![allow (trivial_numeric_casts)] |
96 | #![cfg_attr (test, deny(warnings))] |
97 | #![cfg_attr (docsrs, feature(doc_auto_cfg))] |
98 | |
99 | #[cfg (not(feature = "any_impl" ,))] |
100 | compile_error!("You need to choose a zlib backend" ); |
101 | |
102 | pub use crate::crc::{Crc, CrcReader, CrcWriter}; |
103 | pub use crate::gz::GzBuilder; |
104 | pub use crate::gz::GzHeader; |
105 | pub use crate::mem::{Compress, CompressError, Decompress, DecompressError, Status}; |
106 | pub use crate::mem::{FlushCompress, FlushDecompress}; |
107 | |
108 | mod bufreader; |
109 | mod crc; |
110 | mod deflate; |
111 | mod ffi; |
112 | mod gz; |
113 | mod mem; |
114 | mod zio; |
115 | mod zlib; |
116 | |
117 | /// Types which operate over [`Read`] streams, both encoders and decoders for |
118 | /// various formats. |
119 | /// |
120 | /// Note that the `read` decoder types may read past the end of the compressed |
121 | /// data while decoding. If the caller requires subsequent reads to start |
122 | /// immediately following the compressed data wrap the `Read` type in a |
123 | /// [`BufReader`] and use the `BufReader` with the equivalent decoder from the |
124 | /// `bufread` module and also for the subsequent reads. |
125 | /// |
126 | /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html |
127 | /// [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html |
128 | pub mod read { |
129 | pub use crate::deflate::read::DeflateDecoder; |
130 | pub use crate::deflate::read::DeflateEncoder; |
131 | pub use crate::gz::read::GzDecoder; |
132 | pub use crate::gz::read::GzEncoder; |
133 | pub use crate::gz::read::MultiGzDecoder; |
134 | pub use crate::zlib::read::ZlibDecoder; |
135 | pub use crate::zlib::read::ZlibEncoder; |
136 | } |
137 | |
138 | /// Types which operate over [`Write`] streams, both encoders and decoders for |
139 | /// various formats. |
140 | /// |
141 | /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
142 | pub mod write { |
143 | pub use crate::deflate::write::DeflateDecoder; |
144 | pub use crate::deflate::write::DeflateEncoder; |
145 | pub use crate::gz::write::GzDecoder; |
146 | pub use crate::gz::write::GzEncoder; |
147 | pub use crate::gz::write::MultiGzDecoder; |
148 | pub use crate::zlib::write::ZlibDecoder; |
149 | pub use crate::zlib::write::ZlibEncoder; |
150 | } |
151 | |
152 | /// Types which operate over [`BufRead`] streams, both encoders and decoders for |
153 | /// various formats. |
154 | /// |
155 | /// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html |
156 | pub mod bufread { |
157 | pub use crate::deflate::bufread::DeflateDecoder; |
158 | pub use crate::deflate::bufread::DeflateEncoder; |
159 | pub use crate::gz::bufread::GzDecoder; |
160 | pub use crate::gz::bufread::GzEncoder; |
161 | pub use crate::gz::bufread::MultiGzDecoder; |
162 | pub use crate::zlib::bufread::ZlibDecoder; |
163 | pub use crate::zlib::bufread::ZlibEncoder; |
164 | } |
165 | |
166 | fn _assert_send_sync() { |
167 | fn _assert_send_sync<T: Send + Sync>() {} |
168 | |
169 | _assert_send_sync::<read::DeflateEncoder<&[u8]>>(); |
170 | _assert_send_sync::<read::DeflateDecoder<&[u8]>>(); |
171 | _assert_send_sync::<read::ZlibEncoder<&[u8]>>(); |
172 | _assert_send_sync::<read::ZlibDecoder<&[u8]>>(); |
173 | _assert_send_sync::<read::GzEncoder<&[u8]>>(); |
174 | _assert_send_sync::<read::GzDecoder<&[u8]>>(); |
175 | _assert_send_sync::<read::MultiGzDecoder<&[u8]>>(); |
176 | _assert_send_sync::<write::DeflateEncoder<Vec<u8>>>(); |
177 | _assert_send_sync::<write::DeflateDecoder<Vec<u8>>>(); |
178 | _assert_send_sync::<write::ZlibEncoder<Vec<u8>>>(); |
179 | _assert_send_sync::<write::ZlibDecoder<Vec<u8>>>(); |
180 | _assert_send_sync::<write::GzEncoder<Vec<u8>>>(); |
181 | _assert_send_sync::<write::GzDecoder<Vec<u8>>>(); |
182 | } |
183 | |
184 | /// When compressing data, the compression level can be specified by a value in |
185 | /// this struct. |
186 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
187 | pub struct Compression(u32); |
188 | |
189 | impl Compression { |
190 | /// Creates a new description of the compression level with an explicitly |
191 | /// specified integer. |
192 | /// |
193 | /// The integer here is typically on a scale of 0-9 where 0 means "no |
194 | /// compression" and 9 means "take as long as you'd like". |
195 | pub const fn new(level: u32) -> Compression { |
196 | Compression(level) |
197 | } |
198 | |
199 | /// No compression is to be performed, this may actually inflate data |
200 | /// slightly when encoding. |
201 | pub const fn none() -> Compression { |
202 | Compression(0) |
203 | } |
204 | |
205 | /// Optimize for the best speed of encoding. |
206 | pub const fn fast() -> Compression { |
207 | Compression(1) |
208 | } |
209 | |
210 | /// Optimize for the size of data being encoded. |
211 | pub const fn best() -> Compression { |
212 | Compression(9) |
213 | } |
214 | |
215 | /// Returns an integer representing the compression level, typically on a |
216 | /// scale of 0-9 |
217 | pub fn level(&self) -> u32 { |
218 | self.0 |
219 | } |
220 | } |
221 | |
222 | impl Default for Compression { |
223 | fn default() -> Compression { |
224 | Compression(6) |
225 | } |
226 | } |
227 | |
228 | #[cfg (test)] |
229 | fn random_bytes() -> impl Iterator<Item = u8> { |
230 | use rand::Rng; |
231 | use std::iter; |
232 | |
233 | iter::repeat(()).map(|_| rand::thread_rng().gen()) |
234 | } |
235 | |