use std::io::{self, Write};
use std::path::Path;
use crate::archive::{collect_filtered_entries, compression_label, format_datetime, open_archive};
use crate::codec::EncodingKind;
use crate::error::XzipError;
use crate::filter::PathFilter;
use crate::verbosity::Verbosity;
pub fn list_archive(
input_zip: &Path,
encoding: EncodingKind,
include: &[String],
exclude: &[String],
verbosity: Verbosity,
) -> Result<(), XzipError> {
let mut archive = open_archive(input_zip)?;
let filter = PathFilter::new(include, exclude)?;
let entries = collect_filtered_entries(&mut archive, encoding, &filter)?;
let show_compressed = verbosity.is_verbose();
let show_method = verbosity.is_extra();
let mut stdout = io::stdout().lock();
write_table_header(&mut stdout, show_compressed, show_method)?;
let mut total_size = 0u64;
for entry in &entries {
if !entry.is_dir {
total_size += entry.size;
}
let (date, time) = format_datetime(entry.modified);
write_table_row(
&mut stdout,
entry.size,
&date,
&time,
&entry.name,
if show_compressed {
Some(entry.compressed_size)
} else {
None
},
if show_method {
Some(compression_label(entry.compression))
} else {
None
},
)?;
}
write_table_footer(&mut stdout, total_size, entries.len())?;
Ok(())
}
fn write_table_header(
out: &mut impl Write,
show_compressed: bool,
show_method: bool,
) -> io::Result<()> {
if show_method {
writeln!(
out,
" Length Compressed Date Time Method Name"
)?;
writeln!(
out,
"--------- ---------- ---------- ----- ------ ----"
)?;
} else if show_compressed {
writeln!(out, " Length Compressed Date Time Name")?;
writeln!(out, "--------- ---------- ---------- ----- ----")?;
} else {
writeln!(out, " Length Date Time Name")?;
writeln!(out, "--------- ---------- ----- ----")?;
}
Ok(())
}
fn write_table_row(
out: &mut impl Write,
size: u64,
date: &str,
time: &str,
name: &str,
compressed: Option<u64>,
method: Option<&str>,
) -> io::Result<()> {
if let (Some(compressed), Some(method)) = (compressed, method) {
writeln!(
out,
"{size:>9} {compressed:>10} {date} {time} {method:<6} {name}"
)?;
} else if let Some(compressed) = compressed {
writeln!(out, "{size:>9} {compressed:>10} {date} {time} {name}")?;
} else {
writeln!(out, "{size:>9} {date} {time} {name}")?;
}
Ok(())
}
fn write_table_footer(out: &mut impl Write, total_size: u64, count: usize) -> io::Result<()> {
let label = if count == 1 { "file" } else { "files" };
writeln!(out, "--------- -------")?;
writeln!(
out,
"{total_size:>9} {count} {label}"
)?;
Ok(())
}