Skip to content

Commit

Permalink
feat: Added RAR to the external archive interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Le0X8 committed Aug 9, 2024
1 parent 1154dd5 commit c128613
Show file tree
Hide file tree
Showing 7 changed files with 552 additions and 36 deletions.
71 changes: 66 additions & 5 deletions src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
file::{FileEntry, FileReader, FileWriter, FsFile},
formats::{
self,
rar::RarFileEntry,
zip::{ZipFile, ZipFileEntry},
Formats,
},
Expand All @@ -11,6 +12,7 @@ use std::fs::create_dir_all;

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

pub trait ArchiveMetadata<'a> {
Expand Down Expand Up @@ -40,7 +42,24 @@ pub fn metadata<'a>(
}
OriginalArchiveMetadata::Zip(metadata)
}
Formats::Rar => todo!(),
Formats::Rar => {
let metadata = formats::rar::parser::metadata(&mut file);
if check_integrity
&& !formats::rar::parser::check_integrity_headers(
&mut file,
&metadata,
&buffer_size,
)
&& !formats::rar::parser::check_integrity_all(
&mut file,
&metadata.files,
&buffer_size,
)
{
return Err("Integrity check failed".to_string());
};
OriginalArchiveMetadata::Rar(metadata)
}
};

Ok(Box::new(metadata))
Expand Down Expand Up @@ -73,7 +92,24 @@ pub fn extract(
}
&metadata.clone() as &dyn ArchiveMetadata
}
Formats::Rar => todo!(),
Formats::Rar => {
let metadata = formats::rar::parser::metadata(&mut file);
if check_integrity
&& !formats::rar::parser::check_integrity_headers(
&mut file,
&metadata,
&buffer_size,
)
&& !formats::rar::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();
Expand All @@ -86,7 +122,12 @@ pub fn extract(
format!("{}/{}", &output, &path)
});
}
Formats::Rar => todo!(),
Formats::Rar => {
let rar_files = formats::rar::to_rar_entries(files);
formats::rar::parser::extract(&mut file, &rar_files, &buffer_size, &|path| {
format!("{}/{}", &output, &path)
});
}
}
} else if index.is_some() {
let index = index.unwrap();
Expand All @@ -100,7 +141,12 @@ pub fn extract(
&buffer_size,
&|path| format!("{}/{}", &output, &path),
),
Formats::Rar => todo!(),
Formats::Rar => formats::rar::parser::extract(
&mut file,
&formats::rar::to_rar_entries(files),
&buffer_size,
&|path| format!("{}/{}", &output, &path),
),
};
} else {
let path = path.unwrap();
Expand All @@ -121,7 +167,22 @@ pub fn extract(
format!("{}/{}", &output, &path)
});
}
Formats::Rar => todo!(),
Formats::Rar => {
let files: Vec<RarFileEntry> = metadata
.get_files()
.iter()
.filter_map(|file| {
if file.get_path().starts_with(&path) {
Some(formats::rar::to_rar_entry(*file))
} else {
None
}
})
.collect();
formats::rar::parser::extract(&mut file, &files, &buffer_size, &|path| {
format!("{}/{}", &output, &path)
});
}
}
};

