Skip to main content

async_zip/spec/
compression.rs

1// Copyright (c) 2021 Harry [Majored] [hello@majored.pw]
2// MIT License (https://github.com/Majored/rs-async-zip/blob/main/LICENSE)
3
4use crate::error::{Result, ZipError};
5
6#[cfg(any(
7    feature = "deflate-write",
8    feature = "bzip2-write",
9    feature = "zstd-write",
10    feature = "lzma-write",
11    feature = "xz-write"
12))]
13use async_compression::Level;
14
15/// A compression method supported by this crate.
16#[non_exhaustive]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum Compression {
19    Stored,
20    #[cfg(any(feature = "deflate-read", feature = "deflate-write"))]
21    Deflate,
22    #[cfg(feature = "deflate64-read")]
23    Deflate64,
24    #[cfg(any(feature = "bzip2-read", feature = "bzip2-write"))]
25    Bz,
26    #[cfg(any(feature = "lzma-read", feature = "lzma-write"))]
27    Lzma,
28    #[cfg(any(feature = "zstd-read", feature = "zstd-write"))]
29    Zstd,
30    #[cfg(any(feature = "xz-read", feature = "xz-write"))]
31    Xz,
32}
33
34/// A compression method enabled for writing.
35#[derive(Debug, Clone, Copy)]
36pub(crate) enum WriteCompression {
37    Stored,
38    #[cfg(feature = "deflate-write")]
39    Deflate,
40    #[cfg(feature = "bzip2-write")]
41    Bz,
42    #[cfg(feature = "lzma-write")]
43    Lzma,
44    #[cfg(feature = "zstd-write")]
45    Zstd,
46    #[cfg(feature = "xz-write")]
47    Xz,
48}
49
50impl TryFrom<Compression> for WriteCompression {
51    type Error = ZipError;
52
53    fn try_from(compression: Compression) -> Result<Self> {
54        match compression {
55            Compression::Stored => Ok(Self::Stored),
56            #[cfg(feature = "deflate-write")]
57            Compression::Deflate => Ok(Self::Deflate),
58            #[cfg(feature = "bzip2-write")]
59            Compression::Bz => Ok(Self::Bz),
60            #[cfg(feature = "lzma-write")]
61            Compression::Lzma => Ok(Self::Lzma),
62            #[cfg(feature = "zstd-write")]
63            Compression::Zstd => Ok(Self::Zstd),
64            #[cfg(feature = "xz-write")]
65            Compression::Xz => Ok(Self::Xz),
66            #[cfg(all(feature = "deflate-read", not(feature = "deflate-write")))]
67            Compression::Deflate => Err(ZipError::FeatureNotSupported("Deflate writing")),
68            #[cfg(all(feature = "bzip2-read", not(feature = "bzip2-write")))]
69            Compression::Bz => Err(ZipError::FeatureNotSupported("Bz writing")),
70            #[cfg(all(feature = "lzma-read", not(feature = "lzma-write")))]
71            Compression::Lzma => Err(ZipError::FeatureNotSupported("Lzma writing")),
72            #[cfg(all(feature = "zstd-read", not(feature = "zstd-write")))]
73            Compression::Zstd => Err(ZipError::FeatureNotSupported("Zstd writing")),
74            #[cfg(all(feature = "xz-read", not(feature = "xz-write")))]
75            Compression::Xz => Err(ZipError::FeatureNotSupported("Xz writing")),
76            #[cfg(feature = "deflate64-read")]
77            Compression::Deflate64 => Err(ZipError::FeatureNotSupported("Deflate64 writing")),
78        }
79    }
80}
81
82impl TryFrom<u16> for Compression {
83    type Error = ZipError;
84
85    // Convert a u16 stored with little endianness into a supported compression method.
86    // https://github.com/Majored/rs-async-zip/blob/main/SPECIFICATION.md#445
87    fn try_from(value: u16) -> Result<Self> {
88        match value {
89            0 => Ok(Compression::Stored),
90            #[cfg(any(feature = "deflate-read", feature = "deflate-write"))]
91            8 => Ok(Compression::Deflate),
92            #[cfg(feature = "deflate64-read")]
93            9 => Ok(Compression::Deflate64),
94            #[cfg(any(feature = "bzip2-read", feature = "bzip2-write"))]
95            12 => Ok(Compression::Bz),
96            #[cfg(any(feature = "lzma-read", feature = "lzma-write"))]
97            14 => Ok(Compression::Lzma),
98            #[cfg(any(feature = "zstd-read", feature = "zstd-write"))]
99            93 => Ok(Compression::Zstd),
100            #[cfg(any(feature = "xz-read", feature = "xz-write"))]
101            95 => Ok(Compression::Xz),
102            _ => Err(ZipError::CompressionNotSupported(value)),
103        }
104    }
105}
106
107impl From<&Compression> for u16 {
108    // Convert a supported compression method into its relevant u16 stored with little endianness.
109    // https://github.com/Majored/rs-async-zip/blob/main/SPECIFICATION.md#445
110    fn from(compression: &Compression) -> u16 {
111        match compression {
112            Compression::Stored => 0,
113            #[cfg(any(feature = "deflate-read", feature = "deflate-write"))]
114            Compression::Deflate => 8,
115            #[cfg(feature = "deflate64-read")]
116            Compression::Deflate64 => 9,
117            #[cfg(any(feature = "bzip2-read", feature = "bzip2-write"))]
118            Compression::Bz => 12,
119            #[cfg(any(feature = "lzma-read", feature = "lzma-write"))]
120            Compression::Lzma => 14,
121            #[cfg(any(feature = "zstd-read", feature = "zstd-write"))]
122            Compression::Zstd => 93,
123            #[cfg(any(feature = "xz-read", feature = "xz-write"))]
124            Compression::Xz => 95,
125        }
126    }
127}
128
129impl From<Compression> for u16 {
130    fn from(compression: Compression) -> u16 {
131        (&compression).into()
132    }
133}
134
135/// Level of compression data should be compressed with for deflate.
136#[derive(Debug, Clone, Copy)]
137pub enum DeflateOption {
138    // Normal (-en) compression option was used.
139    Normal,
140
141    // Maximum (-exx/-ex) compression option was used.
142    Maximum,
143
144    // Fast (-ef) compression option was used.
145    Fast,
146
147    // Super Fast (-es) compression option was used.
148    Super,
149
150    /// Other implementation defined level.
151    Other(i32),
152}
153
154#[cfg(any(
155    feature = "deflate-write",
156    feature = "bzip2-write",
157    feature = "zstd-write",
158    feature = "lzma-write",
159    feature = "xz-write"
160))]
161impl DeflateOption {
162    pub(crate) fn into_level(self) -> Level {
163        // FIXME: There's no clear documentation on what these specific levels defined in the ZIP specification relate
164        // to. We want to be compatible with any other library, and not specific to `async_compression`'s levels.
165        if let Self::Other(l) = self {
166            Level::Precise(l)
167        } else {
168            Level::Default
169        }
170    }
171}