use std::{fs::{self, File, OpenOptions}, path::PathBuf, cell::RefCell, io::{Write, self}}; use stream_unpack::zip::{ZipUnpacker, ZipDecodedData, read_cd}; fn main() { let output_dir = "unpack"; let archive = fs::read("archive.zip").unwrap(); let _ = fs::remove_dir_all(output_dir); let central_directory = read_cd::from_provider( vec![archive.len()], false, |pos, length| { println!("Requested {length} bytes at {pos}"); Ok(archive[(pos.offset)..(pos.offset + length)].to_owned()) } ).unwrap().sort(); let current_file: RefCell> = RefCell::new(None); let mut unpacker = ZipUnpacker::new(central_directory, vec![archive.len()]); unpacker.set_callback(|data| { match data { ZipDecodedData::FileHeader(cdfh, _) => { println!(); let mut path = PathBuf::from(output_dir); path.push(&cdfh.filename); if !cdfh.is_directory() { print!("New file: {}", cdfh.filename); io::stdout().flush()?; fs::create_dir_all(path.parent().unwrap())?; *current_file.borrow_mut() = Some( OpenOptions::new() .create(true) .write(true) .open(path)? ); } else { print!("New directory: {}", cdfh.filename); io::stdout().flush()?; fs::create_dir_all(path)?; } }, ZipDecodedData::FileData(data) => { print!("."); io::stdout().flush()?; current_file.borrow().as_ref().unwrap().write_all(data)?; } } Ok(()) }); unpacker.update(archive).unwrap(); println!("\nDone!"); }