You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
2.2 KiB
Rust
65 lines
2.2 KiB
Rust
use crate::format::{FileFormat, FileObject};
|
|
use anyhow::{bail, Context, Result};
|
|
use std::fs::File;
|
|
use std::path::Path;
|
|
use std::{fs, io};
|
|
use zip::ZipArchive;
|
|
|
|
const ZIP_HEADER: &[u8] = &[0x50, 0x4b];
|
|
|
|
pub struct ZipFormat;
|
|
|
|
impl FileFormat for ZipFormat {
|
|
fn parse(file: &FileObject) -> Result<Self> {
|
|
if file.header.starts_with(ZIP_HEADER) {
|
|
if !file.ext.ends_with(".zip") {
|
|
tracing::warn!("The file has a zip signature but no zip extension.");
|
|
}
|
|
Ok(Self)
|
|
} else {
|
|
bail!("Not a zip file");
|
|
}
|
|
}
|
|
|
|
fn extract(&self, file: &Path, output: &Path) -> Result<()> {
|
|
if output.is_file() {
|
|
bail!("The given output is a file");
|
|
}
|
|
let file = File::open(file)?;
|
|
let mut archive = ZipArchive::new(file).context("Opening zip file")?;
|
|
tracing::info!("Zip file with {} entries", archive.len());
|
|
|
|
for i in 0..archive.len() {
|
|
let mut file = archive.by_index(i).context("Getting file by index")?;
|
|
let path = match file.enclosed_name() {
|
|
None => {
|
|
tracing::error!(
|
|
"Cannot extract {:?} because it has an invalid name",
|
|
file.name()
|
|
);
|
|
continue;
|
|
}
|
|
Some(path) => path,
|
|
};
|
|
let output_path = output.join(path);
|
|
|
|
if (*file.name()).ends_with('/') {
|
|
tracing::debug!("Creating directory {output_path:?}");
|
|
fs::create_dir_all(output_path).context("Creating directory")?;
|
|
} else {
|
|
if let Some(parent) = output_path.parent() {
|
|
if !parent.exists() {
|
|
tracing::debug!("Creating parent directory {parent:?}");
|
|
fs::create_dir_all(parent).context("Creating parent dir")?;
|
|
}
|
|
}
|
|
let mut file_output = File::create(&output_path).context("Creating output file")?;
|
|
tracing::debug!("Extracting to {output_path:?}");
|
|
io::copy(&mut file, &mut file_output).context("Writing output file")?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|