pub struct ZipUnpacker<'a> { /* private fields */ }Expand description
A stream unpacker for ZIP archives
Implementations§
Source§impl<'a> ZipUnpacker<'a>
impl<'a> ZipUnpacker<'a>
Sourcepub fn new(
central_directory: SortedCentralDirectory,
disk_sizes: Vec<usize>,
) -> Self
pub fn new( central_directory: SortedCentralDirectory, disk_sizes: Vec<usize>, ) -> Self
Creates a new ZipUnpacker
The easiest way to obtain a central directory object is to use read_cd::from_provider. “disk_sizes” must only contain one element if the archive is a cut one, and not a real split one.
Examples found in repository?
5fn main() {
6 let output_dir = "unpack";
7 let archive = fs::read("archive.zip").unwrap();
8 let _ = fs::remove_dir_all(output_dir);
9
10 let central_directory = read_cd::from_provider(
11 vec![archive.len()],
12 false,
13 |pos, length| {
14 println!("Requested {length} bytes at {pos}");
15 Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16 }
17 ).unwrap().sort();
18
19 let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21 let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22 unpacker.set_callback(|data| {
23 match data {
24 ZipDecodedData::FileHeader(cdfh, _) => {
25 println!();
26
27 let mut path = PathBuf::from(output_dir);
28 path.push(&cdfh.filename);
29
30 if !cdfh.is_directory() {
31 print!("New file: {}", cdfh.filename);
32 io::stdout().flush()?;
33
34 fs::create_dir_all(path.parent().unwrap())?;
35
36 *current_file.borrow_mut() = Some(
37 OpenOptions::new()
38 .create(true)
39 .write(true)
40 .open(path)?
41 );
42 } else {
43 print!("New directory: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path)?;
47 }
48 },
49
50 ZipDecodedData::FileData(data) => {
51 print!(".");
52 io::stdout().flush()?;
53
54 current_file.borrow().as_ref().unwrap().write_all(data)?;
55 }
56 }
57
58 Ok(())
59 });
60
61 unpacker.update(archive).unwrap();
62
63 println!("\nDone!");
64}More examples
5fn main() {
6 let output_dir = "unpack";
7
8 let archives = [
9 "multipart/archive_m.z01",
10 "multipart/archive_m.z02",
11 "multipart/archive_m.z03",
12 "multipart/archive_m.z04",
13 "multipart/archive_m.z05",
14 "multipart/archive_m.z06",
15 "multipart/archive_m.z07",
16 "multipart/archive_m.zip"
17 ].map(fs::read).map(Result::unwrap);
18 let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20 let _ = fs::remove_dir_all(output_dir);
21
22 let central_directory = read_cd::from_provider(
23 &sizes,
24 false,
25 |pos, length| {
26 println!("Requested {length} bytes at {pos}");
27 Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28 }
29 ).unwrap().sort();
30
31 let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33 let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34 unpacker.set_callback(|data| {
35 match data {
36 ZipDecodedData::FileHeader(cdfh, _) => {
37 println!();
38
39 let mut path = PathBuf::from(output_dir);
40 path.push(&cdfh.filename);
41
42 if !cdfh.is_directory() {
43 print!("New file: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path.parent().unwrap())?;
47
48 *current_file.borrow_mut() = Some(
49 OpenOptions::new()
50 .create(true)
51 .write(true)
52 .open(path)?
53 );
54 } else {
55 print!("New directory: {}", cdfh.filename);
56 io::stdout().flush()?;
57
58 fs::create_dir_all(path)?;
59 }
60 },
61
62 ZipDecodedData::FileData(data) => {
63 print!(".");
64 io::stdout().flush()?;
65
66 current_file.borrow().as_ref().unwrap().write_all(data)?;
67 }
68 }
69
70 Ok(())
71 });
72
73 for archive in archives {
74 unpacker.update(archive).unwrap();
75 }
76
77 println!("\nDone!");
78}Sourcepub fn resume(
central_directory: SortedCentralDirectory,
disk_sizes: Vec<usize>,
position: ZipPosition,
) -> Result<Self, DecoderError>
pub fn resume( central_directory: SortedCentralDirectory, disk_sizes: Vec<usize>, position: ZipPosition, ) -> Result<Self, DecoderError>
Creates a new ZipUnpacker, starting from the specified position. If the archive is not actually split, you must set disk number to 0 and use the absolute offset, even if there are multiple files
The easiest way to obtain a central directory object is to use read_cd::from_provider. “disk_sizes” must only contain one element if the archive is a cut one, and not a real split one.
Sourcepub fn set_callback(
&mut self,
on_decode: impl Fn(ZipDecodedData<'_>) -> Result<()> + 'a,
)
pub fn set_callback( &mut self, on_decode: impl Fn(ZipDecodedData<'_>) -> Result<()> + 'a, )
Sets the decode callback. The passed closure will be invoked when new data is decoded from bytes passed to ZipUnpacker::update
Examples found in repository?
5fn main() {
6 let output_dir = "unpack";
7 let archive = fs::read("archive.zip").unwrap();
8 let _ = fs::remove_dir_all(output_dir);
9
10 let central_directory = read_cd::from_provider(
11 vec![archive.len()],
12 false,
13 |pos, length| {
14 println!("Requested {length} bytes at {pos}");
15 Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16 }
17 ).unwrap().sort();
18
19 let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21 let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22 unpacker.set_callback(|data| {
23 match data {
24 ZipDecodedData::FileHeader(cdfh, _) => {
25 println!();
26
27 let mut path = PathBuf::from(output_dir);
28 path.push(&cdfh.filename);
29
30 if !cdfh.is_directory() {
31 print!("New file: {}", cdfh.filename);
32 io::stdout().flush()?;
33
34 fs::create_dir_all(path.parent().unwrap())?;
35
36 *current_file.borrow_mut() = Some(
37 OpenOptions::new()
38 .create(true)
39 .write(true)
40 .open(path)?
41 );
42 } else {
43 print!("New directory: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path)?;
47 }
48 },
49
50 ZipDecodedData::FileData(data) => {
51 print!(".");
52 io::stdout().flush()?;
53
54 current_file.borrow().as_ref().unwrap().write_all(data)?;
55 }
56 }
57
58 Ok(())
59 });
60
61 unpacker.update(archive).unwrap();
62
63 println!("\nDone!");
64}More examples
5fn main() {
6 let output_dir = "unpack";
7
8 let archives = [
9 "multipart/archive_m.z01",
10 "multipart/archive_m.z02",
11 "multipart/archive_m.z03",
12 "multipart/archive_m.z04",
13 "multipart/archive_m.z05",
14 "multipart/archive_m.z06",
15 "multipart/archive_m.z07",
16 "multipart/archive_m.zip"
17 ].map(fs::read).map(Result::unwrap);
18 let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20 let _ = fs::remove_dir_all(output_dir);
21
22 let central_directory = read_cd::from_provider(
23 &sizes,
24 false,
25 |pos, length| {
26 println!("Requested {length} bytes at {pos}");
27 Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28 }
29 ).unwrap().sort();
30
31 let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33 let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34 unpacker.set_callback(|data| {
35 match data {
36 ZipDecodedData::FileHeader(cdfh, _) => {
37 println!();
38
39 let mut path = PathBuf::from(output_dir);
40 path.push(&cdfh.filename);
41
42 if !cdfh.is_directory() {
43 print!("New file: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path.parent().unwrap())?;
47
48 *current_file.borrow_mut() = Some(
49 OpenOptions::new()
50 .create(true)
51 .write(true)
52 .open(path)?
53 );
54 } else {
55 print!("New directory: {}", cdfh.filename);
56 io::stdout().flush()?;
57
58 fs::create_dir_all(path)?;
59 }
60 },
61
62 ZipDecodedData::FileData(data) => {
63 print!(".");
64 io::stdout().flush()?;
65
66 current_file.borrow().as_ref().unwrap().write_all(data)?;
67 }
68 }
69
70 Ok(())
71 });
72
73 for archive in archives {
74 unpacker.update(archive).unwrap();
75 }
76
77 println!("\nDone!");
78}Sourcepub fn update(
&mut self,
data: impl AsRef<[u8]>,
) -> Result<(usize, bool), DecoderError>
pub fn update( &mut self, data: impl AsRef<[u8]>, ) -> Result<(usize, bool), DecoderError>
Update this ZipUnpacker with new bytes. The callback may or may not be fired, depending on the content. The callback may be fired multiple times.
The first return value is how much the caller should advance the input buffer (0 means that there wasn’t enough data in the buffer and the caller should provide more), and the second value determines whether all files were processed (which means that the caller should stop providing data)
Examples found in repository?
5fn main() {
6 let output_dir = "unpack";
7 let archive = fs::read("archive.zip").unwrap();
8 let _ = fs::remove_dir_all(output_dir);
9
10 let central_directory = read_cd::from_provider(
11 vec![archive.len()],
12 false,
13 |pos, length| {
14 println!("Requested {length} bytes at {pos}");
15 Ok(archive[(pos.offset)..(pos.offset + length)].to_owned())
16 }
17 ).unwrap().sort();
18
19 let current_file: RefCell<Option<File>> = RefCell::new(None);
20
21 let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]);
22 unpacker.set_callback(|data| {
23 match data {
24 ZipDecodedData::FileHeader(cdfh, _) => {
25 println!();
26
27 let mut path = PathBuf::from(output_dir);
28 path.push(&cdfh.filename);
29
30 if !cdfh.is_directory() {
31 print!("New file: {}", cdfh.filename);
32 io::stdout().flush()?;
33
34 fs::create_dir_all(path.parent().unwrap())?;
35
36 *current_file.borrow_mut() = Some(
37 OpenOptions::new()
38 .create(true)
39 .write(true)
40 .open(path)?
41 );
42 } else {
43 print!("New directory: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path)?;
47 }
48 },
49
50 ZipDecodedData::FileData(data) => {
51 print!(".");
52 io::stdout().flush()?;
53
54 current_file.borrow().as_ref().unwrap().write_all(data)?;
55 }
56 }
57
58 Ok(())
59 });
60
61 unpacker.update(archive).unwrap();
62
63 println!("\nDone!");
64}More examples
5fn main() {
6 let output_dir = "unpack";
7
8 let archives = [
9 "multipart/archive_m.z01",
10 "multipart/archive_m.z02",
11 "multipart/archive_m.z03",
12 "multipart/archive_m.z04",
13 "multipart/archive_m.z05",
14 "multipart/archive_m.z06",
15 "multipart/archive_m.z07",
16 "multipart/archive_m.zip"
17 ].map(fs::read).map(Result::unwrap);
18 let sizes = archives.iter().map(Vec::len).collect::<Vec<_>>();
19
20 let _ = fs::remove_dir_all(output_dir);
21
22 let central_directory = read_cd::from_provider(
23 &sizes,
24 false,
25 |pos, length| {
26 println!("Requested {length} bytes at {pos}");
27 Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned())
28 }
29 ).unwrap().sort();
30
31 let current_file: RefCell<Option<File>> = RefCell::new(None);
32
33 let mut unpacker = ZipUnpacker::new(central_directory, sizes);
34 unpacker.set_callback(|data| {
35 match data {
36 ZipDecodedData::FileHeader(cdfh, _) => {
37 println!();
38
39 let mut path = PathBuf::from(output_dir);
40 path.push(&cdfh.filename);
41
42 if !cdfh.is_directory() {
43 print!("New file: {}", cdfh.filename);
44 io::stdout().flush()?;
45
46 fs::create_dir_all(path.parent().unwrap())?;
47
48 *current_file.borrow_mut() = Some(
49 OpenOptions::new()
50 .create(true)
51 .write(true)
52 .open(path)?
53 );
54 } else {
55 print!("New directory: {}", cdfh.filename);
56 io::stdout().flush()?;
57
58 fs::create_dir_all(path)?;
59 }
60 },
61
62 ZipDecodedData::FileData(data) => {
63 print!(".");
64 io::stdout().flush()?;
65
66 current_file.borrow().as_ref().unwrap().write_all(data)?;
67 }
68 }
69
70 Ok(())
71 });
72
73 for archive in archives {
74 unpacker.update(archive).unwrap();
75 }
76
77 println!("\nDone!");
78}