2019-02-12 14:32:16 -08:00
|
|
|
use maraiah::{durandal::{bin::*, chunk::*, err::*, file::*, image::*, text::*},
|
2019-02-09 11:04:27 -08:00
|
|
|
marathon::{machdr, map, pict, shp, term, wad}};
|
2019-02-12 14:32:16 -08:00
|
|
|
use std::{collections::HashSet,
|
|
|
|
fs,
|
2019-02-08 21:53:27 -08:00
|
|
|
io::{self, Write}};
|
2018-12-08 14:51:37 -08:00
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
fn make_tga(fname: &str, im: &impl Image) -> ResultS<()>
|
2019-02-10 02:31:57 -08:00
|
|
|
{
|
2019-02-12 15:03:18 -08:00
|
|
|
let mut out = io::BufWriter::new(fs::File::create(fname)?);
|
2019-02-12 14:32:16 -08:00
|
|
|
write_tga(&mut out, im)
|
|
|
|
}
|
|
|
|
|
2019-02-13 21:19:36 -08:00
|
|
|
fn make_chunk(opt: &Options, cid: Ident, cnk: &[u8], eid: u16) -> ResultS<()>
|
2019-02-12 14:32:16 -08:00
|
|
|
{
|
2019-02-13 21:19:36 -08:00
|
|
|
let cid = mac_roman_conv(&cid);
|
2019-02-12 14:32:16 -08:00
|
|
|
let fname = format!("{}/{:04}{}.bin", opt.out_dir, eid, cid);
|
2019-02-12 15:03:18 -08:00
|
|
|
let mut out = io::BufWriter::new(fs::File::create(&fname)?);
|
2019-02-13 21:19:36 -08:00
|
|
|
out.write_all(cnk)?;
|
2019-02-10 02:31:57 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
fn make_yaml(data: &impl serde::Serialize) -> ResultS<()>
|
|
|
|
{
|
|
|
|
serde_yaml::to_writer(io::stdout(), &data)?;
|
|
|
|
println!();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-13 21:19:36 -08:00
|
|
|
fn dump_chunk(opt: &Options, cid: Ident, cnk: &[u8], eid: u16) -> ResultS<()>
|
2018-09-06 09:01:52 -07:00
|
|
|
{
|
2019-02-12 14:32:16 -08:00
|
|
|
if opt.wad_all {
|
|
|
|
make_chunk(opt, cid, cnk, eid)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2019-02-13 21:52:07 -08:00
|
|
|
if opt.wad_chunks.contains(&cid) {
|
|
|
|
match &cid {
|
|
|
|
b"PICT" => {
|
2019-02-12 14:32:16 -08:00
|
|
|
let im = pict::load_pict(cnk)?;
|
|
|
|
make_tga(&format!("{}/pict_{}.tga", opt.out_dir, eid), &im)?;
|
|
|
|
}
|
2019-02-13 21:52:07 -08:00
|
|
|
b"Minf" => make_yaml(&map::Minf::chunk(cnk)?)?,
|
|
|
|
b"EPNT" => make_yaml(&map::Endpoint::chunk(cnk)?)?,
|
|
|
|
b"PNTS" => make_yaml(&map::Point::chunk(cnk)?)?,
|
|
|
|
b"LINS" => make_yaml(&map::Line::chunk(cnk)?)?,
|
|
|
|
b"SIDS" => make_yaml(&map::Side::chunk(cnk)?)?,
|
|
|
|
b"term" => make_yaml(&term::Terminal::chunk(cnk)?)?,
|
|
|
|
_ => (),
|
2019-02-08 21:53:27 -08:00
|
|
|
}
|
2019-02-13 21:52:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if opt.wad_unknown {
|
|
|
|
make_chunk(opt, cid, cnk, eid)?;
|
2019-02-08 20:21:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
fn process_wad(opt: &Options, b: &[u8]) -> ResultS<()>
|
2019-02-08 20:21:22 -08:00
|
|
|
{
|
|
|
|
let wad = wad::Wad::new(b)?;
|
2018-09-09 15:21:31 -07:00
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
if opt.wad_header {
|
2019-02-12 15:03:18 -08:00
|
|
|
make_yaml(&wad.head)?;
|
2019-02-12 14:32:16 -08:00
|
|
|
}
|
2018-09-09 15:21:31 -07:00
|
|
|
|
2019-02-08 20:21:22 -08:00
|
|
|
for (eid, ent) in wad.entries {
|
|
|
|
for (cid, cnk) in ent.chunks {
|
2019-02-13 21:19:36 -08:00
|
|
|
dump_chunk(opt, cid, cnk, eid)?;
|
2018-09-09 15:21:31 -07:00
|
|
|
}
|
2019-02-08 20:21:22 -08:00
|
|
|
}
|
2018-12-08 14:51:37 -08:00
|
|
|
|
2019-02-08 20:21:22 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
2018-12-08 14:51:37 -08:00
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
fn dump_bitmaps(opt: &Options, c: &shp::Collection, i: usize) -> ResultS<()>
|
2019-02-12 06:41:28 -08:00
|
|
|
{
|
2019-02-12 14:32:16 -08:00
|
|
|
if !opt.shp_bmp {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2019-02-12 06:41:28 -08:00
|
|
|
for (j, bmp) in c.bmps.iter().enumerate() {
|
2019-02-12 14:32:16 -08:00
|
|
|
if opt.shp_bmp_all {
|
|
|
|
for (k, tab) in c.tabs.iter().enumerate() {
|
|
|
|
let fname = format!("{}/shape{}_{}_{}.tga", opt.out_dir, i, j, k);
|
|
|
|
make_tga(&fname, &shp::ImageShp::new(bmp, &tab))?;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let fname = format!("{}/shape{}_{}.tga", opt.out_dir, i, j);
|
|
|
|
make_tga(&fname, &shp::ImageShp::new(bmp, &c.tabs[0]))?;
|
2019-02-12 06:41:28 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
fn write_shp_objs(opt: &Options, cl: &shp::Collection) -> ResultS<()>
|
|
|
|
{
|
|
|
|
if opt.shp_tab {
|
|
|
|
make_yaml(&cl.tabs)?;
|
|
|
|
}
|
|
|
|
if opt.shp_frm {
|
|
|
|
make_yaml(&cl.frms)?;
|
|
|
|
}
|
|
|
|
if opt.shp_seq {
|
|
|
|
make_yaml(&cl.seqs)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_shp(opt: &Options, b: &[u8]) -> ResultS<()>
|
2019-02-08 20:21:22 -08:00
|
|
|
{
|
2019-02-12 06:41:28 -08:00
|
|
|
for (i, cl) in shp::read_shapes(b)?.iter().enumerate() {
|
2019-02-12 02:31:20 -08:00
|
|
|
if let Some(cl) = &cl.0 {
|
2019-02-12 14:32:16 -08:00
|
|
|
dump_bitmaps(opt, cl, i)?;
|
|
|
|
write_shp_objs(opt, cl)?;
|
2019-02-12 02:31:20 -08:00
|
|
|
}
|
|
|
|
if let Some(cl) = &cl.1 {
|
2019-02-12 14:32:16 -08:00
|
|
|
dump_bitmaps(opt, cl, i + 100)?;
|
|
|
|
write_shp_objs(opt, cl)?;
|
2019-02-12 02:31:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2018-09-06 09:01:52 -07:00
|
|
|
}
|
|
|
|
|
2019-02-08 20:21:22 -08:00
|
|
|
fn main() -> ResultS<()>
|
|
|
|
{
|
2019-02-12 09:53:25 -08:00
|
|
|
use argparse::*;
|
2019-02-08 20:21:22 -08:00
|
|
|
use memmap::Mmap;
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
let mut opt: Options = Default::default();
|
2019-02-12 09:53:25 -08:00
|
|
|
{
|
|
|
|
let mut ap = ArgumentParser::new();
|
|
|
|
ap.set_description(env!("CARGO_PKG_DESCRIPTION"));
|
|
|
|
ap.add_option(&["-v", "--version"],
|
2019-02-12 15:03:18 -08:00
|
|
|
Print(concat!(env!("CARGO_PKG_NAME"),
|
|
|
|
" ",
|
|
|
|
env!("CARGO_PKG_VERSION")).to_string()),
|
2019-02-12 09:53:25 -08:00
|
|
|
"Show the version");
|
2019-02-12 14:32:16 -08:00
|
|
|
ap.refer(&mut opt.shp_tab)
|
|
|
|
.add_option(&["--shp-write-tab"], StoreTrue,
|
|
|
|
"shp: Dump all CLUTs as YAML to standard output");
|
|
|
|
ap.refer(&mut opt.shp_bmp)
|
|
|
|
.add_option(&["--shp-dump-bitmaps"], StoreTrue,
|
|
|
|
"shp: Dump bitmaps into a folder");
|
|
|
|
ap.refer(&mut opt.shp_bmp_all)
|
|
|
|
.add_option(&["--shp-dump-more-bitmaps"], StoreTrue,
|
|
|
|
"shp: Dump all color variations of each bitmap");
|
|
|
|
ap.refer(&mut opt.shp_frm)
|
|
|
|
.add_option(&["--shp-write-frm"], StoreTrue,
|
|
|
|
"shp: Dump all frames as YAML to standard output");
|
|
|
|
ap.refer(&mut opt.shp_seq)
|
|
|
|
.add_option(&["--shp-write-seq"], StoreTrue,
|
|
|
|
"shp: Dump all sequences as YAML to standard output");
|
|
|
|
ap.refer(&mut opt.wad_all)
|
|
|
|
.add_option(&["--wad-dump-all"], StoreTrue,
|
|
|
|
"wad: Dump all chunks into a folder");
|
|
|
|
ap.refer(&mut opt.wad_unknown)
|
|
|
|
.add_option(&["--wad-dump-unknown"], StoreTrue,
|
|
|
|
"wad: Dump all unknown chunks into a folder");
|
|
|
|
ap.refer(&mut opt.wad_header)
|
|
|
|
.add_option(&["--wad-write-header"], StoreTrue,
|
|
|
|
"wad: Dump header info as YAML to standard output");
|
|
|
|
ap.refer(&mut opt.wad_c_temp)
|
|
|
|
.add_option(&["--wad-write-chunks"], Store,
|
|
|
|
"wad: Dump specified chunks in various formats");
|
|
|
|
ap.refer(&mut opt.out_dir)
|
|
|
|
.add_option(&["--out-dir"], Store,
|
|
|
|
"Sets output directory for dump options");
|
|
|
|
ap.refer(&mut opt.inputs)
|
|
|
|
.add_argument("inputs", Collect, "Input files");
|
2019-02-12 09:53:25 -08:00
|
|
|
ap.parse_args_or_exit();
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
if opt.shp_bmp_all {
|
|
|
|
opt.shp_bmp = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if opt.out_dir.is_empty() {
|
|
|
|
opt.out_dir = ".".to_string();
|
|
|
|
}
|
|
|
|
|
|
|
|
if !opt.wad_c_temp.is_empty() {
|
|
|
|
for ctyp in opt.wad_c_temp.split(',') {
|
|
|
|
opt.wad_chunks.insert(c_iden(ctyp.as_bytes(), 0)?);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
validate_folder_path(&opt.out_dir)?;
|
|
|
|
|
|
|
|
for arg in &opt.inputs {
|
2019-02-08 20:21:22 -08:00
|
|
|
let (typ, fna) = if let Some(st) = arg.find(':') {
|
|
|
|
arg.split_at(st + 1)
|
|
|
|
} else {
|
|
|
|
("wad:", arg.as_str())
|
|
|
|
};
|
|
|
|
|
|
|
|
let fp = fs::File::open(fna)?;
|
2019-02-08 21:53:27 -08:00
|
|
|
let mm = unsafe {Mmap::map(&fp)?};
|
2019-02-10 02:31:57 -08:00
|
|
|
let b = c_data(&mm, machdr::try_mac_header(&mm)..)?;
|
2019-02-08 20:21:22 -08:00
|
|
|
|
|
|
|
match typ {
|
2019-02-12 14:32:16 -08:00
|
|
|
"wad:" => process_wad(&opt, b),
|
|
|
|
"shp:" => process_shp(&opt, b),
|
2019-02-08 21:53:27 -08:00
|
|
|
_ => Err(err_msg("invalid file type specified on commandline")),
|
2019-02-08 20:21:22 -08:00
|
|
|
}?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-02-12 14:32:16 -08:00
|
|
|
#[derive(Default)]
|
|
|
|
struct Options
|
|
|
|
{
|
|
|
|
inputs: Vec<String>,
|
|
|
|
out_dir: String,
|
|
|
|
shp_tab: bool,
|
|
|
|
shp_bmp: bool,
|
|
|
|
shp_bmp_all: bool,
|
|
|
|
shp_frm: bool,
|
|
|
|
shp_seq: bool,
|
|
|
|
wad_all: bool,
|
|
|
|
wad_unknown: bool,
|
|
|
|
wad_header: bool,
|
|
|
|
wad_chunks: HashSet<Ident>,
|
|
|
|
wad_c_temp: String,
|
|
|
|
}
|
|
|
|
|
2018-09-06 09:01:52 -07:00
|
|
|
// EOF
|