1pub use strum::IntoEnumIterator;
2use strum_macros::EnumIter;
3
4use crate::archive::{
5 tar::{Tar, TarBz, TarGz, TarXz, TarZstd},
6 zip::Zip,
7};
8
9#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
10#[derive(EnumIter, Debug, Clone, Copy, PartialEq)]
11pub enum Fmt {
12 Tar,
13 TarGz,
14 TarXz,
15 TarBz,
16 TarZstd,
17 Zip,
18}
19
20impl Fmt {
21 pub fn decode(&self, buffer: Vec<u8>) -> Option<Vec<File>> {
22 match self {
23 Fmt::Zip => Zip::decode(buffer),
24 Fmt::Tar => Tar::decode(buffer),
25 Fmt::TarGz => TarGz::decode(buffer),
26 Fmt::TarXz => TarXz::decode(buffer),
27 Fmt::TarBz => TarBz::decode(buffer),
28 Fmt::TarZstd => TarZstd::decode(buffer),
29 }
30 }
31 pub fn encode(&self, files: Vec<File>) -> Option<Vec<u8>> {
32 match self {
33 Fmt::Zip => Zip::encode(files),
34 Fmt::Tar => Tar::encode(files),
35 Fmt::TarGz => TarGz::encode(files),
36 Fmt::TarXz => TarXz::encode(files),
37 Fmt::TarBz => TarBz::encode(files),
38 Fmt::TarZstd => TarZstd::encode(files),
39 }
40 }
41
42 pub fn guess(name: &str) -> Option<Self> {
43 for fmt in Fmt::iter() {
44 for ext in fmt.extensions() {
45 if name.ends_with(ext) {
46 return Some(fmt);
47 }
48 }
49 }
50 None
51 }
52
53 pub fn extensions(&self) -> &[&'static str] {
54 match self {
55 Fmt::Tar => &[".tar"],
56 Fmt::TarGz => &[".tar.gz", ".tgz"],
57 Fmt::TarXz => &[".tar.xz", ".txz"],
58 Fmt::TarBz => &[".tar.bz2", ".tbz2"],
59 Fmt::TarZstd => &[".tzstd", ".tzst", ".tar.zst"],
60 Fmt::Zip => &[".zip"],
61 }
62 }
63}
64
65#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
66#[derive(Debug, Clone, Default)]
67pub struct File {
68 #[cfg_attr(feature = "wasm", wasm_bindgen(skip))]
69 pub buffer: Vec<u8>,
70 #[cfg_attr(feature = "wasm", wasm_bindgen(skip))]
71 pub path: String,
72 pub mode: Option<u32>,
73 #[cfg_attr(feature = "wasm", wasm_bindgen(js_name = "isDir"))]
74 pub is_dir: bool,
75 #[cfg_attr(feature = "wasm", wasm_bindgen(js_name = "lastModified"))]
76 pub last_modified: Option<u64>,
77}
78
79#[cfg(feature = "wasm")]
80use wasm_bindgen::prelude::*;
81
82#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
83impl File {
84 #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))]
85 pub fn new(
86 path: String,
87 buffer: Vec<u8>,
88 mode: Option<u32>,
89 is_dir: bool,
90 last_modified: Option<u64>,
91 ) -> Self {
92 File {
93 path,
94 buffer,
95 mode,
96 is_dir,
97 last_modified,
98 }
99 }
100}
101
102#[cfg(feature = "wasm")]
103#[wasm_bindgen]
104impl File {
105 #[wasm_bindgen(getter = buffer)]
108 pub fn get_buffer(self) -> Vec<u8> {
109 self.buffer
110 }
111 #[wasm_bindgen(setter = buffer)]
112 pub fn set_buffer(&mut self, buffer: Vec<u8>) {
113 self.buffer = buffer;
114 }
115
116 #[wasm_bindgen(getter = path)]
117 pub fn get_path(&self) -> String {
118 self.path.clone()
119 }
120
121 #[wasm_bindgen(setter = path)]
122 pub fn set_path(&mut self, path: String) {
123 self.path = path;
124 }
125
126 #[wasm_bindgen(getter = bufferSize)]
127 pub fn buffer_size(&self) -> usize {
128 self.buffer.len()
129 }
130 #[wasm_bindgen]
131 pub fn clone(&self) -> Self {
132 Clone::clone(self)
133 }
134}
135
136pub trait Encode {
137 fn encode(files: Vec<File>) -> Option<Vec<u8>>;
138}
139
140pub trait Decode {
141 fn decode<T: AsRef<[u8]>>(buffer: T) -> Option<Vec<File>>;
142}
143
144pub trait Archive: Encode + Decode {}
145
146#[cfg(test)]
147mod test {
148 use super::Fmt;
149
150 #[test]
151 fn test_guess() {
152 for (name, fmt) in [
153 ("a.zip", Fmt::Zip),
154 ("a.tar", Fmt::Tar),
155 ("a.tar.gz", Fmt::TarGz),
156 ("a.tar.xz", Fmt::TarXz),
157 ("a.tar.bz2", Fmt::TarBz),
158 ] {
159 assert!(Fmt::guess(name) == Some(fmt))
160 }
161 }
162}