Skip to main content

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}