1use std::{
2 fs, io,
3 path::{Path, PathBuf},
4};
5
6use crate::{FileType, PathBufUtils};
7use zip::ZipArchive;
8
9pub struct Reader {
10 zip: ZipArchive<fs::File>,
11 files: Vec<crate::reader::File>,
12}
13
14impl Reader {
15 fn open(path: &Path, _options: crate::reader::Options) -> crate::reader::Result<Self> {
16 let file = fs::File::open(path).map_err(crate::reader::Error::OpeningInputFile)?;
17 let mut zip =
18 ZipArchive::new(file).map_err(|err| crate::reader::Error::Other(err.to_string()))?;
19
20 let mut files = Vec::new();
21
22 for index in 0..zip.len() {
23 let file = zip
24 .by_index(index)
25 .map_err(|err| crate::reader::Error::Other(err.to_string()))?;
26
27 let file_type = if file.is_dir() {
28 FileType::Directory
29 } else {
30 FileType::RegularFile
31 };
32
33 files.push(crate::reader::File {
34 name: PathBuf::from_unix(file.name()),
35 file_type,
36 size: Some(file.size()),
37 });
38 }
39
40 Ok(Self { zip, files })
41 }
42}
43
44impl crate::reader::Reader for Reader {
45 fn file_count(&self) -> usize {
46 self.files.len()
47 }
48
49 fn get_file(&self, index: usize) -> crate::reader::File {
50 let file = self
51 .files
52 .get(index)
53 .expect("should be able to get file by index");
54
55 crate::reader::File {
56 name: file.name.clone(),
57 file_type: file.file_type.clone(),
58 size: file.size,
59 }
60 }
61
62 fn create_file_reader<'a>(
63 &'a mut self,
64 index: usize,
65 ) -> crate::reader::Result<Box<dyn io::Read + 'a>> {
66 let file = self
67 .zip
68 .by_index(index)
69 .expect("should be able to get file by index");
70
71 Ok(Box::new(file))
72 }
73}
74
75pub fn make_reader(
76 path: &Path,
77 options: crate::reader::Options,
78) -> crate::reader::Result<Box<dyn crate::reader::Reader>> {
79 Ok(Box::new(Reader::open(path, options)?))
80}