aboutsummaryrefslogtreecommitdiff
path: root/src/zip/driver.rs
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-01 19:12:40 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-02 18:59:00 +0900
commit5d3d32ded672b67471d9d7c85ebbe691129cc51c (patch)
tree1f9a82196d69cfec34af595a659e4d74a80b0c92 /src/zip/driver.rs
parent6d5f8f046b3b24e50cb1a0e7751c6bc9170ed9d1 (diff)
downloadarchivator-5d3d32ded672b67471d9d7c85ebbe691129cc51c.tar.gz
archivator-5d3d32ded672b67471d9d7c85ebbe691129cc51c.zip
Add compression support (lzma and xz are broken)
Diffstat (limited to 'src/zip/driver.rs')
-rw-r--r--src/zip/driver.rs88
1 files changed, 50 insertions, 38 deletions
diff --git a/src/zip/driver.rs b/src/zip/driver.rs
index a280dc7..e276844 100644
--- a/src/zip/driver.rs
+++ b/src/zip/driver.rs
@@ -1,13 +1,17 @@
1use crate::driver::{ArchiveRead, ArchiveWrite, Driver}; 1use crate::driver::{ArchiveRead, ArchiveWrite, Driver};
2use crate::zip::structs::{deserialize, EOCDR64Locator, ExtraHeader, CDR, EOCDR, EOCDR64}; 2use crate::zip::structs::{deserialize, EOCDR64Locator, ExtraHeader, CDR, EOCDR, EOCDR64};
3use crate::zip::{BitFlag, CompressionMethod, ZipError, ZipFile, ZipFileInfo, ZipResult}; 3use crate::zip::{
4 BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult,
5};
4use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime}; 6use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime};
7use std::collections::HashMap as Map;
8use std::fs::File;
5use std::io::{Read, Seek, SeekFrom, Write}; 9use std::io::{Read, Seek, SeekFrom, Write};
6 10
7pub struct Zip<Io> { 11pub struct Zip<Io = File> {
8 io: Io, 12 io: Io,
9 13
10 files: Vec<ZipFileInfo>, 14 files: Map<String, ZipFileInfo>,
11 comment: String, 15 comment: String,
12} 16}
13 17
@@ -15,11 +19,12 @@ impl<Io> Driver for Zip<Io> {
15 type Error = ZipError; 19 type Error = ZipError;
16 20
17 type Io = Io; 21 type Io = Io;
18 type FileDriver<'d> = ZipFile<'d, Self::Io> where Self::Io: 'd;
19 type FileInfo = ZipFileInfo; 22 type FileInfo = ZipFileInfo;
20} 23}
21 24
22impl<Io: Read + Seek> ArchiveRead for Zip<Io> { 25impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
26 type FileReader<'d> = ZipFileReader<'d, Io> where Io: 'd;
27
23 fn read(mut io: Self::Io) -> ZipResult<Self> { 28 fn read(mut io: Self::Io) -> ZipResult<Self> {
24 // Search eocdr 29 // Search eocdr
25 let limit = 65557.min(io.seek(SeekFrom::End(0))?) as i64; 30 let limit = 65557.min(io.seek(SeekFrom::End(0))?) as i64;
@@ -79,7 +84,7 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
79 }; 84 };
80 85
81 // Read cd records 86 // Read cd records
82 let mut files = Vec::with_capacity(cd_records as usize); 87 let mut files = Map::with_capacity(cd_records as usize);
83 io.seek(SeekFrom::Start(cd_pointer))?; 88 io.seek(SeekFrom::Start(cd_pointer))?;
84 let buf = { 89 let buf = {
85 let mut buf = vec![0; cd_size as usize]; 90 let mut buf = vec![0; cd_size as usize];
@@ -134,49 +139,54 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
134 } 139 }
135 } 140 }
136 141
137 files.push(ZipFileInfo::new( 142 files.insert(
138 CompressionMethod::from_struct_id(cdr.compression_method)?, 143 name.clone(),
139 BitFlag::new(cdr.bit_flag), 144 ZipFileInfo::new(
140 NaiveDateTime::new( 145 CompressionMethod::from_struct_id(cdr.compression_method)?,
141 NaiveDate::from_ymd_opt( 146 BitFlag::new(cdr.bit_flag),
142 (cdr.dos_date as i32 >> 9 & 0x7F) + 1980, 147 NaiveDateTime::new(
143 cdr.dos_date as u32 >> 5 & 0xF, 148 NaiveDate::from_ymd_opt(
144 cdr.dos_date as u32 & 0x1F, 149 (cdr.dos_date as i32 >> 9 & 0x7F) + 1980,
145 ) 150 cdr.dos_date as u32 >> 5 & 0xF,
146 .ok_or(ZipError::InvalidDate)?, 151 cdr.dos_date as u32 & 0x1F,
147 NaiveTime::from_hms_opt( 152 )
148 (cdr.dos_time as u32 >> 11) & 0x1F, 153 .ok_or(ZipError::InvalidDate)?,
149 (cdr.dos_time as u32 >> 5) & 0x3F, 154 NaiveTime::from_hms_opt(
150 (cdr.dos_time as u32 & 0x1F) * 2, 155 (cdr.dos_time as u32 >> 11) & 0x1F,
156 (cdr.dos_time as u32 >> 5) & 0x3F,
157 (cdr.dos_time as u32 & 0x1F) * 2,
158 )
159 .ok_or(ZipError::InvalidTime)?,
151 ) 160 )
152 .ok_or(ZipError::InvalidTime)?, 161 .and_local_timezone(Local)
153 ) 162 .unwrap(),
154 .and_local_timezone(Local) 163 cdr.crc,
155 .unwrap(), 164 compressed_size,
156 cdr.crc, 165 size,
157 compressed_size, 166 header_pointer,
158 size, 167 name,
159 header_pointer, 168 comment,
160 name, 169 ),
161 comment, 170 );
162 ));
163 } 171 }
164 172
165 Ok(Self { io, files, comment }) 173 Ok(Self { io, files, comment })
166 } 174 }
167 175
168 fn files(&self) -> &Vec<Self::FileInfo> { 176 fn files(&self) -> Vec<&Self::FileInfo> {
169 &self.files 177 let mut files: Vec<&Self::FileInfo> = self.files.values().collect();
178 files.sort_by_key(|f| &f.name);
179 files
170 } 180 }
171 181
172 fn get_file_info(&self, index: usize) -> ZipResult<&Self::FileInfo> { 182 fn get_file_info(&self, name: &str) -> ZipResult<&Self::FileInfo> {
173 self.files.get(index).ok_or(ZipError::FileNotFound.into()) 183 self.files.get(name).ok_or(ZipError::FileNotFound.into())
174 } 184 }
175 185
176 fn get_file_reader<'d>(&'d mut self, index: usize) -> ZipResult<Self::FileDriver<'d>> { 186 fn get_file_reader<'d>(&'d mut self, name: &str) -> ZipResult<Self::FileReader<'d>> {
177 Ok(ZipFile::new( 187 Ok(ZipFileReader::new(
178 &mut self.io, 188 &mut self.io,
179 self.files.get(index).ok_or(ZipError::FileNotFound)?, 189 self.files.get(name).ok_or(ZipError::FileNotFound)?,
180 )?) 190 )?)
181 } 191 }
182} 192}
@@ -187,6 +197,8 @@ impl<Io: Read + Seek> Zip<Io> {
187 } 197 }
188} 198}
189 199
190impl<Io: Read + Write + Seek> ArchiveWrite for Zip<Io> {} 200impl<Io: Read + Write + Seek> ArchiveWrite for Zip<Io> {
201 type FileWriter<'d> = ZipFileWriter<'d, Io> where Io: 'd;
202}
191 203
192impl<Io: Read + Write + Seek> Zip<Io> {} 204impl<Io: Read + Write + Seek> Zip<Io> {}