Expand Down
3 changes: 2 additions & 1 deletion src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{

use chrono::{DateTime, Utc};

use crate::formats::zip::ZipFileEntry;
use crate::formats::{rar::RarFileEntry, zip::ZipFileEntry};

pub struct FsFile {
pub size: u64,
Expand Down Expand Up @@ -59,6 +59,7 @@ pub trait File {

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

pub trait FileEntry<'a> {
Expand Down
139 changes: 138 additions & 1 deletion src/formats/rar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ use chrono::{DateTime, Utc};

pub mod parser;

use parser::EncryptionHeader;
use parser::{EncryptionHeader, Header};

use crate::{
archive::ArchiveMetadata,
file::{FileEntry, OriginalFileEntry},
};

#[derive(Debug)]
pub struct RarArchiveMetadata {
Expand All @@ -20,6 +25,43 @@ pub struct RarArchiveMetadata {
pub rr_offset: Option<u64>,
pub encryption_header: Option<EncryptionHeader>,
pub is_last: bool,
pub headers: Vec<Header>,
}

impl<'a> ArchiveMetadata<'a> for RarArchiveMetadata {
fn get_files(&self) -> Vec<&dyn FileEntry> {
self.files.iter().map(|x| x as &dyn FileEntry).collect()
}

fn get_format(&self) -> super::Formats {
super::Formats::Rar
}

fn get_original(&'a self) -> crate::archive::OriginalArchiveMetadata<'a> {
crate::archive::OriginalArchiveMetadata::Rar(self.clone())
}
}

impl Clone for RarArchiveMetadata {
fn clone(&self) -> Self {
RarArchiveMetadata {
files: self.files.clone(),
archive_start: self.archive_start,
version: self.version,
multivolume: self.multivolume,
volume: self.volume,
solid: self.solid,
has_recovery: self.has_recovery,
locked: self.locked,
original_name: self.original_name.clone(),
created: self.created,
qo_offset: self.qo_offset,
rr_offset: self.rr_offset,
encryption_header: self.encryption_header.clone(),
is_last: self.is_last,
headers: self.headers.clone(),
}
}
}

#[derive(Debug)]
Expand All @@ -36,11 +78,86 @@ pub struct RarFileEntry {
pub creation_platform: Option<RarPlatform>,
}

impl<'a> FileEntry<'a> for RarFileEntry {
fn get_path(&self) -> &String {
&self.path
}

fn get_offset(&self) -> &u64 {
&self.offset
}

fn get_size(&self) -> &u64 {
&self.size
}

fn get_modified(&self) -> &DateTime<Utc> {
todo!()
}

fn get_is_directory(&self) -> &bool {
&self.is_directory
}

fn get_uncompressed_size(&self) -> &u32 {
todo!()
}

fn get_original(&'a self) -> crate::file::OriginalFileEntry<'a> {
crate::file::OriginalFileEntry::Rar(self)
}
}

impl Clone for RarFileEntry {
fn clone(&self) -> Self {
RarFileEntry {
path: self.path.clone(),
offset: self.offset,
size: self.size,
uncompressed_size: self.uncompressed_size,
is_directory: self.is_directory,
modified: self.modified,
checksum: self.checksum,
encryption: self.encryption.clone(),
compression: self.compression.clone(),
creation_platform: self.creation_platform.clone(),
}
}
}

pub fn to_rar_entry<'a>(from: &'a (dyn FileEntry<'a> + 'a)) -> RarFileEntry {
let original = from.get_original();
match original {
OriginalFileEntry::Rar(rar_file) => rar_file.clone(),
_ => panic!("This could never happen, this is only here for type safety"),
}
}

pub fn to_rar_entries<'a>(from: Vec<&'a (dyn FileEntry<'a> + 'a)>) -> Vec<RarFileEntry> {
from.into_iter()
.map(|file| {
let original = file.get_original();
match original {
OriginalFileEntry::Rar(rar_file) => rar_file.clone(),
_ => panic!("This could never happen, this is only here for type safety"),
}
})
.collect()
}

#[derive(Debug)]
pub enum RarEncryption {
Aes256,
}

impl Clone for RarEncryption {
fn clone(&self) -> Self {
match self {
RarEncryption::Aes256 => RarEncryption::Aes256,
}
}
}

#[derive(Debug)]
pub struct RarCompression {
pub version: u8,
Expand All @@ -49,8 +166,28 @@ pub struct RarCompression {
pub dict_size: u64,
}

impl Clone for RarCompression {
fn clone(&self) -> Self {
RarCompression {
version: self.version,
solid: self.solid,
method: self.method,
dict_size: self.dict_size,
}
}
}

#[derive(Debug)]
pub enum RarPlatform {
Windows,
Unix,
}

impl Clone for RarPlatform {
fn clone(&self) -> Self {
match self {
RarPlatform::Windows => RarPlatform::Windows,
RarPlatform::Unix => RarPlatform::Unix,
}
}
}
Loading

0 comments on commit c128613

Please sign in to comment.