universal_archiver/format/
mod.rs1mod gzip;
2mod tar;
3mod xz;
4mod zip;
5
6use crate::format::gzip::GZipFormat;
7use crate::format::tar::TarFormat;
8use crate::format::xz::XZFormat;
9use crate::format::zip::ZipFormat;
10use anyhow::{bail, Result};
11use std::fs::File;
12use std::io::Read;
13use std::path::Path;
14
15pub enum Format {
16 Zip(ZipFormat),
17 Xz(XZFormat),
18 Gz(GZipFormat),
19 Tar(TarFormat),
20}
21
22pub struct FileObject {
23 pub ext: String,
24 pub header: [u8; 32],
25}
26
27pub trait FileFormat: Sized {
28 fn parse(file: &FileObject) -> Result<Self>;
29 fn extract(&self, file: &Path, output: &Path) -> Result<()>;
30}
31
32impl FileFormat for Format {
33 fn parse(file: &FileObject) -> Result<Self> {
34 if let Ok(zip) = ZipFormat::parse(file) {
35 tracing::info!("Detected zip format");
36 Ok(Self::Zip(zip))
37 } else if let Ok(tar) = TarFormat::parse(file) {
38 tracing::info!("Detected tar format");
39 Ok(Self::Tar(tar))
40 } else if let Ok(xz) = XZFormat::parse(file) {
41 tracing::info!("Detected xz format");
42 Ok(Self::Xz(xz))
43 } else if let Ok(gz) = GZipFormat::parse(file) {
44 tracing::info!("Detected gzip format");
45 Ok(Self::Gz(gz))
46 } else {
47 bail!("Unknown file format");
48 }
49 }
50
51 fn extract(&self, file: &Path, output: &Path) -> Result<()> {
52 match self {
53 Format::Zip(zip) => zip.extract(file, output),
54 Format::Xz(xz) => xz.extract(file, output),
55 Format::Gz(gz) => gz.extract(file, output),
56 Format::Tar(tar) => tar.extract(file, output),
57 }
58 }
59}
60
61pub fn parse_format(file: &Path) -> Result<Format> {
63 let obj = FileObject {
64 ext: get_file_extensions(file).unwrap_or_default(),
65 header: get_file_header(file)?,
66 };
67
68 Format::parse(&obj)
69}
70
71fn get_file_extensions(path: &Path) -> Option<String> {
76 let name = path.file_name()?.to_string_lossy();
77 let extensions: String = name
78 .split('.')
79 .skip(1)
80 .fold(String::new(), |acc, val| format!("{acc}.{val}"));
81
82 Some(extensions)
83}
84
85fn get_file_header(path: &Path) -> Result<[u8; 32]> {
88 let mut file = File::open(path)?;
89 let mut header_buf = [0u8; 32];
90 file.read_exact(&mut header_buf)?;
91
92 Ok(header_buf)
93}