extern crate getopts;
use getopts::Options;
use gxter::GXTFile;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::BufReader;
#[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(
"s",
"sanitize-tags",
"do not use the character table while reading tags",
);
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 sanitize_tags = matches.opt_present("s");
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,
Some(sanitize_tags),
)
.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,
Some(sanitize_tags),
)
.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(())
}
}