yaz0 0.3.0

A library for de/compressing Nintendo Yaz0 files
Documentation
extern crate clap;
extern crate indicatif;
extern crate yaz0;

use std::io::Write;
use clap::{App, AppSettings, Arg, SubCommand};
use indicatif::ProgressBar;
use std::error::Error;
use std::fs::File;
use std::io::{Read, BufReader};
use std::sync::mpsc;
use std::thread;
use std::path::Path;
use yaz0::{Yaz0Archive, Yaz0Writer, CompressionLevel};
use yaz0::deflate::ProgressMsg;

fn main() -> Result<(), Box<dyn Error>> {
    let matches = App::new("yaztool")
        .author("Erin Moon <erin@hashbang.sh>")
        .about("(de)compresses Yaz0 files")
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(SubCommand::with_name("decompress")
                    .arg(Arg::with_name("INPUT")
                        .required(true))
                    .arg(Arg::with_name("OUTPUT")
                        .required(true)))
        .subcommand(SubCommand::with_name("compress")
            .arg(Arg::with_name("INPUT")
                .required(true))
            .arg(Arg::with_name("OUTPUT")
                .required(true)))
        .get_matches();

    match matches.subcommand() {
        ("decompress", Some(matches)) => {
            let in_path = Path::new(matches.value_of("INPUT").unwrap());
            let out_path = Path::new(matches.value_of("OUTPUT").unwrap());

            let reader = BufReader::new(File::open(in_path)?);

            let mut yazfile = Yaz0Archive::new(reader)?;
            let inflated = yazfile.decompress()?;

            let mut outfile = File::create(out_path)?;
            outfile.write_all(&inflated)?;
        },
        ("compress", Some(matches)) => {
            let in_path = Path::new(matches.value_of("INPUT").unwrap());
            let out_path = Path::new(matches.value_of("OUTPUT").unwrap());

            let data = {
                let mut d = Vec::new();
                File::open(in_path)?.read_to_end(&mut d)?;
                d
            };

            let pb = ProgressBar::new(data.len() as u64);
            let (tx, rx) = mpsc::channel::<ProgressMsg>();
            thread::spawn(move || {
                while let Ok(progress) = rx.recv() {
                    pb.set_position(progress.read_head as u64);
                }
            });

            let quality = CompressionLevel::Lookahead {quality: 10};
            let deflated = {
                let mut d = Vec::new();
                Yaz0Writer::new(&mut d)
                    .compress_and_write_with_progress(&data, quality, tx)?;
                d
            };

            let mut outfile = File::create(out_path)?;
            outfile.write_all(&deflated)?;
        },
        _ => unreachable!(),
    }

    Ok(())
}