| 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` to Rust. This feature does not |
| 21 | //! require a C compiler, and only uses safe Rust code. |
| 22 | //! |
| 23 | //! * `zlib-rs` - this implementation utilizes the `zlib-rs` crate, a Rust rewrite of zlib. |
| 24 | //! This backend is the fastest, at the cost of some `unsafe` Rust code. |
| 25 | //! |
| 26 | //! Several backends implemented in C are also available. |
| 27 | //! These are useful in case you are already using a specific C implementation |
| 28 | //! and need the result of compression to be bit-identical. |
| 29 | //! See the crate's README for details on the available C backends. |
| 30 | //! |
| 31 | //! The `zlib-rs` backend typically outperforms all the C implementations. |
| 32 | //! |
| 33 | //! # Organization |
| 34 | //! |
| 35 | //! This crate consists mainly of three modules, [`read`], [`write`], and |
| 36 | //! [`bufread`]. Each module contains a number of types used to encode and |
| 37 | //! decode various streams of data. |
| 38 | //! |
| 39 | //! All types in the [`write`] module work on instances of [`Write`][write], |
| 40 | //! whereas all types in the [`read`] module work on instances of |
| 41 | //! [`Read`][read] and [`bufread`] works with [`BufRead`][bufread]. If you |
| 42 | //! are decoding directly from a `&[u8]`, use the [`bufread`] types. |
| 43 | //! |
| 44 | //! ``` |
| 45 | //! use flate2::write::GzEncoder; |
| 46 | //! use flate2::Compression; |
| 47 | //! use std::io; |
| 48 | //! use std::io::prelude::*; |
| 49 | //! |
| 50 | //! # fn main() { let _ = run(); } |
| 51 | //! # fn run() -> io::Result<()> { |
| 52 | //! let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); |
| 53 | //! encoder.write_all(b"Example" )?; |
| 54 | //! # Ok(()) |
| 55 | //! # } |
| 56 | //! ``` |
| 57 | //! |
| 58 | //! |
| 59 | //! Other various types are provided at the top-level of the crate for |
| 60 | //! management and dealing with encoders/decoders. Also note that types which |
| 61 | //! operate over a specific trait often implement the mirroring trait as well. |
| 62 | //! For example a `flate2::read::DeflateDecoder<T>` *also* implements the |
| 63 | //! `Write` trait if `T: Write`. That is, the "dual trait" is forwarded directly |
| 64 | //! to the underlying object if available. |
| 65 | //! |
| 66 | //! # About multi-member Gzip files |
| 67 | //! |
| 68 | //! While most `gzip` files one encounters will have a single *member* that can be read |
| 69 | //! with the [`GzDecoder`], there may be some files which have multiple members. |
| 70 | //! |
| 71 | //! A [`GzDecoder`] will only read the first member of gzip data, which may unexpectedly |
| 72 | //! provide partial results when a multi-member gzip file is encountered. `GzDecoder` is appropriate |
| 73 | //! for data that is designed to be read as single members from a multi-member file. `bufread::GzDecoder` |
| 74 | //! and `write::GzDecoder` also allow non-gzip data following gzip data to be handled. |
| 75 | //! |
| 76 | //! The [`MultiGzDecoder`] on the other hand will decode all members of a `gzip` file |
| 77 | //! into one consecutive stream of bytes, which hides the underlying *members* entirely. |
| 78 | //! If a file contains non-gzip data after the gzip data, MultiGzDecoder will |
| 79 | //! emit an error after decoding the gzip data. This behavior matches the `gzip`, |
| 80 | //! `gunzip`, and `zcat` command line tools. |
| 81 | //! |
| 82 | //! [`read`]: read/index.html |
| 83 | //! [`bufread`]: bufread/index.html |
| 84 | //! [`write`]: write/index.html |
| 85 | //! [read]: https://doc.rust-lang.org/std/io/trait.Read.html |
| 86 | //! [write]: https://doc.rust-lang.org/std/io/trait.Write.html |
| 87 | //! [bufread]: https://doc.rust-lang.org/std/io/trait.BufRead.html |
| 88 | //! [`GzDecoder`]: read/struct.GzDecoder.html |
| 89 | //! [`MultiGzDecoder`]: read/struct.MultiGzDecoder.html |
| 90 | #![doc (html_root_url = "https://docs.rs/flate2/0.2" )] |
| 91 | #![deny (missing_docs)] |
| 92 | #![deny (missing_debug_implementations)] |
| 93 | #![allow (trivial_numeric_casts)] |
| 94 | #![cfg_attr (test, deny(warnings))] |
| 95 | #![cfg_attr (docsrs, feature(doc_auto_cfg))] |
| 96 | |
| 97 | #[cfg (not(feature = "any_impl" ,))] |
| 98 | compile_error!("You need to choose a zlib backend" ); |
| 99 | |
| 100 | pub use crate::crc::{Crc, CrcReader, CrcWriter}; |
| 101 | pub use crate::gz::GzBuilder; |
| 102 | pub use crate::gz::GzHeader; |
| 103 | pub use crate::mem::{Compress, CompressError, Decompress, DecompressError, Status}; |
| 104 | pub use crate::mem::{FlushCompress, FlushDecompress}; |
| 105 | |
| 106 | mod bufreader; |
| 107 | mod crc; |
| 108 | mod deflate; |
| 109 | mod ffi; |
| 110 | mod gz; |
| 111 | mod mem; |
| 112 | mod zio; |
| 113 | mod zlib; |
| 114 | |
| 115 | /// Types which operate over [`Read`] streams, both encoders and decoders for |
| 116 | /// various formats. |
| 117 | /// |
| 118 | /// Note that the `read` decoder types may read past the end of the compressed |
| 119 | /// data while decoding. If the caller requires subsequent reads to start |
| 120 | /// immediately following the compressed data wrap the `Read` type in a |
| 121 | /// [`BufReader`] and use the `BufReader` with the equivalent decoder from the |
| 122 | /// `bufread` module and also for the subsequent reads. |
| 123 | /// |
| 124 | /// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html |
| 125 | /// [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html |
| 126 | pub mod read { |
| 127 | pub use crate::deflate::read::DeflateDecoder; |
| 128 | pub use crate::deflate::read::DeflateEncoder; |
| 129 | pub use crate::gz::read::GzDecoder; |
| 130 | pub use crate::gz::read::GzEncoder; |
| 131 | pub use crate::gz::read::MultiGzDecoder; |
| 132 | pub use crate::zlib::read::ZlibDecoder; |
| 133 | pub use crate::zlib::read::ZlibEncoder; |
| 134 | } |
| 135 | |
| 136 | /// Types which operate over [`Write`] streams, both encoders and decoders for |
| 137 | /// various formats. |
| 138 | /// |
| 139 | /// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html |
| 140 | pub mod write { |
| 141 | pub use crate::deflate::write::DeflateDecoder; |
| 142 | pub use crate::deflate::write::DeflateEncoder; |
| 143 | pub use crate::gz::write::GzDecoder; |
| 144 | pub use crate::gz::write::GzEncoder; |
| 145 | pub use crate::gz::write::MultiGzDecoder; |
| 146 | pub use crate::zlib::write::ZlibDecoder; |
| 147 | pub use crate::zlib::write::ZlibEncoder; |
| 148 | } |
| 149 | |
| 150 | /// Types which operate over [`BufRead`] streams, both encoders and decoders for |
| 151 | /// various formats. |
| 152 | /// |
| 153 | /// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html |
| 154 | pub mod bufread { |
| 155 | pub use crate::deflate::bufread::DeflateDecoder; |
| 156 | pub use crate::deflate::bufread::DeflateEncoder; |
| 157 | pub use crate::gz::bufread::GzDecoder; |
| 158 | pub use crate::gz::bufread::GzEncoder; |
| 159 | pub use crate::gz::bufread::MultiGzDecoder; |
| 160 | pub use crate::zlib::bufread::ZlibDecoder; |
| 161 | pub use crate::zlib::bufread::ZlibEncoder; |
| 162 | } |
| 163 | |
| 164 | fn _assert_send_sync() { |
| 165 | fn _assert_send_sync<T: Send + Sync>() {} |
| 166 | |
| 167 | _assert_send_sync::<read::DeflateEncoder<&[u8]>>(); |
| 168 | _assert_send_sync::<read::DeflateDecoder<&[u8]>>(); |
| 169 | _assert_send_sync::<read::ZlibEncoder<&[u8]>>(); |
| 170 | _assert_send_sync::<read::ZlibDecoder<&[u8]>>(); |
| 171 | _assert_send_sync::<read::GzEncoder<&[u8]>>(); |
| 172 | _assert_send_sync::<read::GzDecoder<&[u8]>>(); |
| 173 | _assert_send_sync::<read::MultiGzDecoder<&[u8]>>(); |
| 174 | _assert_send_sync::<write::DeflateEncoder<Vec<u8>>>(); |
| 175 | _assert_send_sync::<write::DeflateDecoder<Vec<u8>>>(); |
| 176 | _assert_send_sync::<write::ZlibEncoder<Vec<u8>>>(); |
| 177 | _assert_send_sync::<write::ZlibDecoder<Vec<u8>>>(); |
| 178 | _assert_send_sync::<write::GzEncoder<Vec<u8>>>(); |
| 179 | _assert_send_sync::<write::GzDecoder<Vec<u8>>>(); |
| 180 | } |
| 181 | |
| 182 | /// When compressing data, the compression level can be specified by a value in |
| 183 | /// this struct. |
| 184 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
| 185 | pub struct Compression(u32); |
| 186 | |
| 187 | impl Compression { |
| 188 | /// Creates a new description of the compression level with an explicitly |
| 189 | /// specified integer. |
| 190 | /// |
| 191 | /// The integer here is typically on a scale of 0-9 where 0 means "no |
| 192 | /// compression" and 9 means "take as long as you'd like". |
| 193 | /// |
| 194 | /// ### Backend differences |
| 195 | /// |
| 196 | /// The [`miniz_oxide`](https://crates.io/crates/miniz_oxide) backend for flate2 |
| 197 | /// does not support level 0 or `Compression::none()`. Instead it interprets them |
| 198 | /// as the default compression level, which is quite slow. |
| 199 | /// `Compression::fast()` should be used instead. |
| 200 | /// |
| 201 | /// `miniz_oxide` also supports a non-compliant compression level 10. |
| 202 | /// It is even slower and may result in higher compression, but |
| 203 | /// **only miniz_oxide will be able to read the data** compressed with level 10. |
| 204 | /// Do **not** use level 10 if you need other software to be able to read it! |
| 205 | pub const fn new(level: u32) -> Compression { |
| 206 | Compression(level) |
| 207 | } |
| 208 | |
| 209 | /// No compression is to be performed, this may actually inflate data |
| 210 | /// slightly when encoding. |
| 211 | pub const fn none() -> Compression { |
| 212 | Compression(0) |
| 213 | } |
| 214 | |
| 215 | /// Optimize for the best speed of encoding. |
| 216 | pub const fn fast() -> Compression { |
| 217 | Compression(1) |
| 218 | } |
| 219 | |
| 220 | /// Optimize for the size of data being encoded. |
| 221 | pub const fn best() -> Compression { |
| 222 | Compression(9) |
| 223 | } |
| 224 | |
| 225 | /// Returns an integer representing the compression level, typically on a |
| 226 | /// scale of 0-9. See [`new`](Self::new) for details about compression levels. |
| 227 | pub fn level(&self) -> u32 { |
| 228 | self.0 |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | impl Default for Compression { |
| 233 | fn default() -> Compression { |
| 234 | Compression(6) |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | #[cfg (test)] |
| 239 | fn random_bytes() -> impl Iterator<Item = u8> { |
| 240 | use rand::Rng; |
| 241 | use std::iter; |
| 242 | |
| 243 | iter::repeat(()).map(|_| rand::rng().random()) |
| 244 | } |
| 245 | |