1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
extern crate zip;
extern crate time;
extern crate transformation_pipeline;
mod transformation_metadata;
use std::io;
use std::io::prelude::Read;
use std::fs;
use std::path::{Path, PathBuf};
use transformation_pipeline::TransformationPipeline;
use transformation_metadata::ExtractionMetadata;
mod strip_components;
use strip_components::StripComponents;
pub struct UnzipperStats {
dirs: u16,
files: u16,
}
type UnzipperResult = Result<UnzipperStats, io::Error>;
pub struct Unzipper<R: Read + io::Seek, O: AsRef<Path>> {
source: R,
outdir: O,
strip_components: u8,
}
impl<R: Read + io::Seek, O: AsRef<Path>> Unzipper<R, O> {
pub fn new(reader: R, output: O) -> Unzipper<R, O> {
Unzipper {
source: reader,
outdir: output,
strip_components: 0,
}
}
pub fn strip_components(mut self, num: u8) -> Unzipper<R, O> {
self.strip_components = num;
self
}
pub fn unzip(self) -> UnzipperResult {
let mut archive = zip::ZipArchive::new(self.source)?;
let outdir: &Path = Path::new(self.outdir.as_ref());
let mut stats = UnzipperStats {
dirs: 0,
files: 0,
};
let pipeline: TransformationPipeline<ExtractionMetadata> = TransformationPipeline::new(vec![
Box::new(StripComponents::new(self.strip_components)),
]);
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let metadata = pipeline.run(ExtractionMetadata {
extract: true,
filename: file.name().to_owned(),
comment: file.comment().to_owned(),
compressed_size: file.compressed_size(),
uncompressed_size: file.size(),
crc32: file.crc32(),
data_start: file.data_start(),
last_modified: file.last_modified(),
unix_mode: file.unix_mode(),
})?;
if !metadata.extract {
continue;
}
let outpath: PathBuf = outdir.join(metadata.filename);
if let Some(parent_dir) = outpath.as_path().parent() {
fs::create_dir_all(&parent_dir)?;
}
if (&*file.name()).ends_with('/') {
stats.dirs = stats.dirs + 1;
continue;
}
let mut outfile = fs::File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
stats.files = stats.files + 1;
}
Ok(stats)
}
}