From d515e20a26cc959db912504706189ad1cce9dbfa Mon Sep 17 00:00:00 2001 From: Igor Tolmachev Date: Sun, 14 Jul 2024 17:15:24 +0900 Subject: Add file indexation --- src/archive.rs | 33 ++++++++++++++++++++++---- src/driver/driver.rs | 11 +++++---- src/zip/driver.rs | 66 +++++++++++++++++++++++++++++++--------------------- tests/zip.rs | 12 +++------- 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 }) } + #[inline] pub fn read_from_file(path: impl AsRef) -> ArchiveResult where D: ArchiveRead, @@ -25,19 +26,41 @@ where Self::read(File::open(path)?) } - pub fn files(&self) -> Vec<&D::FileInfo> { + pub fn files(&self) -> &Vec { self.driver.files() } - pub fn get_file_info(&self, name: &str) -> ArchiveResult<&D::FileInfo, D::Error> { - self.driver.get_file_info(name) + #[inline] + pub fn len(&self) -> usize { + self.files().len() } - pub fn get_file_reader<'d>( + pub fn get_file_index(&self, name: &str) -> ArchiveResult { + self.driver.get_file_index(name) + } + + pub fn get_file_info_by_index(&self, index: usize) -> ArchiveResult<&D::FileInfo, D::Error> { + self.driver.get_file_info(index) + } + + #[inline] + pub fn get_file_info_by_name(&self, name: &str) -> ArchiveResult<&D::FileInfo, D::Error> { + self.get_file_info_by_index(self.get_file_index(name)?) + } + + pub fn get_file_reader_by_index<'d>( + &'d mut self, + index: usize, + ) -> ArchiveResult>, D::Error> { + Ok(ArchiveFile::new(self.driver.get_file_reader(index)?)) + } + + #[inline] + pub fn get_file_reader_by_name<'d>( &'d mut self, name: &str, ) -> ArchiveResult>, D::Error> { - Ok(ArchiveFile::new(self.driver.get_file_reader(name)?)) + self.get_file_reader_by_index(self.get_file_index(name)?) } } 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 // Create driver instance fn read(io: Self::Io) -> ArchiveResult; - // Return vec of file info - fn files(&self) -> Vec<&Self::FileInfo>; + // Return vec of file infos + fn files(&self) -> &Vec; + + // Return file index by name + fn get_file_index(&self, name: &str) -> ArchiveResult; // Return file info by index - fn get_file_info(&self, name: &str) -> ArchiveResult<&Self::FileInfo, Self::Error>; + fn get_file_info(&self, index: usize) -> ArchiveResult<&Self::FileInfo, Self::Error>; // Return file reader by index fn get_file_reader<'d>( &'d mut self, - name: &str, + index: usize, ) -> ArchiveResult, Self::Error>; } 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::{ BitFlag, CompressionMethod, ZipError, ZipFileInfo, ZipFileReader, ZipFileWriter, ZipResult, }; use chrono::{DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime}; -use std::collections::BTreeMap as Map; +use std::collections::HashMap as Map; use std::fs::File; use std::io::{Read, Seek, SeekFrom, Write}; @@ -47,7 +47,8 @@ fn timestamp_to_local(time: i32) -> ZipResult> { pub struct Zip { io: Io, - files: Map, + indexes: Map, + files: Vec, comment: String, } @@ -106,12 +107,13 @@ impl ArchiveRead for Zip { }; // Read cd records - let mut files = Map::new(); + let mut indexes = Map::with_capacity(cd_records as usize); + let mut files = Vec::with_capacity(cd_records as usize); io.seek(SeekFrom::Start(cd_pointer))?; let buf = io.read_vec(cd_size as usize)?; let mut p: usize = 0; - for _ in 0..cd_records { + for i in 0..cd_records as usize { if u32::from_le_bytes(buf[p..p + 4].try_into().unwrap()) != 0x02014b50 { return Err(ZipError::InvalidCDRSignature.into()); } @@ -215,39 +217,49 @@ impl ArchiveRead for Zip { } } - files.insert( - name.clone(), - ZipFileInfo::new( - CompressionMethod::from_struct_id(cdr.compression_method)?, - bit_flag, - mtime, - atime, - ctime, - cdr.crc, - compressed_size, - size, - header_pointer, - name, - comment, - ), - ); + indexes.insert(name.clone(), i); + files.push(ZipFileInfo::new( + CompressionMethod::from_struct_id(cdr.compression_method)?, + bit_flag, + mtime, + atime, + ctime, + cdr.crc, + compressed_size, + size, + header_pointer, + name, + comment, + )); } - Ok(Self { io, files, comment }) + Ok(Self { + io, + indexes, + files, + comment, + }) } - fn files(&self) -> Vec<&Self::FileInfo> { - self.files.values().collect() + fn files(&self) -> &Vec { + &self.files } - fn get_file_info(&self, name: &str) -> ZipResult<&Self::FileInfo> { - self.files.get(name).ok_or(ZipError::FileNotFound.into()) + fn get_file_index(&self, name: &str) -> crate::ArchiveResult { + self.indexes + .get(name) + .ok_or(ZipError::FileNotFound.into()) + .copied() } - fn get_file_reader<'d>(&'d mut self, name: &str) -> ZipResult> { + fn get_file_info(&self, index: usize) -> ZipResult<&Self::FileInfo> { + self.files.get(index).ok_or(ZipError::FileNotFound.into()) + } + + fn get_file_reader<'d>(&'d mut self, index: usize) -> ZipResult> { Ok(ZipFileReader::new( &mut self.io, - self.files.get(name).ok_or(ZipError::FileNotFound)?, + self.files.get(index).ok_or(ZipError::FileNotFound)?, )?) } } 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() { vec!["bzip", "deflate", "lzma", "store", "xz", "zstd"] ); - let mut f = archive.get_file_reader("store").unwrap(); + let mut f = archive.get_file_reader_by_name("store").unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); @@ -48,14 +48,8 @@ fn test_zip() { assert_eq!(f.seek(SeekFrom::Start(100)).unwrap(), 14); - for name in archive - .files() - .iter() - .map(|f| f.name.clone()) - .collect::>() - { - let mut f = archive.get_file_reader(&name).unwrap(); - + for index in 0..archive.len() { + let mut f = archive.get_file_reader_by_index(index).unwrap(); let mut data = String::new(); f.read_to_string(&mut data).unwrap(); assert_eq!(data, "test file data"); -- cgit v1.2.3