1#[cfg(feature = "tar")]
2use std::fs::File;
3#[cfg(feature = "zstd")]
4use std::io::BufReader;
5use std::path::Path;
6
7use path_utils::PathExt;
8
9#[cfg(feature = "bzip2")]
10use bzip2::read::BzDecoder as BzSysDecoder;
11#[cfg(feature = "bzip2-rs")]
12use bzip2_rs::decoder::DecoderReader as BzNativeDecoder;
13#[cfg(feature = "flate2")]
14use flate2::read::GzDecoder;
15#[cfg(feature = "lz4")]
16use lz4::Decoder as Lz4Decoder;
17#[cfg(feature = "tar")]
18use tar::Archive as Tar;
19#[cfg(feature = "xz2")]
20use xz2::read::XzDecoder;
21#[cfg(feature = "zstd")]
22use zstd::stream::read::Decoder as ZstdDecoder;
23
24use crate::Result;
25
26#[non_exhaustive]
29#[allow(clippy::large_enum_variant)]
32pub enum Archive {
33 #[cfg(feature = "tar")]
34 #[doc(hidden)]
35 Tar(Tar<File>),
36
37 #[cfg(all(feature = "bzip2", feature = "tar"))]
38 #[doc(hidden)]
39 TarBzip2(Tar<BzSysDecoder<File>>),
40
41 #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
42 #[doc(hidden)]
43 TarBzip2Rs(Tar<BzNativeDecoder<File>>),
44
45 #[cfg(all(feature = "flate2", feature = "tar"))]
46 #[doc(hidden)]
47 TarGzip(Tar<GzDecoder<File>>),
48
49 #[cfg(all(feature = "lz4", feature = "tar"))]
50 #[doc(hidden)]
51 TarLz4(Tar<Lz4Decoder<File>>),
52
53 #[cfg(all(feature = "xz2", feature = "tar"))]
54 #[doc(hidden)]
55 TarXz(Tar<XzDecoder<File>>),
56
57 #[cfg(all(feature = "zstd", feature = "tar"))]
58 #[doc(hidden)]
59 TarZstd(Tar<ZstdDecoder<'static, BufReader<File>>>),
60}
61
62impl Archive {
63 pub fn open(path: impl AsRef<Path>) -> Result<Self> {
70 let path = path.as_ref();
71
72 let extensions: Vec<String> = path.extensions_lossy().collect();
73 let extensions: Vec<&str> =
74 extensions.iter().map(String::as_str).collect();
75
76 match extensions.as_slice() {
77 #[cfg(all(feature = "bzip2", feature = "tar"))]
78 ["tbz" | "tbz2", ..] | ["bz2", "tar", ..] => {
79 let file = File::open(path)?;
80 let file = BzSysDecoder::new(file);
81 Ok(Self::TarBzip2(Tar::new(file)))
82 }
83
84 #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
85 ["tbz" | "tbz2", ..] | ["bz2", "tar", ..] => {
86 let file = File::open(path)?;
87 let file = BzNativeDecoder::new(file);
88 Ok(Self::TarBzip2Rs(Tar::new(file)))
89 }
90
91 #[cfg(all(feature = "flate2", feature = "tar"))]
92 ["tgz", ..] | ["gz", "tar", ..] => {
93 let file = File::open(path)?;
94 let file = GzDecoder::new(file);
95 Ok(Self::TarGzip(Tar::new(file)))
96 }
97
98 #[cfg(all(feature = "lz4", feature = "tar"))]
99 ["lz4", "tar", ..] => {
100 let file = File::open(path)?;
101 let file = Lz4Decoder::new(file)?;
102 Ok(Self::TarLz4(Tar::new(file)))
103 }
104
105 #[cfg(all(feature = "xz2", feature = "tar"))]
106 ["txz", ..] | ["xz", "tar", ..] => {
107 let file = File::open(path)?;
108 let file = XzDecoder::new(file);
109 Ok(Self::TarXz(Tar::new(file)))
110 }
111
112 #[cfg(all(feature = "zstd", feature = "tar"))]
113 ["zst", "tar", ..] => {
114 let file = File::open(path)?;
115 let file = ZstdDecoder::new(file)?;
116 Ok(Self::TarZstd(Tar::new(file)))
117 }
118
119 #[cfg(feature = "tar")]
120 ["tar", ..] => {
121 let file = File::open(path)?;
122 Ok(Self::Tar(Tar::new(file)))
123 }
124
125 _ => Err(crate::Error::UnsupportedArchiveType(path.to_path_buf())),
126 }
127 }
128}