extern crate getopts;
use std::collections::HashMap;
use gxter::GXTFile;
use std::io;
use std::fs::File;
use std::io::BufReader;
use getopts::Options;
use std::env;
#[cfg(feature = "pretty")]
mod pretty;
fn print_usage(program: &str, opts: Options) {
let brief = format!("Usage: {} FILE [options]", program);
print!("{}", opts.usage(&brief));
}
fn main() -> Result<(), gxter::GXTError> {
let mut opts = Options::new();
opts.optflag("d","decompile","decompile a .gxt file into a text file, rather than the other way around");
opts.optopt("n","name-list","when reading CRC32 hashes of string names, match against this list of names","FILENAME");
#[cfg(feature = "pretty")]
opts.optflag("p","pretty-print","print the contents of a GXT or text file with color formatting");
opts.optopt("o","output","output file name","NAME");
opts.optopt("c","character-table","custom character table","FILENAME");
opts.optflag("K","key-sort","arrange strings in the same order as their keys");
opts.optflag("O","offset-sort","arrange strings in the same order as their data locations");
opts.optflag("h","help","print this help menu");
let args: Vec<String> = env::args().collect();
let program = args[0].clone();
let matches = match opts.parse(&args[1..]) {
Ok(m) => {m}
Err(f) => {panic!("{}", f.to_string())}
};
if matches.opt_present("h") {
print_usage(&program, opts);
return Ok(());
}
let decompile = matches.opt_present("d");
#[cfg(feature = "pretty")]
let do_pretty_print = matches.opt_present("p");
let input_filename = if !matches.free.is_empty() { matches.free[0].clone() } else { print_usage(&program, opts); return Ok(());
};
let data_ordering = if matches.opt_present("key-sort") {
gxter::ImportOrdering::Key
} else if matches.opt_present("offset-sort") {
gxter::ImportOrdering::Offset
} else {
gxter::ImportOrdering::Native
};
let custom_table: Option<gxter::GXTCharacterTable> = match matches.opt_str("character-table") {
Some(name) => {
let _f = File::open(&name).expect("Unable to open character table file");
let mut file = BufReader::new(_f);
Some(gxter::read_custom_table(&mut file).unwrap())
},
None => None,
};
let name_list: Option<HashMap<u32,String>> = match matches.opt_str("name-list") {
Some(name) => {
let _f = File::open(&name).expect("Unable to open name list file");
let mut file = BufReader::new(_f);
Some(gxter::read_name_list(&mut file).unwrap())
},
None => None,
};
#[cfg(feature = "pretty")]
if do_pretty_print {
let gxt = if decompile {
let _f = File::open(&input_filename).expect("Unable to open GXT file");
let mut file = BufReader::new(_f);
GXTFile::read_from_gxt(&mut file, &Some(data_ordering), &custom_table, &name_list).expect("Unable to decompile GXT file")
} else {
let _f = File::open(&input_filename).expect("Unable to open text file");
let mut file = BufReader::new(_f);
GXTFile::read_from_text(&mut file).expect("Unable to decompile GXT file")
};
for (k,v) in gxt.main_table {
pretty::pretty_print(&k,&v,&gxt.format).unwrap();
}
for (k,v) in gxt.aux_tables {
println!("[{k}]");
for (k,v) in v {
pretty::pretty_print(&k,&v,&gxt.format).unwrap();
}
println!("");
}
return Ok(());
}
if decompile {
let _f = File::open(&input_filename).expect("Unable to open GXT file");
let mut file = BufReader::new(_f);
let gxt = GXTFile::read_from_gxt(&mut file, &Some(data_ordering), &custom_table, &name_list).expect("Unable to decompile GXT file");
let output = matches.opt_str("o");
match output {
Some(ofn) => {
let mut outfile = File::create(ofn).expect("Unable to open output file");
gxt.write_to_text(&mut outfile).unwrap();
},
None => {
let mut stdout = io::stdout();
gxt.write_to_text(&mut stdout).unwrap();
}
};
Ok(())
} else {
let output = matches.opt_str("o");
match output {
Some(ofn) => {
let _f = File::open(&input_filename).expect("Unable to open text file");
let mut file = BufReader::new(_f);
let gxt = GXTFile::read_from_text(&mut file).expect("Unable to decompile GXT file");
let mut outfile = File::create(ofn).expect("Unable to open output file");
gxt.write_to_gxt(&mut outfile, &custom_table).unwrap();
},
None => {
eprintln!("No output file name specified!");
},
}
Ok(())
}
}