1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! # compress_lib
//!
//! DEFLATE (RFC 1951), zlib (RFC 1950), and gzip (RFC 1952) for Rust
//! services, with the per-message rules of WebSocket permessage-deflate
//! (RFC 7692).
//!
//! The engine is sans-IO: the caller pushes input and pulls output through
//! buffers it owns. Memory is fixed when an engine is built and never grows
//! with input, and every decoder enforces an absolute output cap while it
//! decodes, so a decompression bomb costs at most the cap. There is no
//! `unsafe` code and no third-party runtime dependency.
//!
//! ## Tier 1
//!
//! Add it with Cargo's rename, `compress = { package = "compress-lib", version
//! = "0.7" }`, and code reads `compress::`. One call each way; decoding is
//! capped at 64 MiB of output by default:
//!
//! ```
//! use compress_lib as compress;
//!
//! let packed = compress::gzip::compress(b"hello, hello, hello");
//! let body = compress::gzip::decompress(&packed)?;
//! assert_eq!(body, b"hello, hello, hello");
//!
//! let z = compress::zlib::compress(b"zlib, which HTTP calls deflate");
//! let raw = compress::deflate::compress_with(b"raw DEFLATE", compress::Level::FAST);
//! assert_eq!(compress::decompress(&z)?, b"zlib, which HTTP calls deflate"); // gzip or zlib, detected
//!
//! let small = compress::Limits::new().with_max_output(1 << 20);
//! assert_eq!(compress::deflate::decompress_with(&raw, small)?, b"raw DEFLATE");
//! # Ok::<(), compress_lib::Error>(())
//! ```
//!
//! ## WebSocket permessage-deflate
//!
//! [`message`] has the RFC 7692 rules: the sync-flush tail removed and put
//! back, context takeover on or off, window bits 8 to 15, and the output
//! budget checked while inflating.
//!
//! ```
//! use compress_lib::message::{Compressor, Decompressor, MessageConfig};
//!
//! let config = MessageConfig::new().with_window_bits(10);
//! let mut tx = Compressor::new(config)?;
//! let mut rx = Decompressor::new(config)?;
//! let mut wire = Vec::new();
//! tx.compress_message(b"{\"op\":\"ping\"}", &mut wire)?;
//! let mut text = Vec::new();
//! rx.decompress_message(&wire, &mut text, 1 << 20)?;
//! assert_eq!(text, b"{\"op\":\"ping\"}");
//! # Ok::<(), compress_lib::Error>(())
//! ```
//!
//! ## Streaming
//!
//! [`deflate::Inflater`] and [`deflate::Deflater`] take buffers you own and
//! say where they stopped ([`Status`]); memory is fixed when they are built,
//! and every decoder limit is checked before output is written.
//!
//! ```
//! use compress_lib::deflate::{Deflater, Flush, Inflater, Status};
//!
//! let mut deflater = Deflater::default();
//! let mut packed = [0u8; 256];
//! let p = deflater.compress(b"streamed", &mut packed, Flush::Finish)?;
//! assert_eq!(p.status, Status::Done);
//!
//! let mut inflater = Inflater::new().with_window_bits(12)?;
//! let mut out = [0u8; 64];
//! let q = inflater.finish(&packed[..p.produced], &mut out)?;
//! assert_eq!(&out[..q.produced], b"streamed");
//! # Ok::<(), compress_lib::Error>(())
//! ```
//!
//! [`Decoder`] and [`Encoder`] take a [`Format`] chosen at run time (an HTTP
//! layer picking by `Content-Encoding`); with the `std` feature, [`io`] wraps
//! any of them around `Read` and `Write`.
//!
//! Every failure is an [`Error`] with a matchable [`ErrorKind`] and a stable
//! code for logs and metrics. [`checksum`] has CRC-32 and Adler-32.
//!
//! ## Status
//!
//! `0.7.0`, hardened: an attack test per threat, a 4-hour soak, and
//! `docs/SECURITY.md` (the threat model, each defence with its cost) in the
//! [repository](https://github.com/jamesgober/compress-lib). Consumer runs
//! and the 1.0 audit follow; the complete planned API, each item with its
//! version, is `docs/API.md` there.
extern crate alloc;
/// Crate version string, populated by Cargo at build time.
pub const VERSION: &str = env!;
pub use ;
pub use ;
pub use Level;
pub use Limits;
pub use ;
/// Overwrites every element of `v` with the default value, spare capacity
/// included, keeping its length, and passes it through
/// [`core::hint::black_box`] so the writes are not removed as dead stores.
/// Without `unsafe` (volatile writes) this is a strong hint to the compiler,
/// not a guarantee; the documentation of every `wipe` says so.
pub