aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Tolmachev <me@igorek.dev>2024-07-14 17:15:24 +0900
committerIgor Tolmachev <me@igorek.dev>2024-07-14 17:15:24 +0900
commitd515e20a26cc959db912504706189ad1cce9dbfa (patch)
tree9abaab23fc8e90e335f3f44d20f60bc2d0f28926
parent75f4a84e977a1f409e6580056dc31343e15bbf3e (diff)
downloadarchivator-d515e20a26cc959db912504706189ad1cce9dbfa.tar.gz
archivator-d515e20a26cc959db912504706189ad1cce9dbfa.zip
Add file indexation
-rw-r--r--src/archive.rs33
-rw-r--r--src/driver/driver.rs11
-rw-r--r--src/zip/driver.rs66
-rw-r--r--tests/zip.rs12
4 files changed, 77 insertions, 45 deletions
diff --git a/src/archive.rs b/src/archive.rs
index 2dab393..e17db80 100644
--- a/src/archive.rs
+++ b/src/archive.rs
@@ -18,6 +18,7 @@ where
18 }) 18 })
19 } 19 }
20 20
21 #[inline]
21 pub fn read_from_file(path: impl AsRef<Path>) -> ArchiveResult<Self, D::Error> 22 pub fn read_from_file(path: impl AsRef<Path>) -> ArchiveResult<Self, D::Error>
22 where 23 where
23 D: ArchiveRead<Io = File>, 24 D: ArchiveRead<Io = File>,
@@ -25,19 +26,41 @@ where
25 Self::read(File::open(path)?) 26 Self::read(File::open(path)?)
26 } 27 }
27 28
28 pub fn files(&self) -> Vec<&D::FileInfo> { 29 pub fn files(&self) -> &Vec<D::FileInfo> {
29 self.driver.files() 30 self.driver.files()
30 } 31 }
31 32
32 pub fn get_file_info(&self, name: &str) -> ArchiveResult<&D::FileInfo, D::Error> { 33 #[inline]
33 self.driver.get_file_info(name) 34 pub fn len(&self) -> usize {
35 self.files().len()
34 } 36 }
35 37
36 pub fn get_file_reader<'d>( 38 pub fn get_file_index(&self, name: &str) -> ArchiveResult<usize, D::Error> {
39 self.driver.get_file_index(name)
40 }
41
42 pub fn get_file_info_by_index(&self, index: usize) -> ArchiveResult<&D::FileInfo, D::Error> {
43 self.driver.get_file_info(index)
44 }
45
46 #[inline]
47 pub fn get_file_info_by_name(&self, name: &str) -> ArchiveResult<&D::FileInfo, D::Error> {
48 self.get_file_info_by_index(self.get_file_index(name)?)
49 }
50
51 pub fn get_file_reader_by_index<'d>(
52 &'d mut self,
53 index: usize,
54 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> {
55 Ok(ArchiveFile::new(self.driver.get_file_reader(index)?))
56 }
57
58 #[inline]
59 pub fn get_file_reader_by_name<'d>(
37 &'d mut self, 60 &'d mut self,
38 name: &str, 61 name: &str,
39 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> { 62 ) -> ArchiveResult<ArchiveFile<D::FileReader<'d>>, D::Error> {
40 Ok(ArchiveFile::new(self.driver.get_file_reader(name)?)) 63 self.get_file_reader_by_index(self.get_file_index(name)?)
41 } 64 }
42} 65}
43 66
diff --git a/src/driver/driver.rs b/src/driver/driver.rs
index f7f1f24..747345c 100644
--- a/src/driver/driver.rs
+++ b/src/driver/driver.rs
@@ -21,16 +21,19 @@ where
21 // Create driver instance 21 // Create driver instance
22 fn read(io: Self::Io) -> ArchiveResult<Self, Self::Error>; 22 fn read(io: Self::Io) -> ArchiveResult<Self, Self::Error>;
23 23
24 // Return vec of file info 24 // Return vec of file infos
25 fn files(&self) -> Vec<&Self::FileInfo>; 25 fn files(&self) -> &Vec<Self::FileInfo>;
26
27 // Return file index by name
28 fn get_file_index(&self, name: &str) -> ArchiveResult<usize, Self::Error>;
26 29
27 // Return file info by index 30 // Return file info by index
28 fn get_file_info(&self, name: &str) -> ArchiveResult<&Self::FileInfo, Self::Error>; 31 fn get_file_info(&self, index: usize) -> ArchiveResult<&Self::FileInfo, Self::Error>;
29 32
30 // Return file reader by index 33 // Return file reader by index
31 fn get_file_reader<'d>( 34 fn get_file_reader<'d>(
32 &'d mut self, 35 &'d mut self,
33 name: &str, 36 index: usize,
34 ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>; 37 ) -> ArchiveResult<Self::FileReader<'d>, Self::Error>;
35} 38}
36 39
diff --git a/src/zip/driver.rs b/src/zip/driver.rs
index 4782e65..0905d9a 100644
--- a/src/zip/driver.rs
+++ b/src/zip/driver.rs
@@ -6,7 +6,7 @@ use crate::zip::{
6 BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult, 6 BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult,
7}; 7};
8use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime}; 8use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime};
9use std::collections::BTreeMap as Map; 9use std::collections::HashMap as Map;
10use std::fs::File; 10use std::fs::File;
11use std::io::{Read, Seek, SeekFrom, Write}; 11use std::io::{Read, Seek, SeekFrom, Write};
12 12
@@ -47,7 +47,8 @@ fn timestamp_to_local(time: i32) -> ZipResult<DateTime<Local>> {
47pub struct Zip<Io = File> { 47pub struct Zip<Io = File> {
48 io: Io, 48 io: Io,
49 49
50 files: Map<String, ZipFileInfo>, 50 indexes: Map<String, usize>,
51 files: Vec<ZipFileInfo>,
51 comment: String, 52 comment: String,
52} 53}
53 54
@@ -106,12 +107,13 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
106 }; 107 };
107 108
108 // Read cd records 109 // Read cd records
109 let mut files = Map::new(); 110 let mut indexes = Map::with_capacity(cd_records as usize);
111 let mut files = Vec::with_capacity(cd_records as usize);
110 io.seek(SeekFrom::Start(cd_pointer))?; 112 io.seek(SeekFrom::Start(cd_pointer))?;
111 let buf = io.read_vec(cd_size as usize)?; 113 let buf = io.read_vec(cd_size as usize)?;
112 114
113 let mut p: usize = 0; 115 let mut p: usize = 0;
114 for _ in 0..cd_records { 116 for i in 0..cd_records as usize {
115 if u32::from_le_bytes(buf[p..p + 4].try_into().unwrap()) != 0x02014b50 { 117 if u32::from_le_bytes(buf[p..p + 4].try_into().unwrap()) != 0x02014b50 {
116 return Err(ZipError::InvalidCDRSignature.into()); 118 return Err(ZipError::InvalidCDRSignature.into());
117 } 119 }
@@ -215,39 +217,49 @@ impl<Io: Read + Seek> ArchiveRead for Zip<Io> {
215 } 217 }
216 } 218 }
217 219
218 files.insert( 220 indexes.insert(name.clone(), i);
219 name.clone(), 221 files.push(ZipFileInfo::new(
220 ZipFileInfo::new( 222 CompressionMethod::from_struct_id(cdr.compression_method)?,
221 CompressionMethod::from_struct_id(cdr.compression_method)?, 223 bit_flag,
222 bit_flag, 224 mtime,
223 mtime, 225 atime,
224 atime, 226 ctime,
225 ctime, 227 cdr.crc,
226 cdr.crc, 228 compressed_size,
227 compressed_size, 229 size,
228 size, 230 header_pointer,
229 header_pointer, 231 name,
230 name, 232 comment,
231 comment, 233 ));
232 ),
233 );
234 } 234 }
235 235
236 Ok(Self { io, files, comment }) 236 Ok(Self {
237 io,
238 indexes,
239 files,
240 comment,
241 })
237 } 242 }
238 243
239 fn files(&self) -> Vec<&Self::FileInfo> { 244 fn files(&self) -> &Vec<Self::FileInfo> {
240 self.files.values().collect() 245 &self.files
241 } 246 }
242 247
243 fn get_file_info(&self, name: &str) -> ZipResult<&Self::FileInfo> { 248 fn get_file_index(&self, name: &str) -> crate::ArchiveResult<usize, Self::Error> {
244 self.files.get(name).ok_or(ZipError::FileNotFound.into()) 249 self.indexes
250 .get(name)
251 .ok_or(ZipError::FileNotFound.into())
252 .copied()
245 } 253 }
246 254
247 fn get_file_reader<'d>(&'d mut self, name: &str) -> ZipResult<Self::FileReader<'d>> { 255 fn get_file_info(&self, index: usize) -> ZipResult<&Self::FileInfo> {
256 self.files.get(index).ok_or(ZipError::FileNotFound.into())
257 }
258
259 fn get_file_reader<'d>(&'d mut self, index: usize) -> ZipResult<Self::FileReader<'d>> {
248 Ok(ZipFileReader::new( 260 Ok(ZipFileReader::new(
249 &mut self.io, 261 &mut self.io,
250 self.files.get(name).ok_or(ZipError::FileNotFound)?, 262 self.files.get(index).ok_or(ZipError::FileNotFound)?,
251 )?) 263 )?)
252 } 264 }
253} 265}
diff --git a/tests/zip.rs b/tests/zip.rs
index b9291fc..1e919d3 100644
--- a/tests/zip.rs
+++ b/tests/zip.rs
@@ -15,7 +15,7 @@ fn test_zip() {
15 vec!["bzip", "deflate", "lzma", "store", "xz", "zstd"] 15 vec!["bzip", "deflate", "lzma", "store", "xz", "zstd"]
16 ); 16 );
17 17
18 let mut f = archive.get_file_reader("store").unwrap(); 18 let mut f = archive.get_file_reader_by_name("store").unwrap();
19 19
20 let mut data = String::new(); 20 let mut data = String::new();
21 f.read_to_string(&mut data).unwrap(); 21 f.read_to_string(&mut data).unwrap();
@@ -48,14 +48,8 @@ fn test_zip() {
48 48
49 assert_eq!(f.seek(SeekFrom::Start(100)).unwrap(), 14); 49 assert_eq!(f.seek(SeekFrom::Start(100)).unwrap(), 14);
50 50
51 for name in archive 51 for index in 0..archive.len() {
52 .files() 52 let mut f = archive.get_file_reader_by_index(index).unwrap();
53 .iter()
54 .map(|f| f.name.clone())
55 .collect::<Vec<_>>()
56 {
57 let mut f = archive.get_file_reader(&name).unwrap();
58
59 let mut data = String::new(); 53 let mut data = String::new();
60 f.read_to_string(&mut data).unwrap(); 54 f.read_to_string(&mut data).unwrap();
61 assert_eq!(data, "test file data"); 55 assert_eq!(data, "test file data");