use crate::driver::ArchiveFileInfo; use crate::zip::datetime::DosDateTime; use chrono::{DateTime, Local}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum CompressionMethod { Store, Deflate, BZip2, Lzma, Zstd, Xz, Unsupported(u16), } impl CompressionMethod { #[inline] pub(crate) fn from_struct_id(id: u16) -> Self { match id { 0 => Self::Store, 8 => Self::Deflate, 12 => Self::BZip2, 14 => Self::Lzma, 93 => Self::Zstd, 95 => Self::Xz, _ => Self::Unsupported(id), } } } #[derive(Debug, PartialEq, Eq, Clone)] pub enum EncryptionMethod { None, Weak, // ZipCrypto Aes128, // WinZip encryption Aes192, Aes256, Unsupported, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub struct BitFlag { flag: u16, } pub mod bit { #[derive(Debug, PartialEq, Eq, Clone)] pub enum DeflateMode { Normal, Maximum, Fast, SuperFast, } } macro_rules! get_set_bit_flag { {$($get:ident $set:ident $bit:expr)+} => { $( pub fn $get(&self) -> bool { self.get_bit($bit) } pub fn $set(&mut self, enable: bool) { self.set_bit($bit, enable); } )* }; } impl BitFlag { pub fn new(flag: u16) -> Self { Self { flag } } #[inline] fn get_bit(&self, bit: u32) -> bool { (self.flag & 2u16.pow(bit)) > 0 } #[inline] fn set_bit(&mut self, bit: u32, enable: bool) { if enable { self.flag |= 2u16.pow(bit); } else { self.flag &= !2u16.pow(bit); } } pub fn deflate_mode(&self) -> bit::DeflateMode { match self.flag & 6 { 0 => bit::DeflateMode::Normal, 2 => bit::DeflateMode::Maximum, 4 => bit::DeflateMode::Fast, 6 => bit::DeflateMode::SuperFast, _ => panic!("impossible"), } } pub fn set_deflate_mode(&mut self, mode: bit::DeflateMode) { match mode { bit::DeflateMode::Normal => { self.set_bit(1, false); self.set_bit(2, false); } bit::DeflateMode::Maximum => { self.set_bit(1, true); self.set_bit(2, false); } bit::DeflateMode::Fast => { self.set_bit(1, false); self.set_bit(2, true); } bit::DeflateMode::SuperFast => { self.set_bit(1, true); self.set_bit(2, true); } } } get_set_bit_flag! { is_encrypted set_encrypted 0 is_imploding_8k set_imploding_8k 1 is_imploding_3sf_trees set_imploding_3sf_trees 2 is_lzma_has_eos_marker set_lzma_has_eos_marker 1 is_has_data_descriptor set_has_data_descriptor 3 is_patched_data set_patched_data 5 is_strong_encryption set_strong_encryption 6 is_utf8 set_utf8 11 is_cd_encryption set_cd_encryption 13 } } #[derive(Debug, Clone)] pub struct ZipFileInfo { pub compression_method: CompressionMethod, pub encryption_method: EncryptionMethod, pub bit_flag: BitFlag, pub mtime: DateTime, pub atime: Option>, pub ctime: Option>, pub crc: u32, pub compressed_size: u64, pub size: u64, pub header_pointer: u64, pub name: String, pub comment: String, } impl ZipFileInfo { pub(crate) fn new( compression_method: CompressionMethod, encryption_method: EncryptionMethod, bit_flag: BitFlag, mtime: DateTime, atime: Option>, ctime: Option>, crc: u32, compressed_size: u64, size: u64, header_pointer: u64, name: String, comment: String, ) -> Self { Self { compression_method, encryption_method, bit_flag, mtime, atime, ctime, crc, compressed_size, size, header_pointer, name, comment, } } #[inline] pub(crate) fn password_check(&self) -> u8 { if self.bit_flag.is_has_data_descriptor() { (self.mtime.to_dos_time() >> 8) as u8 } else { (self.crc >> 24) as u8 } } pub fn is_dir(&self) -> bool { self.name.ends_with("/") } } impl ArchiveFileInfo for ZipFileInfo {}