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 archives = [ "multipart/archive_m.z01", "multipart/archive_m.z02", "multipart/archive_m.z03", "multipart/archive_m.z04", "multipart/archive_m.z05", "multipart/archive_m.z06", "multipart/archive_m.z07", "multipart/archive_m.zip" ].map(fs::read).map(Result::unwrap); let sizes = archives.iter().map(Vec::len).collect::>(); let _ = fs::remove_dir_all(output_dir); let central_directory = read_cd::from_provider( &sizes, false, |pos, length| { println!("Requested {length} bytes at {pos}"); Ok(archives[pos.disk][(pos.offset)..(pos.offset + length)].to_owned()) } ).unwrap().sort(); let current_file: RefCell> = RefCell::new(None); let mut unpacker = ZipUnpacker::new(central_directory, sizes); 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(()) }); for archive in archives { unpacker.update(archive).unwrap(); } println!("\nDone!"); }