1use std::{fs::{self, File, OpenOptions}, path::PathBuf, cell::RefCell, io::{Write, self}};
2
3use stream_unpack::zip::{ZipUnpacker, ZipDecodedData, read_cd};
4
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}