From 3c6dffa5ccfc72804a76f2090738721b90b10ce8 Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Tue, 25 Jun 2024 23:23:19 +0900 Subject: Add bit flag logic --- src/zip/driver.rs | 3 +- src/zip/file.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/zip/mod.rs | 3 ++ src/zip/tests.rs | 42 +++++++++++++++++++++++++ 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/zip/tests.rs (limited to 'src') diff --git a/src/zip/driver.rs b/src/zip/driver.rs index 8e8c27c..c9a5155 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs @@ -1,5 +1,5 @@ use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; -use crate::zip::file::CompressionMethod; +use crate::zip::file::{BitFlag, CompressionMethod}; use crate::zip::structs::{deserialize, EOCDR64Locator, ExtraHeader, CDR, EOCDR, EOCDR64}; use crate::zip::{ZipError, ZipFile, ZipResult}; use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime}; @@ -138,6 +138,7 @@ impl ArchiveRead for Zip { name.clone(), ZipFile::new( CompressionMethod::from_struct_id(cdr.compression_method)?, + BitFlag::new(cdr.bit_flag), NaiveDateTime::new( NaiveDate::from_ymd_opt( (cdr.dos_date as i32 >> 9 & 0x7F) + 1980, diff --git a/src/zip/file.rs b/src/zip/file.rs index f735d65..b4f2d7c 100644 --- a/src/zip/file.rs +++ b/src/zip/file.rs @@ -28,8 +28,100 @@ impl CompressionMethod { } } +pub struct BitFlag { + pub flag: u16, +} + +pub mod bit { + #[derive(Debug, PartialEq, Eq)] + 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 + } +} + pub struct ZipFile { pub compression_method: CompressionMethod, + pub bit_flag: BitFlag, pub datetime: DateTime, pub crc: u32, pub compressed_size: u64, @@ -42,6 +134,7 @@ pub struct ZipFile { impl ZipFile { pub fn new( compression_method: CompressionMethod, + bit_flag: BitFlag, datetime: DateTime, crc: u32, compressed_size: u64, @@ -52,6 +145,7 @@ impl ZipFile { ) -> Self { Self { compression_method, + bit_flag, datetime, crc, compressed_size, diff --git a/src/zip/mod.rs b/src/zip/mod.rs index 8601526..23cadb9 100644 --- a/src/zip/mod.rs +++ b/src/zip/mod.rs @@ -6,3 +6,6 @@ mod structs; pub use driver::Zip; pub use error::{ZipError, ZipResult}; pub use file::ZipFile; + +#[cfg(test)] +mod tests; diff --git a/src/zip/tests.rs b/src/zip/tests.rs new file mode 100644 index 0000000..d64e626 --- /dev/null +++ b/src/zip/tests.rs @@ -0,0 +1,42 @@ +use crate::zip::file::{bit::DeflateMode, BitFlag}; + +#[test] +fn test_bit_flag() { + macro_rules! bit_flag { + ($($get:ident $set:ident)+) => { + $( + let mut bit_flag = BitFlag::new(0); + + assert_eq!(bit_flag.$get(), false); + bit_flag.$set(true); + assert_eq!(bit_flag.$get(), true); + bit_flag.$set(false); + assert_eq!(bit_flag.$get(), false); + )+ + }; + } + + bit_flag!( + is_encrypted set_encrypted + is_imploding_8k set_imploding_8k + is_imploding_3sf_trees set_imploding_3sf_trees + is_lzma_has_eos_marker set_lzma_has_eos_marker + is_has_data_descriptor set_has_data_descriptor + is_patched_data set_patched_data + is_strong_encryption set_strong_encryption + is_utf8 set_utf8 + is_cd_encryption set_cd_encryption + ); + + let mut bit_flag = BitFlag::new(0); + + assert_eq!(bit_flag.deflate_mode(), DeflateMode::Normal); + bit_flag.set_deflate_mode(DeflateMode::Maximum); + assert_eq!(bit_flag.deflate_mode(), DeflateMode::Maximum); + bit_flag.set_deflate_mode(DeflateMode::Fast); + assert_eq!(bit_flag.deflate_mode(), DeflateMode::Fast); + bit_flag.set_deflate_mode(DeflateMode::SuperFast); + assert_eq!(bit_flag.deflate_mode(), DeflateMode::SuperFast); + bit_flag.set_deflate_mode(DeflateMode::Normal); + assert_eq!(bit_flag.deflate_mode(), DeflateMode::Normal); +} -- cgit v1.2.3