aboutsummaryrefslogtreecommitdiff
path: root/src/zip/driver.rs
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-06-23 15:19:40 +0900
committerIgor Tolmachev <me@igorek.dev>2024-06-23 15:34:35 +0900
commita4e92ed9bec1f5879eb1c20dfe281c4d25ed5f89 (patch)
tree6acef99bfaf57c573b543f29836701a92c215a83 /src/zip/driver.rs
parent62aaae347d87c5c9411f1e9f8db525b7c2c603d2 (diff)
downloadarchivator-a4e92ed9bec1f5879eb1c20dfe281c4d25ed5f89.tar.gz
archivator-a4e92ed9bec1f5879eb1c20dfe281c4d25ed5f89.zip
Improve ZipFile
Diffstat (limited to 'src/zip/driver.rs')
-rw-r--r--src/zip/driver.rs113
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 @@
1use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; 1use crate::driver::{ArchiveRead, ArchiveWrite, Driver};
2use crate::zip::error::{ZipError, ZipResult}; 2use crate::zip::file::CompressionMethod;
3use crate::zip::structs::{deserialize, EOCDR64Locator, CDR, EOCDR, EOCDR64}; 3use crate::zip::structs::{deserialize, EOCDR64Locator, ExtraHeader, CDR, EOCDR, EOCDR64};
4use crate::zip::ZipFile; 4use crate::zip::{ZipError, ZipFile, ZipResult};
5use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime};
5use std::collections::HashMap as Map; 6use std::collections::HashMap as Map;
6use std::fs::File; 7use std::fs::File;
7use std::io::{Read, Seek, SeekFrom, Write}; 8use 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 );