compress_lib/format.rs
1//! One decoder and one encoder type for code that picks the format at run
2//! time (an HTTP layer choosing by `Content-Encoding`, for example).
3
4use alloc::vec::Vec;
5
6use crate::{
7 Error, ErrorKind, Level, Limits, Progress,
8 deflate::{Deflater, Flush, Inflater},
9 gzip, zlib,
10};
11
12/// A compressed format.
13///
14/// # Examples
15///
16/// ```
17/// use compress_lib::{Format, gzip, zlib};
18///
19/// assert_eq!(Format::detect(&gzip::compress(b"x")), Some(Format::Gzip));
20/// assert_eq!(Format::detect(&zlib::compress(b"x")), Some(Format::Zlib));
21/// assert_eq!(Format::detect(b"plain text"), None);
22/// ```
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
24#[non_exhaustive]
25pub enum Format {
26 /// Raw DEFLATE (RFC 1951): no header, no checksum.
27 Raw,
28 /// zlib (RFC 1950); also HTTP's `deflate` content coding.
29 Zlib,
30 /// gzip (RFC 1952); HTTP's `gzip` content coding.
31 Gzip,
32}
33
34impl Format {
35 /// Recognises gzip by its magic number and zlib by its header check.
36 /// Raw DEFLATE has no header and is never guessed. Needs at least two
37 /// bytes.
38 ///
39 /// # Examples
40 ///
41 /// ```
42 /// use compress_lib::Format;
43 ///
44 /// assert_eq!(Format::detect(&[0x1F, 0x8B]), Some(Format::Gzip));
45 /// assert_eq!(Format::detect(&[0x78, 0x9C]), Some(Format::Zlib));
46 /// assert_eq!(Format::detect(&[0x78]), None);
47 /// ```
48 #[must_use]
49 pub fn detect(data: &[u8]) -> Option<Format> {
50 match data {
51 [0x1F, 0x8B, ..] => Some(Format::Gzip),
52 [cmf, flg, ..] if zlib::header_ok(*cmf, *flg) => Some(Format::Zlib),
53 _ => None,
54 }
55 }
56}
57
58/// Decompresses a complete gzip or zlib stream, detected from its first
59/// bytes, with the default [`Limits`].
60///
61/// # Errors
62///
63/// [`ErrorKind::InvalidHeader`] when the data is neither; otherwise as
64/// [`gzip::decompress`] or [`zlib::decompress`].
65///
66/// # Examples
67///
68/// ```
69/// use compress_lib as compress;
70///
71/// assert_eq!(compress::decompress(&compress::gzip::compress(b"either"))?, b"either");
72/// assert_eq!(compress::decompress(&compress::zlib::compress(b"either"))?, b"either");
73/// # Ok::<(), compress_lib::Error>(())
74/// ```
75pub fn decompress(data: &[u8]) -> Result<Vec<u8>, Error> {
76 decompress_with(data, Limits::new())
77}
78
79/// As [`decompress`], with the given limits.
80///
81/// # Errors
82///
83/// As [`decompress`].
84///
85/// # Examples
86///
87/// ```
88/// use compress_lib as compress;
89///
90/// let limits = compress::Limits::new().with_max_output(1 << 20);
91/// assert_eq!(compress::decompress_with(&compress::gzip::compress(b"x"), limits)?, b"x");
92/// # Ok::<(), compress_lib::Error>(())
93/// ```
94pub fn decompress_with(data: &[u8], limits: Limits) -> Result<Vec<u8>, Error> {
95 match Format::detect(data) {
96 Some(Format::Gzip) => gzip::decompress_with(data, limits),
97 Some(Format::Zlib) => zlib::decompress_with(data, limits),
98 _ => Err(Error::new(ErrorKind::InvalidHeader, 0)),
99 }
100}
101
102#[derive(Debug)]
103enum Inner<R, Z, G> {
104 Raw(R),
105 Zlib(Z),
106 Gzip(G),
107}
108
109/// A streaming decoder for any [`Format`].
110///
111/// # Examples
112///
113/// ```
114/// use compress_lib::{Decoder, Format, gzip};
115///
116/// let mut dec = Decoder::new(Format::Gzip);
117/// let mut out = Vec::new();
118/// dec.finish_vec(&gzip::compress(b"any format"), &mut out)?;
119/// assert_eq!(out, b"any format");
120/// # Ok::<(), compress_lib::Error>(())
121/// ```
122#[derive(Debug)]
123pub struct Decoder(Inner<Inflater, zlib::Decoder, gzip::Decoder>);
124
125impl Decoder {
126 /// A decoder for `format` with the default limits.
127 ///
128 /// # Examples
129 ///
130 /// ```
131 /// let dec = compress_lib::Decoder::new(compress_lib::Format::Zlib);
132 /// assert_eq!(dec.format(), compress_lib::Format::Zlib);
133 /// ```
134 #[must_use]
135 pub fn new(format: Format) -> Self {
136 Self(match format {
137 Format::Raw => Inner::Raw(Inflater::new()),
138 Format::Zlib => Inner::Zlib(zlib::Decoder::new()),
139 Format::Gzip => Inner::Gzip(gzip::Decoder::new()),
140 })
141 }
142
143 /// Sets the limits checked while decoding.
144 ///
145 /// # Examples
146 ///
147 /// ```
148 /// use compress_lib::{Decoder, Format, Limits};
149 ///
150 /// let dec = Decoder::new(Format::Gzip).with_limits(Limits::new().with_max_output(1 << 20));
151 /// # let _ = dec;
152 /// ```
153 #[must_use]
154 pub fn with_limits(self, limits: Limits) -> Self {
155 Self(match self.0 {
156 Inner::Raw(d) => Inner::Raw(d.with_limits(limits)),
157 Inner::Zlib(d) => Inner::Zlib(d.with_limits(limits)),
158 Inner::Gzip(d) => Inner::Gzip(d.with_limits(limits)),
159 })
160 }
161
162 /// The format decoded.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use compress_lib::{Decoder, Format};
168 ///
169 /// assert_eq!(Decoder::new(Format::Raw).format(), Format::Raw);
170 /// ```
171 #[must_use]
172 pub fn format(&self) -> Format {
173 match self.0 {
174 Inner::Raw(_) => Format::Raw,
175 Inner::Zlib(_) => Format::Zlib,
176 Inner::Gzip(_) => Format::Gzip,
177 }
178 }
179
180 /// As [`Inflater::decompress`].
181 ///
182 /// # Errors
183 ///
184 /// The errors of the format's decoder.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// use compress_lib::{Decoder, Format, deflate::Status, zlib};
190 ///
191 /// let mut out = [0u8; 16];
192 /// let p = Decoder::new(Format::Zlib).decompress(&zlib::compress(b"abc"), &mut out)?;
193 /// assert_eq!(p.status, Status::Done);
194 /// # Ok::<(), compress_lib::Error>(())
195 /// ```
196 pub fn decompress(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
197 match &mut self.0 {
198 Inner::Raw(d) => d.decompress(input, output),
199 Inner::Zlib(d) => d.decompress(input, output),
200 Inner::Gzip(d) => d.decompress(input, output),
201 }
202 }
203
204 /// As [`Inflater::finish`].
205 ///
206 /// # Errors
207 ///
208 /// The errors of the format's decoder, plus `UnexpectedEnd`.
209 ///
210 /// # Examples
211 ///
212 /// ```
213 /// use compress_lib::{Decoder, Format, gzip};
214 ///
215 /// let mut out = [0u8; 16];
216 /// let p = Decoder::new(Format::Gzip).finish(&gzip::compress(b"abc"), &mut out)?;
217 /// assert_eq!(&out[..p.produced], b"abc");
218 /// # Ok::<(), compress_lib::Error>(())
219 /// ```
220 pub fn finish(&mut self, input: &[u8], output: &mut [u8]) -> Result<Progress, Error> {
221 match &mut self.0 {
222 Inner::Raw(d) => d.finish(input, output),
223 Inner::Zlib(d) => d.finish(input, output),
224 Inner::Gzip(d) => d.finish(input, output),
225 }
226 }
227
228 /// As [`Inflater::decompress_vec`].
229 ///
230 /// # Errors
231 ///
232 /// The errors of the format's decoder, plus `AllocationFailed`.
233 ///
234 /// # Examples
235 ///
236 /// ```
237 /// use compress_lib::{Decoder, Format, deflate};
238 ///
239 /// let mut out = Vec::new();
240 /// Decoder::new(Format::Raw).decompress_vec(&deflate::compress(b"raw"), &mut out)?;
241 /// assert_eq!(out, b"raw");
242 /// # Ok::<(), compress_lib::Error>(())
243 /// ```
244 pub fn decompress_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
245 match &mut self.0 {
246 Inner::Raw(d) => d.decompress_vec(input, out),
247 Inner::Zlib(d) => d.decompress_vec(input, out),
248 Inner::Gzip(d) => d.decompress_vec(input, out),
249 }
250 }
251
252 /// As [`Inflater::finish_vec`].
253 ///
254 /// # Errors
255 ///
256 /// The errors of the format's decoder, plus `UnexpectedEnd` and
257 /// `AllocationFailed`.
258 ///
259 /// # Examples
260 ///
261 /// ```
262 /// use compress_lib::{Decoder, Format, zlib};
263 ///
264 /// let mut out = Vec::new();
265 /// Decoder::new(Format::Zlib).finish_vec(&zlib::compress(b"z"), &mut out)?;
266 /// assert_eq!(out, b"z");
267 /// # Ok::<(), compress_lib::Error>(())
268 /// ```
269 pub fn finish_vec(&mut self, input: &[u8], out: &mut Vec<u8>) -> Result<Progress, Error> {
270 match &mut self.0 {
271 Inner::Raw(d) => d.finish_vec(input, out),
272 Inner::Zlib(d) => d.finish_vec(input, out),
273 Inner::Gzip(d) => d.finish_vec(input, out),
274 }
275 }
276
277 /// `true` once the stream ended.
278 ///
279 /// # Examples
280 ///
281 /// ```
282 /// assert!(!compress_lib::Decoder::new(compress_lib::Format::Gzip).is_done());
283 /// ```
284 #[must_use]
285 pub fn is_done(&self) -> bool {
286 match &self.0 {
287 Inner::Raw(d) => d.is_done(),
288 Inner::Zlib(d) => d.is_done(),
289 Inner::Gzip(d) => d.is_done(),
290 }
291 }
292
293 /// Compressed bytes consumed.
294 ///
295 /// # Examples
296 ///
297 /// ```
298 /// assert_eq!(compress_lib::Decoder::new(compress_lib::Format::Gzip).total_in(), 0);
299 /// ```
300 #[must_use]
301 pub fn total_in(&self) -> u64 {
302 match &self.0 {
303 Inner::Raw(d) => d.total_in(),
304 Inner::Zlib(d) => d.total_in(),
305 Inner::Gzip(d) => d.total_in(),
306 }
307 }
308
309 /// Decompressed bytes produced.
310 ///
311 /// # Examples
312 ///
313 /// ```
314 /// assert_eq!(compress_lib::Decoder::new(compress_lib::Format::Gzip).total_out(), 0);
315 /// ```
316 #[must_use]
317 pub fn total_out(&self) -> u64 {
318 match &self.0 {
319 Inner::Raw(d) => d.total_out(),
320 Inner::Zlib(d) => d.total_out(),
321 Inner::Gzip(d) => d.total_out(),
322 }
323 }
324
325 /// Starts over for a new stream, keeping allocations.
326 ///
327 /// # Examples
328 ///
329 /// ```
330 /// let mut dec = compress_lib::Decoder::new(compress_lib::Format::Zlib);
331 /// dec.reset();
332 /// ```
333 pub fn reset(&mut self) {
334 match &mut self.0 {
335 Inner::Raw(d) => d.reset(),
336 Inner::Zlib(d) => d.reset(),
337 Inner::Gzip(d) => d.reset(),
338 }
339 }
340}
341
342/// A streaming encoder for any [`Format`].
343///
344/// # Examples
345///
346/// ```
347/// use compress_lib::{Encoder, Format, Level, deflate::Flush, gzip};
348///
349/// let mut enc = Encoder::new(Format::Gzip, Level::DEFAULT);
350/// let mut out = Vec::new();
351/// enc.compress_vec(b"response body", &mut out, Flush::Finish)?;
352/// assert_eq!(gzip::decompress(&out)?, b"response body");
353/// # Ok::<(), compress_lib::Error>(())
354/// ```
355#[derive(Debug)]
356pub struct Encoder(Inner<Deflater, zlib::Encoder, gzip::Encoder>);
357
358impl Encoder {
359 /// An encoder for `format` at `level`.
360 ///
361 /// # Examples
362 ///
363 /// ```
364 /// use compress_lib::{Encoder, Format, Level};
365 ///
366 /// assert_eq!(Encoder::new(Format::Zlib, Level::FAST).format(), Format::Zlib);
367 /// ```
368 #[must_use]
369 pub fn new(format: Format, level: Level) -> Self {
370 Self(match format {
371 Format::Raw => Inner::Raw(Deflater::new(level)),
372 Format::Zlib => Inner::Zlib(zlib::Encoder::new(level)),
373 Format::Gzip => Inner::Gzip(gzip::Encoder::new(level)),
374 })
375 }
376
377 /// The format written.
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// use compress_lib::{Encoder, Format, Level};
383 ///
384 /// assert_eq!(Encoder::new(Format::Raw, Level::FAST).format(), Format::Raw);
385 /// ```
386 #[must_use]
387 pub fn format(&self) -> Format {
388 match self.0 {
389 Inner::Raw(_) => Format::Raw,
390 Inner::Zlib(_) => Format::Zlib,
391 Inner::Gzip(_) => Format::Gzip,
392 }
393 }
394
395 /// As [`Deflater::compress`], with the format's header and trailer.
396 ///
397 /// # Errors
398 ///
399 /// As `Deflater::compress`.
400 ///
401 /// # Examples
402 ///
403 /// ```
404 /// use compress_lib::{Encoder, Format, Level, deflate::{Flush, Status}};
405 ///
406 /// let mut enc = Encoder::new(Format::Zlib, Level::DEFAULT);
407 /// let mut out = [0u8; 64];
408 /// assert_eq!(enc.compress(b"abc", &mut out, Flush::Finish)?.status, Status::Done);
409 /// # Ok::<(), compress_lib::Error>(())
410 /// ```
411 pub fn compress(
412 &mut self,
413 input: &[u8],
414 output: &mut [u8],
415 flush: Flush,
416 ) -> Result<Progress, Error> {
417 match &mut self.0 {
418 Inner::Raw(e) => e.compress(input, output, flush),
419 Inner::Zlib(e) => e.compress(input, output, flush),
420 Inner::Gzip(e) => e.compress(input, output, flush),
421 }
422 }
423
424 /// As [`Deflater::compress_vec`].
425 ///
426 /// # Errors
427 ///
428 /// As `compress`, plus `AllocationFailed`.
429 ///
430 /// # Examples
431 ///
432 /// ```
433 /// use compress_lib::{Encoder, Format, Level, deflate::Flush, zlib};
434 ///
435 /// let mut out = Vec::new();
436 /// Encoder::new(Format::Zlib, Level::DEFAULT).compress_vec(b"abc", &mut out, Flush::Finish)?;
437 /// assert_eq!(zlib::decompress(&out)?, b"abc");
438 /// # Ok::<(), compress_lib::Error>(())
439 /// ```
440 pub fn compress_vec(
441 &mut self,
442 input: &[u8],
443 out: &mut Vec<u8>,
444 flush: Flush,
445 ) -> Result<Progress, Error> {
446 match &mut self.0 {
447 Inner::Raw(e) => e.compress_vec(input, out, flush),
448 Inner::Zlib(e) => e.compress_vec(input, out, flush),
449 Inner::Gzip(e) => e.compress_vec(input, out, flush),
450 }
451 }
452
453 /// Starts a new stream, keeping allocations.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// let mut enc = compress_lib::Encoder::new(compress_lib::Format::Gzip, compress_lib::Level::FAST);
459 /// enc.reset();
460 /// ```
461 pub fn reset(&mut self) {
462 match &mut self.0 {
463 Inner::Raw(e) => e.reset(),
464 Inner::Zlib(e) => e.reset(),
465 Inner::Gzip(e) => e.reset(),
466 }
467 }
468}