diff options
Diffstat (limited to 'src/zip/driver.rs')
| -rw-r--r-- | src/zip/driver.rs | 113 |
1 files changed, 79 insertions, 34 deletions
diff --git a/src/zip/driver.rs b/src/zip/driver.rs index e5aa58d..8e8c27c 100644 --- a/src/zip/driver.rs +++ b/src/zip/driver.rs | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; | 1 | use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; |
| 2 | use crate::zip::error::{ZipError, ZipResult}; | 2 | use crate::zip::file::CompressionMethod; |
| 3 | use crate::zip::structs::{deserialize, EOCDR64Locator, CDR, EOCDR, EOCDR64}; | 3 | use crate::zip::structs::{deserialize, EOCDR64Locator, ExtraHeader, CDR, EOCDR, EOCDR64}; |
| 4 | use crate::zip::ZipFile; | 4 | use crate::zip::{ZipError, ZipFile, ZipResult}; |
| 5 | use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime}; | ||
| 5 | use std::collections::HashMap as Map; | 6 | use std::collections::HashMap as Map; |
| 6 | use std::fs::File; | 7 | use std::fs::File; |
| 7 | use std::io::{Read, Seek, SeekFrom, Write}; | 8 | use std::io::{Read, Seek, SeekFrom, Write}; |
| @@ -41,7 +42,7 @@ impl<IO: Read + Seek> ArchiveRead for Zip<IO> { | |||
| 41 | io.read(&mut buf)?; | 42 | io.read(&mut buf)?; |
| 42 | buf | 43 | buf |
| 43 | }; | 44 | }; |
| 44 | let eocdr: EOCDR = deserialize(&buf).map_err(|_| ZipError::InvalidEOCDR)?; | 45 | let eocdr: EOCDR = deserialize(&buf).unwrap(); |
| 45 | let comment = { | 46 | let comment = { |
| 46 | let mut buf: Vec<u8> = vec![0; eocdr.comment_len as usize]; | 47 | let mut buf: Vec<u8> = vec![0; eocdr.comment_len as usize]; |
| 47 | io.read(&mut buf)?; | 48 | io.read(&mut buf)?; |
| @@ -55,31 +56,29 @@ impl<IO: Read + Seek> ArchiveRead for Zip<IO> { | |||
| 55 | io.read(&mut buf)?; | 56 | io.read(&mut buf)?; |
| 56 | buf | 57 | buf |
| 57 | }; | 58 | }; |
| 58 | let (cd_pointer, cd_size, cd_records) = if u32::from_le_bytes(buf[0..4].try_into().unwrap()) | 59 | let (cd_pointer, cd_size, cd_records) = |
| 59 | == 0x07064b50 | 60 | if u32::from_le_bytes(buf[0..4].try_into().unwrap()) == 0x07064b50 { |
| 60 | { | 61 | let eocdr64locator: EOCDR64Locator = deserialize(&buf[4..]).unwrap(); |
| 61 | let eocdr64locator: EOCDR64Locator = | 62 | |
| 62 | deserialize(&buf[4..]).map_err(|_| ZipError::InvalidEOCDR64Locator)?; | 63 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; |
| 63 | 64 | let buf = { | |
| 64 | io.seek(SeekFrom::Start(eocdr64locator.eocdr64_pointer))?; | 65 | let mut buf = [0; 56]; |
| 65 | let buf = { | 66 | io.read(&mut buf)?; |
| 66 | let mut buf = [0; 56]; | 67 | buf |
| 67 | io.read(&mut buf)?; | 68 | }; |
| 68 | buf | 69 | if u32::from_le_bytes(buf[0..4].try_into().unwrap()) != 0x06064b50 { |
| 70 | return Err(ZipError::InvalidEOCDR64Signature.into()); | ||
| 71 | } | ||
| 72 | let eocdr64: EOCDR64 = deserialize(&buf[4..]).unwrap(); | ||
| 73 | |||
| 74 | (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) | ||
| 75 | } else { | ||
| 76 | ( | ||
| 77 | eocdr.cd_pointer as u64, | ||
| 78 | eocdr.cd_size as u64, | ||
| 79 | eocdr.cd_records as u64, | ||
| 80 | ) | ||
| 69 | }; | 81 | }; |
| 70 | if u32::from_le_bytes(buf[0..4].try_into().unwrap()) != 0x06064b50 { | ||
| 71 | return Err(ZipError::InvalidEOCDR64Signature.into()); | ||
| 72 | } | ||
| 73 | let eocdr64: EOCDR64 = deserialize(&buf[4..]).map_err(|_| ZipError::InvalidEOCDR64)?; | ||
| 74 | |||
| 75 | (eocdr64.cd_pointer, eocdr64.cd_size, eocdr64.cd_records) | ||
| 76 | } else { | ||
| 77 | ( | ||
| 78 | eocdr.cd_pointer as u64, | ||
| 79 | eocdr.cd_size as u64, | ||
| 80 | eocdr.cd_records as u64, | ||
| 81 | ) | ||
| 82 | }; | ||
| 83 | 82 | ||
| 84 | // Read cd records | 83 | // Read cd records |
| 85 | let mut files = Map::with_capacity(cd_records as usize); | 84 | let mut files = Map::with_capacity(cd_records as usize); |
| @@ -96,7 +95,7 @@ impl<IO: Read + Seek> ArchiveRead for Zip<IO> { | |||
| 96 | return Err(ZipError::InvalidCDRSignature.into()); | 95 | return Err(ZipError::InvalidCDRSignature.into()); |
| 97 | } | 96 | } |
| 98 | p += 4; | 97 | p += 4; |
| 99 | let cdr: CDR = deserialize(&buf[p..p + 42]).map_err(|_| ZipError::InvalidCDR)?; | 98 | let cdr: CDR = deserialize(&buf[p..p + 42]).unwrap(); |
| 100 | p += 42; | 99 | p += 42; |
| 101 | let name = String::from_utf8(buf[p..p + cdr.name_len as usize].into()).unwrap(); | 100 | let name = String::from_utf8(buf[p..p + cdr.name_len as usize].into()).unwrap(); |
| 102 | p += cdr.name_len as usize; | 101 | p += cdr.name_len as usize; |
| @@ -105,15 +104,61 @@ impl<IO: Read + Seek> ArchiveRead for Zip<IO> { | |||
| 105 | let comment = String::from_utf8(buf[p..p + cdr.comment_len as usize].into()).unwrap(); | 104 | let comment = String::from_utf8(buf[p..p + cdr.comment_len as usize].into()).unwrap(); |
| 106 | p += cdr.comment_len as usize; | 105 | p += cdr.comment_len as usize; |
| 107 | 106 | ||
| 107 | let mut compressed_size = cdr.compressed_size as u64; | ||
| 108 | let mut size = cdr.size as u64; | ||
| 109 | let mut header_pointer = cdr.header_pointer as u64; | ||
| 110 | |||
| 111 | let mut ep: usize = 0; | ||
| 112 | while ep < cdr.extra_field_len as usize { | ||
| 113 | let header: ExtraHeader = deserialize(&extra_fields[ep..ep + 4]).unwrap(); | ||
| 114 | ep += 4; | ||
| 115 | match header.id { | ||
| 116 | 0x0001 => { | ||
| 117 | if size == 0xFFFFFFFF { | ||
| 118 | compressed_size = deserialize(&extra_fields[ep..ep + 8]).unwrap(); | ||
| 119 | ep += 8; | ||
| 120 | } | ||
| 121 | if compressed_size == 0xFFFFFFFF { | ||
| 122 | size = deserialize(&extra_fields[ep..ep + 8]).unwrap(); | ||
| 123 | ep += 8; | ||
| 124 | } | ||
| 125 | if header_pointer == 0xFFFFFFFF { | ||
| 126 | header_pointer = deserialize(&extra_fields[ep..ep + 8]).unwrap(); | ||
| 127 | ep += 8; | ||
| 128 | } | ||
| 129 | if cdr.disk == 0xFFFF { | ||
| 130 | ep += 4 | ||
| 131 | } | ||
| 132 | } | ||
| 133 | _ => ep += header.size as usize, | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 108 | files.insert( | 137 | files.insert( |
| 109 | name.clone(), | 138 | name.clone(), |
| 110 | ZipFile::new( | 139 | ZipFile::new( |
| 140 | CompressionMethod::from_struct_id(cdr.compression_method)?, | ||
| 141 | NaiveDateTime::new( | ||
| 142 | NaiveDate::from_ymd_opt( | ||
| 143 | (cdr.dos_date as i32 >> 9 & 0x7F) + 1980, | ||
| 144 | cdr.dos_date as u32 >> 5 & 0xF, | ||
| 145 | cdr.dos_date as u32 & 0x1F, | ||
| 146 | ) | ||
| 147 | .ok_or(ZipError::InvalidDate)?, | ||
| 148 | NaiveTime::from_hms_opt( | ||
| 149 | (cdr.dos_time as u32 >> 11) & 0x1F, | ||
| 150 | (cdr.dos_time as u32 >> 5) & 0x3F, | ||
| 151 | (cdr.dos_time as u32 & 0x1F) * 2, | ||
| 152 | ) | ||
| 153 | .ok_or(ZipError::InvalidTime)?, | ||
| 154 | ) | ||
| 155 | .and_local_timezone(Local) | ||
| 156 | .unwrap(), | ||
| 157 | cdr.crc, | ||
| 158 | compressed_size, | ||
| 159 | size, | ||
| 160 | header_pointer, | ||
| 111 | name, | 161 | name, |
| 112 | cdr.dos_date, | ||
| 113 | cdr.dos_time, | ||
| 114 | cdr.compression_method, | ||
| 115 | cdr.compressed_size as u64, | ||
| 116 | cdr.size as u64, | ||
| 117 | comment, | 162 | comment, |
| 118 | ), | 163 | ), |
| 119 | ); | 164 | ); |
