zar/
compression.rs

1use std::io::Error;
2use std::io::Read;
3use std::io::Write;
4
5use bzip2::read::BzDecoder;
6use deko::write::AnyEncoder;
7use deko::write::Compression as DekoCompression;
8use deko::Format;
9use flate2::read::ZlibDecoder;
10use xz::read::XzDecoder;
11
12/// Compression codec that is used to compress files and table of contents.
13#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
14pub enum Compression {
15    /// No compression.
16    ///
17    /// Write the contents verbatim.
18    None,
19    /// GZIP compression.
20    #[default]
21    Gzip,
22    /// BZIP2 compression.
23    Bzip2,
24    /// XZ compression.
25    Xz,
26}
27
28impl Compression {
29    /// Get codec name as written in table of contents.
30    pub fn as_str(self) -> &'static str {
31        match self {
32            Self::None => OCTET_STREAM_MIME_TYPE,
33            Self::Gzip => GZIP_MIME_TYPE,
34            Self::Bzip2 => BZIP2_MIME_TYPE,
35            Self::Xz => XZ_MIME_TYPE,
36        }
37    }
38
39    /// Create new encoder for this compression codec.
40    pub fn encoder<W: Write>(self, writer: W) -> Result<AnyEncoder<W>, Error> {
41        match self {
42            Self::None => AnyEncoder::new(writer, Format::Verbatim, DekoCompression::Best),
43            Self::Gzip => AnyEncoder::new(writer, Format::Zlib, DekoCompression::Best),
44            Self::Bzip2 => AnyEncoder::new(writer, Format::Bz, DekoCompression::Best),
45            Self::Xz => AnyEncoder::new(writer, Format::Xz, DekoCompression::Best),
46        }
47    }
48
49    /// Create new decoder for this compression codec.
50    pub fn decoder<R: Read>(self, reader: R) -> XarDecoder<R> {
51        match self {
52            Self::None => XarDecoder::OctetStream(reader),
53            Self::Gzip => XarDecoder::Gzip(ZlibDecoder::new(reader)),
54            Self::Bzip2 => XarDecoder::Bzip2(BzDecoder::new(reader)),
55            Self::Xz => XarDecoder::Xz(XzDecoder::new(reader)),
56        }
57    }
58}
59
60impl From<&str> for Compression {
61    fn from(s: &str) -> Self {
62        match s {
63            GZIP_MIME_TYPE | ZLIB_MIME_TYPE => Self::Gzip,
64            BZIP2_MIME_TYPE => Self::Bzip2,
65            XZ_MIME_TYPE => Self::Xz,
66            _ => Self::None,
67        }
68    }
69}
70
71/// Decoder for [`Compression`] codec.
72pub enum XarDecoder<R: Read> {
73    /// No compression.
74    OctetStream(R),
75    /// GZIP compression.
76    Gzip(ZlibDecoder<R>),
77    /// BZIP2 compression.
78    Bzip2(BzDecoder<R>),
79    /// XZ compression.
80    Xz(XzDecoder<R>),
81}
82
83impl<R: Read> Read for XarDecoder<R> {
84    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
85        match self {
86            Self::OctetStream(r) => r.read(buf),
87            Self::Gzip(r) => r.read(buf),
88            Self::Bzip2(r) => r.read(buf),
89            Self::Xz(r) => r.read(buf),
90        }
91    }
92
93    // TODO other methods
94}
95
96const OCTET_STREAM_MIME_TYPE: &str = "application/octet-stream";
97const GZIP_MIME_TYPE: &str = "application/x-gzip";
98const BZIP2_MIME_TYPE: &str = "application/x-bzip2";
99const ZLIB_MIME_TYPE: &str = "application/zlib";
100const XZ_MIME_TYPE: &str = "application/x-xz";