use crate::format::*;
#[derive(Debug)]
pub struct Archive {
pub(crate) size: u64,
pub(crate) encoding: Encoding,
pub(crate) entries: Vec<StoredEntry>,
pub(crate) comment: Option<String>,
}
impl Archive {
pub fn entries(&self) -> &[StoredEntry] {
&self.entries[..]
}
pub fn by_name<N: AsRef<str>>(&self, name: N) -> Option<&StoredEntry> {
self.entries.iter().find(|&x| x.name() == name.as_ref())
}
pub fn encoding(&self) -> Encoding {
self.encoding
}
pub fn comment(&self) -> Option<&String> {
self.comment.as_ref()
}
}
#[derive(Debug)]
pub struct Entry {
pub name: String,
pub method: Method,
pub comment: Option<String>,
pub modified: chrono::DateTime<chrono::offset::Utc>,
pub created: Option<chrono::DateTime<chrono::offset::Utc>>,
pub accessed: Option<chrono::DateTime<chrono::offset::Utc>>,
}
impl Entry {
pub fn new<S>(name: S, method: Method) -> Self
where
S: Into<String>,
{
Self {
name: name.into(),
comment: None,
modified: zero_datetime(),
created: None,
accessed: None,
method,
}
}
}
#[derive(Debug)]
pub struct StoredEntry {
pub entry: Entry,
pub crc32: u32,
pub header_offset: u64,
pub compressed_size: u64,
pub uncompressed_size: u64,
pub external_attrs: u32,
pub creator_version: Version,
pub reader_version: Version,
pub flags: u16,
pub uid: Option<u32>,
pub gid: Option<u32>,
pub mode: Mode,
pub extra_fields: Vec<ExtraField>,
pub is_zip64: bool,
}
impl StoredEntry {
pub fn name(&self) -> &str {
self.entry.name.as_ref()
}
pub fn comment(&self) -> Option<&str> {
self.entry.comment.as_ref().map(|x| x.as_ref())
}
pub fn method(&self) -> Method {
self.entry.method
}
pub fn modified(&self) -> DateTime<Utc> {
self.entry.modified
}
pub fn created(&self) -> Option<&DateTime<Utc>> {
self.entry.created.as_ref()
}
pub fn accessed(&self) -> Option<&DateTime<Utc>> {
self.entry.accessed.as_ref()
}
pub fn reader<'a, F, R>(&'a self, get_reader: F) -> crate::reader::EntryReader<'a, R>
where
R: std::io::Read,
F: Fn(u64) -> R,
{
crate::reader::EntryReader::new(self, get_reader)
}
}
#[derive(Debug)]
pub enum EntryContents<'a> {
Directory(Directory<'a>),
File(File<'a>),
Symlink(Symlink<'a>),
}
impl StoredEntry {
pub fn contents<'a>(&'a self) -> EntryContents<'a> {
if self.mode.has(Mode::SYMLINK) {
EntryContents::Symlink(Symlink { entry: &self })
} else if self.mode.has(Mode::DIR) {
EntryContents::Directory(Directory { entry: &self })
} else {
EntryContents::File(File { entry: &self })
}
}
}
#[derive(Debug)]
pub struct Directory<'a> {
pub entry: &'a StoredEntry,
}
#[derive(Debug)]
pub struct File<'a> {
pub entry: &'a StoredEntry,
}
#[derive(Debug)]
pub struct Symlink<'a> {
pub entry: &'a StoredEntry,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Method {
Store,
Deflate,
Bzip2,
Lzma,
Unsupported(u16),
}
impl From<u16> for Method {
fn from(m: u16) -> Self {
use Method::*;
match m {
0 => Store,
8 => Deflate,
12 => Bzip2,
14 => Lzma,
_ => Unsupported(m),
}
}
}
impl Into<u16> for Method {
fn into(self) -> u16 {
use Method::*;
match self {
Store => 0,
Deflate => 8,
Bzip2 => 12,
Lzma => 14,
Unsupported(m) => m,
}
}
}