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 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}