#![allow(clippy::doc_markdown)]
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::process::ExitCode;
use zipatch_rs::chunk::SqpkCommand;
use zipatch_rs::{Chunk, open_patch};
fn main() -> ExitCode {
let Some(path) = std::env::args_os().nth(1).map(PathBuf::from) else {
eprintln!("usage: parse_summary <path/to/file.patch>");
return ExitCode::from(2);
};
let mut reader = match open_patch(&path) {
Ok(r) => r,
Err(e) => {
eprintln!("failed to open {}: {e}", path.display());
return ExitCode::FAILURE;
}
};
let mut counts: BTreeMap<&'static str, u64> = BTreeMap::new();
let mut total: u64 = 0;
loop {
let rec = match reader.next_chunk() {
Ok(Some(rec)) => rec,
Ok(None) => break,
Err(e) => {
eprintln!("parse error after {total} chunks: {e}");
return ExitCode::FAILURE;
}
};
total += 1;
*counts.entry(chunk_label(&rec.chunk)).or_insert(0) += 1;
}
println!("file: {}", path.display());
println!("total chunks: {total}");
println!();
println!("{:<32} {:>10}", "variant", "count");
println!("{:-<32} {:->10}", "", "");
for (label, count) in &counts {
println!("{label:<32} {count:>10}");
}
ExitCode::SUCCESS
}
fn chunk_label(chunk: &Chunk) -> &'static str {
match chunk {
Chunk::FileHeader(_) => "FileHeader",
Chunk::ApplyOption(_) => "ApplyOption",
Chunk::ApplyFreeSpace(_) => "ApplyFreeSpace",
Chunk::AddDirectory(_) => "AddDirectory",
Chunk::DeleteDirectory(_) => "DeleteDirectory",
Chunk::Sqpk(cmd) => match cmd {
SqpkCommand::AddData(_) => "Sqpk::AddData",
SqpkCommand::DeleteData(_) => "Sqpk::DeleteData",
SqpkCommand::ExpandData(_) => "Sqpk::ExpandData",
SqpkCommand::Header(_) => "Sqpk::Header",
SqpkCommand::TargetInfo(_) => "Sqpk::TargetInfo",
SqpkCommand::File(_) => "Sqpk::File",
SqpkCommand::Index(_) => "Sqpk::Index",
SqpkCommand::PatchInfo(_) => "Sqpk::PatchInfo",
},
Chunk::EndOfFile => "EndOfFile",
}
}