Skip to content

Commit

Permalink
feat!: Merge pull request #21 from acridotheres/18-bundle-functions-t…
Browse files Browse the repository at this point in the history
…ogether

Bundle functions together (v0.2.0)
  • Loading branch information
Le0X8 authored Aug 1, 2024
2 parents 451081a + 703649c commit 92b0704
Show file tree
Hide file tree
Showing 11 changed files with 773 additions and 116 deletions.
173 changes: 173 additions & 0 deletions src/archive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use crate::{
file::{FileEntry, FileReader, FileWriter, FsFile},
formats::{
self,
zip::{ZipFile, ZipFileEntry},
Formats,
},
helpers::hash::crc32,
};
use std::fs::create_dir_all;

pub enum OriginalArchiveMetadata<'a> {
Zip(formats::zip::ZipArchiveMetadata<'a>),
}

pub trait ArchiveMetadata<'a> {
fn get_format(&self) -> Formats;
fn get_files(&self) -> Vec<&dyn FileEntry>;
fn get_original(&'a self) -> OriginalArchiveMetadata<'a>;
}

pub fn metadata<'a>(
format: Formats,
input: String,
check_integrity: bool,
buffer_size: u64,
) -> Result<Box<OriginalArchiveMetadata<'a>>, String> {
let mut file = FileReader::new(&input);
let metadata = match format {
Formats::Zip => {
let metadata = formats::zip::parser::metadata(&mut file);
if check_integrity {
if !formats::zip::parser::check_integrity_all(
&mut file,
&metadata.files,
&buffer_size,
) {
return Err("Integrity check failed".to_string());
}
}
OriginalArchiveMetadata::Zip(metadata)
}
};

Ok(Box::new(metadata))
}

pub fn extract(
format: Formats,
input: String,
output: String,
index: Option<u32>,
path: Option<String>,
all: bool,
check_integrity: bool,
buffer_size: u64,
) -> Result<(), String> {
let mut file = FileReader::new(&input);
create_dir_all(&output).unwrap();

let metadata: &dyn ArchiveMetadata = match format {
Formats::Zip => {
let metadata = formats::zip::parser::metadata(&mut file);
if check_integrity {
if !formats::zip::parser::check_integrity_all(
&mut file,
&metadata.files,
&buffer_size,
) {
return Err("Integrity check failed".to_string());
}
}
&metadata.clone() as &dyn ArchiveMetadata
}
};

let files = metadata.get_files();

if all {
match format {
Formats::Zip => {
let zip_files = formats::zip::to_zip_entries(files);
formats::zip::parser::extract(&mut file, &zip_files, &buffer_size, &|path| {
format!("{}/{}", &output, &path)
});
}
}
} else {
if index != None {
let index = index.unwrap();
if index >= files.len() as u32 {
return Err("Index out of range".to_string());
}
formats::zip::parser::extract(
&mut file,
&formats::zip::to_zip_entries(files),
&buffer_size,
&|path| format!("{}/{}", &output, &path),
);
} else {
let path = path.unwrap();
let files: Vec<ZipFileEntry> = metadata
.get_files()
.iter()
.filter_map(|file| {
if file.get_path().starts_with(&path) {
Some(formats::zip::to_zip_entry(*file))
} else {
None
}
})
.collect();
formats::zip::parser::extract(&mut file, &files, &buffer_size, &|path| {
format!("{}/{}", &output, &path)
});
}
};

Ok(())
}

pub struct EntrySource<'a> {
pub path: String,
pub source: &'a mut FsFile,
}

pub fn create(
format: Formats,
output: String,
input: &mut Vec<EntrySource>,
buffer_size: u64,
) -> Result<(), String> {
let mut file = FileWriter::new(&output, &false);

match format {
Formats::Zip => {
let files: Vec<ZipFile> = input
.iter_mut()
.map(|entry| {
if entry.source.is_directory {
return ZipFile {
checksum: 0,
path: entry.path.clone(),
offset: 0,
size: 0,
modified: entry.source.modified,
is_directory: true,
source: None,
};
};
let size = entry.source.size.to_owned();
let reader = entry.source.reader.as_mut().unwrap();
ZipFile {
checksum: crc32::hash(reader, &0, &size, &buffer_size),
path: entry.path.clone(),
offset: 0,
size,
modified: entry.source.modified,
is_directory: entry.source.is_directory,
source: Some(reader),
}
})
.collect();
formats::zip::writer::write(
&mut file,
&mut formats::zip::ZipArchiveData { files },
&buffer_size,
);
}
}

Ok(())
}
55 changes: 54 additions & 1 deletion src/file.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,65 @@
use std::{
cmp::min,
fs::{FileTimes, OpenOptions},
fs::{self, FileTimes, OpenOptions},
io::{Read, Seek, Write},
mem::drop,
};

use chrono::{DateTime, Utc};

use crate::formats::zip::ZipFileEntry;

pub struct FsFile {
pub size: u64,
pub reader: Option<FileReader>,
pub modified: DateTime<Utc>,
pub is_directory: bool,
}

impl FsFile {
pub fn new(path: &String) -> Self {
if fs::metadata(path).unwrap().is_dir() {
return Self {
size: 0,
reader: None,
modified: fs::metadata(path).unwrap().modified().unwrap().into(),
is_directory: true,
};
};
let reader = FileReader::new(path);
Self {
size: reader.get_size(),
modified: reader.get_times().modified,
reader: Some(reader),
is_directory: false,
}
}
}

pub trait File {
fn get_path(&self) -> &String;
fn get_offset(&self) -> &u64;
fn get_size(&self) -> &u64;
fn get_modified(&self) -> &DateTime<Utc>;
fn get_is_directory(&self) -> &bool;
fn get_source(&mut self) -> Option<&mut FileReader>;
fn get_checksum(&self) -> &u32;
}

pub enum OriginalFileEntry<'a> {
Zip(&'a ZipFileEntry<'a>),
}

pub trait FileEntry<'a> {
fn get_path(&self) -> &String;
fn get_offset(&self) -> &u64;
fn get_size(&self) -> &u64;
fn get_modified(&self) -> &DateTime<Utc>;
fn get_is_directory(&self) -> &bool;
fn get_uncompressed_size(&self) -> &u32;
fn get_original(&'a self) -> OriginalFileEntry<'a>;
}

#[derive(Debug)]
pub struct Times {
pub created: DateTime<Utc>,
Expand Down
32 changes: 32 additions & 0 deletions src/formats.rs
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
use crate::archive::ArchiveMetadata;

pub mod zip;

pub enum Formats {
Zip,
}

pub fn from_string(format: &String) -> Formats {
match format.as_str() {
"zip" => Formats::Zip,
_ => panic!("Unsupported format"),
}
}

pub fn to_string(format: &Formats) -> String {
match format {
Formats::Zip => "zip".to_string(),
}
}

pub enum FormatMetadata<'a> {
Zip(zip::ZipArchiveMetadata<'a>),
}

pub fn to_format_metadata<'a>(
format: Formats,
metadata: &'a dyn ArchiveMetadata<'a>,
) -> FormatMetadata<'a> {
match format {
Formats::Zip => FormatMetadata::Zip(zip::to_zip_archive_metadata(metadata)),
}
}
Loading

0 comments on commit 92b0704

Please sign in to comment.