1#[cfg(feature = "zip")]
2pub use self::zip::Zip;
3
4#[cfg(feature = "zip")]
5mod zip {
6 use std::fs::{create_dir_all, File};
7 use std::io::{copy, Read, Seek};
8 use std::path::Path;
9
10 use zip::ZipArchive;
11
12 use crate::{Archive, ArchiverError, Result};
13
14 pub struct Zip<R: Read + Seek> {
15 archive: ZipArchive<R>,
16 }
17
18 impl Zip<File> {
19 pub fn open(path: &Path) -> std::io::Result<Self> {
20 let archive = File::open(path)?;
21
22 Self::new(archive)
23 }
24 }
25
26 impl<R: Read + Seek> Zip<R> {
27 pub fn new(r: R) -> std::io::Result<Self> {
28 let archive = ZipArchive::new(r)?;
29
30 Ok(Self { archive })
31 }
32 }
33
34 impl<R: Read + Seek> Archive for Zip<R> {
35 fn contains(&mut self, file: String) -> Result<bool> {
36 let result = match self.archive.by_name(&file) {
37 Ok(_) => true,
38 Err(_) => false,
39 };
40
41 Ok(result)
42 }
43
44 fn extract(&mut self, destination: &Path) -> Result<()> {
45 for i in 0..self.archive.len() {
46 let mut file = self.archive.by_index(i).unwrap();
47 let target = file.mangled_name();
48 let target = destination.join(target);
49
50 if (&*file.name()).ends_with('/') {
51 create_dir_all(target)?;
52 } else {
53 if let Some(p) = target.parent() {
54 if !p.exists() {
55 create_dir_all(&p)?;
56 }
57 }
58 let mut outfile = File::create(target)?;
59 copy(&mut file, &mut outfile)?;
60 }
61 }
62
63 Ok(())
64 }
65
66 fn extract_single(&mut self, target: &Path, file: String) -> Result<()> {
67 if let Some(p) = target.parent() {
68 if !p.exists() {
69 create_dir_all(&p)?;
70 }
71 }
72
73 let mut f = self
74 .archive
75 .by_name(&file)
76 .map_err(|_| ArchiverError::NotFound)?;
77
78 let mut target = File::create(target)?;
79 copy(&mut f, &mut target)?;
80
81 return Ok(());
82 }
83
84 fn files(&mut self) -> Result<Vec<String>> {
85 let files = self.archive.file_names().map(|e| e.into()).collect();
86
87 Ok(files)
88 }
89
90 fn walk(&mut self, f: Box<dyn Fn(String) -> Option<String>>) -> Result<()> {
91 let files = self.files()?;
92
93 for file in files {
94 if let Some(f) = f(file.clone()) {
95 self.extract_single(Path::new(&f), file.clone())?;
96 }
97 }
98
99 Ok(())
100 }
101 }
102}