unshield 0.2.0

Extract files from InstallShield Z archives.
Documentation
use std::fs::File;
use std::io::{Result, Write};
use std::path::{Path, PathBuf};

fn help(cmd: &str) {
    let basename = Path::new(cmd).file_name().unwrap().to_str().unwrap();
    eprintln!("Usage:");
    eprintln!("  {} list <ARCHIVE>", basename);
    eprintln!("  {} extract [--raw] <ARCHIVE> <DESTINATION>", basename);
}

fn list(archive: &str) -> Result<()> {
    let file = File::open(archive)?;
    let ar = unshield::Archive::new(file)?;
    for file in ar.list() {
        println!("{}\t{}", file.size, file.path);
    }
    Ok(())
}

fn extract(archive: &str, destination: &str, raw: bool) -> Result<()> {
    let file = File::open(archive)?;
    let mut ar = unshield::Archive::new(file)?;
    let files: Vec<unshield::FileInfo> = ar.list().cloned().collect();
    for file in files {
        let mut dest = PathBuf::new();
        dest.push(destination);
        for part in file.path.split('\\') {
            dest.push(part);
        }

        eprintln!("{}", dest.to_str().unwrap());
        if let Some(parent) = dest.parent() {
            std::fs::create_dir_all(parent)?;
        }
        let mut f = File::create(dest)?;

        if raw {
            let data = ar.load_compressed(&file.path)?;
            f.write_all(&data)?;
        } else {
            let data = ar.load(&file.path)?;
            f.write_all(&data)?;
        }
    }
    Ok(())
}

fn main() -> Result<()> {
    let args: Vec<String> = std::env::args().collect();
    let argsref: Vec<&str> = args.iter().map(|v| v.as_str()).collect();
    match &argsref[..] {
        &[_, "list", archive] => list(archive)?,

        &[_, "extract", archive, destination] => {
            extract(archive, destination, false)?
        }
        &[_, "extract", "--raw", archive, destination] => {
            extract(archive, destination, true)?
        }

        &[cmd, "--help"] => help(cmd),
        &[cmd, "-h"] => help(cmd),
        &[cmd] => help(cmd),
        a => {
            eprintln!("Invalid arguments.");
            help(a[0]);
        }
    }
    Ok(())
}