Skip to main content

rapidgzip_core/
format.rs

1//! Container selection and prefix detection.
2
3use crate::zlib;
4use std::fmt::{self, Display, Formatter};
5
6/// Container framing around a DEFLATE stream.
7///
8/// Gzip includes ordinary single-member files, concatenated multi-member
9/// archives, and BGZF. Raw DEFLATE has no recognizable header and therefore
10/// must always be selected explicitly.
11#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
12#[non_exhaustive]
13pub enum Format {
14    /// RFC 1952 gzip framing.
15    #[default]
16    Gzip,
17    /// RFC 1950 zlib framing.
18    Zlib,
19    /// An unwrapped RFC 1951 DEFLATE stream.
20    RawDeflate,
21}
22
23impl Display for Format {
24    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
25        formatter.write_str(match self {
26            Self::Gzip => "gzip",
27            Self::Zlib => "zlib",
28            Self::RawDeflate => "raw DEFLATE",
29        })
30    }
31}
32
33#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub(crate) enum FormatSelection {
35    Explicit(Format),
36    Auto,
37}
38
39impl Default for FormatSelection {
40    fn default() -> Self {
41        Self::Explicit(Format::Gzip)
42    }
43}
44
45pub(crate) fn detect(prefix: [u8; 2]) -> Option<Format> {
46    if prefix == [0x1f, 0x8b] {
47        Some(Format::Gzip)
48    } else if zlib::is_header(prefix[0], prefix[1]) {
49        Some(Format::Zlib)
50    } else {
51        None
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn detects_only_framed_formats() {
61        assert_eq!(detect([0x1f, 0x8b]), Some(Format::Gzip));
62        assert_eq!(detect([0x78, 0x01]), Some(Format::Zlib));
63        assert_eq!(detect([0x78, 0x9c]), Some(Format::Zlib));
64        assert_eq!(detect([0x78, 0xda]), Some(Format::Zlib));
65        assert_eq!(detect([0x78, 0x9d]), None);
66        assert_eq!(detect([0x03, 0x00]), None);
67    }
68}