zip/
compression.rs
1use std::{fmt, io};
4
5#[allow(deprecated)]
6#[derive(Copy, Clone, PartialEq, Eq, Debug)]
14#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
15#[non_exhaustive]
16pub enum CompressionMethod {
17 Stored,
19 #[cfg(feature = "_deflate-any")]
21 Deflated,
22 #[cfg(feature = "deflate64")]
25 Deflate64,
26 #[cfg(feature = "bzip2")]
28 Bzip2,
29 #[cfg(feature = "aes-crypto")]
34 Aes,
35 #[cfg(feature = "zstd")]
37 Zstd,
38 #[cfg(feature = "lzma")]
40 Lzma,
41 #[cfg(feature = "xz")]
43 Xz,
44 #[cfg_attr(
46 not(fuzzing),
47 deprecated(since = "0.5.7", note = "use the constants instead")
48 )]
49 Unsupported(u16),
50}
51#[allow(deprecated, missing_docs)]
52impl CompressionMethod {
54 pub const STORE: Self = CompressionMethod::Stored;
55 pub const SHRINK: Self = CompressionMethod::Unsupported(1);
56 pub const REDUCE_1: Self = CompressionMethod::Unsupported(2);
57 pub const REDUCE_2: Self = CompressionMethod::Unsupported(3);
58 pub const REDUCE_3: Self = CompressionMethod::Unsupported(4);
59 pub const REDUCE_4: Self = CompressionMethod::Unsupported(5);
60 pub const IMPLODE: Self = CompressionMethod::Unsupported(6);
61 #[cfg(feature = "_deflate-any")]
62 pub const DEFLATE: Self = CompressionMethod::Deflated;
63 #[cfg(not(feature = "_deflate-any"))]
64 pub const DEFLATE: Self = CompressionMethod::Unsupported(8);
65 #[cfg(feature = "deflate64")]
66 pub const DEFLATE64: Self = CompressionMethod::Deflate64;
67 #[cfg(not(feature = "deflate64"))]
68 pub const DEFLATE64: Self = CompressionMethod::Unsupported(9);
69 pub const PKWARE_IMPLODE: Self = CompressionMethod::Unsupported(10);
70 #[cfg(feature = "bzip2")]
71 pub const BZIP2: Self = CompressionMethod::Bzip2;
72 #[cfg(not(feature = "bzip2"))]
73 pub const BZIP2: Self = CompressionMethod::Unsupported(12);
74 #[cfg(not(feature = "lzma"))]
75 pub const LZMA: Self = CompressionMethod::Unsupported(14);
76 #[cfg(feature = "lzma")]
77 pub const LZMA: Self = CompressionMethod::Lzma;
78 pub const IBM_ZOS_CMPSC: Self = CompressionMethod::Unsupported(16);
79 pub const IBM_TERSE: Self = CompressionMethod::Unsupported(18);
80 pub const ZSTD_DEPRECATED: Self = CompressionMethod::Unsupported(20);
81 #[cfg(feature = "zstd")]
82 pub const ZSTD: Self = CompressionMethod::Zstd;
83 #[cfg(not(feature = "zstd"))]
84 pub const ZSTD: Self = CompressionMethod::Unsupported(93);
85 pub const MP3: Self = CompressionMethod::Unsupported(94);
86 #[cfg(feature = "xz")]
87 pub const XZ: Self = CompressionMethod::Xz;
88 #[cfg(not(feature = "xz"))]
89 pub const XZ: Self = CompressionMethod::Unsupported(95);
90 pub const JPEG: Self = CompressionMethod::Unsupported(96);
91 pub const WAVPACK: Self = CompressionMethod::Unsupported(97);
92 pub const PPMD: Self = CompressionMethod::Unsupported(98);
93 #[cfg(feature = "aes-crypto")]
94 pub const AES: Self = CompressionMethod::Aes;
95 #[cfg(not(feature = "aes-crypto"))]
96 pub const AES: Self = CompressionMethod::Unsupported(99);
97}
98impl CompressionMethod {
99 pub(crate) const fn parse_from_u16(val: u16) -> Self {
100 match val {
101 0 => CompressionMethod::Stored,
102 #[cfg(feature = "_deflate-any")]
103 8 => CompressionMethod::Deflated,
104 #[cfg(feature = "deflate64")]
105 9 => CompressionMethod::Deflate64,
106 #[cfg(feature = "bzip2")]
107 12 => CompressionMethod::Bzip2,
108 #[cfg(feature = "lzma")]
109 14 => CompressionMethod::Lzma,
110 #[cfg(feature = "xz")]
111 95 => CompressionMethod::Xz,
112 #[cfg(feature = "zstd")]
113 93 => CompressionMethod::Zstd,
114 #[cfg(feature = "aes-crypto")]
115 99 => CompressionMethod::Aes,
116 #[allow(deprecated)]
117 v => CompressionMethod::Unsupported(v),
118 }
119 }
120
121 #[deprecated(
123 since = "0.5.7",
124 note = "use a constant to construct a compression method"
125 )]
126 pub const fn from_u16(val: u16) -> CompressionMethod {
127 Self::parse_from_u16(val)
128 }
129
130 pub(crate) const fn serialize_to_u16(self) -> u16 {
131 match self {
132 CompressionMethod::Stored => 0,
133 #[cfg(feature = "_deflate-any")]
134 CompressionMethod::Deflated => 8,
135 #[cfg(feature = "deflate64")]
136 CompressionMethod::Deflate64 => 9,
137 #[cfg(feature = "bzip2")]
138 CompressionMethod::Bzip2 => 12,
139 #[cfg(feature = "aes-crypto")]
140 CompressionMethod::Aes => 99,
141 #[cfg(feature = "zstd")]
142 CompressionMethod::Zstd => 93,
143 #[cfg(feature = "lzma")]
144 CompressionMethod::Lzma => 14,
145 #[cfg(feature = "xz")]
146 CompressionMethod::Xz => 95,
147 #[allow(deprecated)]
148 CompressionMethod::Unsupported(v) => v,
149 }
150 }
151
152 #[deprecated(
154 since = "0.5.7",
155 note = "to match on other compression methods, use a constant"
156 )]
157 pub const fn to_u16(self) -> u16 {
158 self.serialize_to_u16()
159 }
160}
161
162impl Default for CompressionMethod {
163 fn default() -> Self {
164 #[cfg(feature = "_deflate-any")]
165 return CompressionMethod::Deflated;
166
167 #[cfg(not(feature = "_deflate-any"))]
168 return CompressionMethod::Stored;
169 }
170}
171
172impl fmt::Display for CompressionMethod {
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 write!(f, "{self:?}")
176 }
177}
178
179pub const SUPPORTED_COMPRESSION_METHODS: &[CompressionMethod] = &[
181 CompressionMethod::Stored,
182 #[cfg(feature = "_deflate-any")]
183 CompressionMethod::Deflated,
184 #[cfg(feature = "deflate64")]
185 CompressionMethod::Deflate64,
186 #[cfg(feature = "bzip2")]
187 CompressionMethod::Bzip2,
188 #[cfg(feature = "zstd")]
189 CompressionMethod::Zstd,
190 #[cfg(feature = "xz")]
191 CompressionMethod::Xz,
192];
193
194pub(crate) enum Decompressor<R: io::BufRead> {
195 Stored(R),
196 #[cfg(feature = "_deflate-any")]
197 Deflated(flate2::bufread::DeflateDecoder<R>),
198 #[cfg(feature = "deflate64")]
199 Deflate64(deflate64::Deflate64Decoder<R>),
200 #[cfg(feature = "bzip2")]
201 Bzip2(bzip2::bufread::BzDecoder<R>),
202 #[cfg(feature = "zstd")]
203 Zstd(zstd::Decoder<'static, R>),
204 #[cfg(feature = "lzma")]
205 Lzma(Box<crate::read::lzma::LzmaDecoder<R>>),
206 #[cfg(feature = "xz")]
207 Xz(xz2::bufread::XzDecoder<R>),
208}
209
210impl<R: io::BufRead> io::Read for Decompressor<R> {
211 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
212 match self {
213 Decompressor::Stored(r) => r.read(buf),
214 #[cfg(feature = "_deflate-any")]
215 Decompressor::Deflated(r) => r.read(buf),
216 #[cfg(feature = "deflate64")]
217 Decompressor::Deflate64(r) => r.read(buf),
218 #[cfg(feature = "bzip2")]
219 Decompressor::Bzip2(r) => r.read(buf),
220 #[cfg(feature = "zstd")]
221 Decompressor::Zstd(r) => r.read(buf),
222 #[cfg(feature = "lzma")]
223 Decompressor::Lzma(r) => r.read(buf),
224 #[cfg(feature = "xz")]
225 Decompressor::Xz(r) => r.read(buf),
226 }
227 }
228}
229
230impl<R: io::BufRead> Decompressor<R> {
231 pub fn new(reader: R, compression_method: CompressionMethod) -> crate::result::ZipResult<Self> {
232 Ok(match compression_method {
233 CompressionMethod::Stored => Decompressor::Stored(reader),
234 #[cfg(feature = "_deflate-any")]
235 CompressionMethod::Deflated => {
236 Decompressor::Deflated(flate2::bufread::DeflateDecoder::new(reader))
237 }
238 #[cfg(feature = "deflate64")]
239 CompressionMethod::Deflate64 => {
240 Decompressor::Deflate64(deflate64::Deflate64Decoder::with_buffer(reader))
241 }
242 #[cfg(feature = "bzip2")]
243 CompressionMethod::Bzip2 => Decompressor::Bzip2(bzip2::bufread::BzDecoder::new(reader)),
244 #[cfg(feature = "zstd")]
245 CompressionMethod::Zstd => Decompressor::Zstd(zstd::Decoder::with_buffer(reader)?),
246 #[cfg(feature = "lzma")]
247 CompressionMethod::Lzma => {
248 Decompressor::Lzma(Box::new(crate::read::lzma::LzmaDecoder::new(reader)))
249 }
250 #[cfg(feature = "xz")]
251 CompressionMethod::Xz => Decompressor::Xz(xz2::bufread::XzDecoder::new(reader)),
252 _ => {
253 return Err(crate::result::ZipError::UnsupportedArchive(
254 "Compression method not supported",
255 ))
256 }
257 })
258 }
259
260 pub fn into_inner(self) -> R {
262 match self {
263 Decompressor::Stored(r) => r,
264 #[cfg(feature = "_deflate-any")]
265 Decompressor::Deflated(r) => r.into_inner(),
266 #[cfg(feature = "deflate64")]
267 Decompressor::Deflate64(r) => r.into_inner(),
268 #[cfg(feature = "bzip2")]
269 Decompressor::Bzip2(r) => r.into_inner(),
270 #[cfg(feature = "zstd")]
271 Decompressor::Zstd(r) => r.finish(),
272 #[cfg(feature = "lzma")]
273 Decompressor::Lzma(r) => r.into_inner(),
274 #[cfg(feature = "xz")]
275 Decompressor::Xz(r) => r.into_inner(),
276 }
277 }
278}
279
280#[cfg(test)]
281mod test {
282 use super::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS};
283
284 #[test]
285 fn from_eq_to() {
286 for v in 0..(u16::MAX as u32 + 1) {
287 let from = CompressionMethod::parse_from_u16(v as u16);
288 let to = from.serialize_to_u16() as u32;
289 assert_eq!(v, to);
290 }
291 }
292
293 #[test]
294 fn to_eq_from() {
295 fn check_match(method: CompressionMethod) {
296 let to = method.serialize_to_u16();
297 let from = CompressionMethod::parse_from_u16(to);
298 let back = from.serialize_to_u16();
299 assert_eq!(to, back);
300 }
301
302 for &method in SUPPORTED_COMPRESSION_METHODS {
303 check_match(method);
304 }
305 }
306
307 #[test]
308 fn to_display_fmt() {
309 fn check_match(method: CompressionMethod) {
310 let debug_str = format!("{method:?}");
311 let display_str = format!("{method}");
312 assert_eq!(debug_str, display_str);
313 }
314
315 for &method in SUPPORTED_COMPRESSION_METHODS {
316 check_match(method);
317 }
318 }
319}