multipart/
multipart.rs

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}