Maraiah/source/marathon/wad.rs

213 lines
6.7 KiB
Rust
Raw Normal View History

2019-02-08 21:08:53 -08:00
//! Marathon Wad format handling.
2019-03-30 14:19:10 -07:00
use crate::{durandal::{bin::*, err::*, image},
2019-04-01 02:09:01 -07:00
marathon::{map, phy, pict, text::mac_roman_cstr}};
2019-03-01 01:27:28 -08:00
use std::collections::BTreeMap;
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
/// Reads all chunks in an entry.
2019-04-01 02:09:01 -07:00
pub fn read_chunks(b: &[u8], old: bool, siz_cnk: usize)
2019-03-01 20:04:20 -08:00
-> ResultS<Vec<Chunk>>
2019-02-08 21:08:53 -08:00
{
2019-03-01 01:27:28 -08:00
let mut chunks = Vec::new();
let mut p = 0;
2019-04-01 02:09:01 -07:00
let read_chunk_minf = if old {map::minf::read_old} else {map::minf::read};
let read_chunk_sids = if old {map::sids::read_old} else {map::sids::read};
let read_chunk_poly = if old {map::poly::read_old} else {map::poly::read};
let read_chunk_lite = if old {map::lite::read_old} else {map::lite::read};
2019-03-01 20:04:20 -08:00
2019-03-01 01:27:28 -08:00
while p < b.len() {
2019-02-18 20:06:34 -08:00
read_data! {
2019-03-18 12:31:14 -07:00
endian: BIG, buf: b, size: siz_cnk, start: p, data {
let iden = Ident[0];
let size = u32[8] usize;
}
2019-02-18 20:06:34 -08:00
}
2019-03-01 01:27:28 -08:00
let beg = p + siz_cnk;
let end = beg + size;
let data = &b[beg..end];
2019-03-01 20:04:20 -08:00
chunks.push(match &iden.0 {
2019-03-04 04:28:04 -08:00
b"PICT" => Chunk::Pict(pict::load_pict(data)?),
2019-04-01 02:09:01 -07:00
b"Minf" => Chunk::Minf(read_chunk_minf(data)?),
2019-04-01 00:39:47 -07:00
b"iidx" => Chunk::Iidx(rd_array(data, map::iidx::read)?),
2019-04-01 03:17:56 -07:00
b"EPNT" => Chunk::Epnt(rd_array(data, map::epnt::read)?),
2019-04-01 00:39:47 -07:00
b"PNTS" => Chunk::Pnts(rd_array(data, map::pnts::read)?),
b"LINS" => Chunk::Lins(rd_array(data, map::lins::read)?),
2019-04-01 02:09:01 -07:00
b"SIDS" => Chunk::Sids(rd_array(data, read_chunk_sids)?),
b"POLY" => Chunk::Poly(rd_array(data, read_chunk_poly)?),
2019-04-01 00:39:47 -07:00
b"OBJS" => Chunk::Objs(rd_array(data, map::objs::read)?),
2019-04-01 02:09:01 -07:00
b"LITE" => Chunk::Lite(rd_array(data, read_chunk_lite)?),
2019-04-01 00:39:47 -07:00
b"plac" => Chunk::Plac(rd_array(data, map::plac::read)?),
b"ambi" => Chunk::Ambi(rd_array(data, map::ambi::read)?),
b"bonk" => Chunk::Bonk(rd_array(data, map::bonk::read)?),
b"medi" => Chunk::Medi(rd_array(data, map::medi::read)?),
b"plat" => Chunk::Plat(rd_array(data, map::plat::read)?),
b"NOTE" => Chunk::Note(rd_array(data, map::note::read)?),
2019-04-01 02:09:01 -07:00
b"term" => Chunk::Term(rd_array(data, map::term::read)?),
2019-04-01 01:38:51 -07:00
b"FXpx" => Chunk::Fxpx(rd_array(data, phy::fxpx::read)?),
b"MNpx" => Chunk::Mnpx(rd_array(data, phy::mnpx::read)?),
b"PRpx" => Chunk::Prpx(rd_array(data, phy::prpx::read)?),
b"PXpx" => Chunk::Pxpx(rd_array(data, phy::pxpx::read)?),
b"WPpx" => Chunk::Wppx(rd_array(data, phy::wppx::read)?),
2019-03-31 12:04:18 -07:00
_ => Chunk::Data{iden, data: data.to_vec()},
2019-03-04 04:28:04 -08:00
});
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
p = end;
}
2019-02-08 21:53:27 -08:00
2019-03-01 01:27:28 -08:00
Ok(chunks)
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
/// Reads all entries in a `Wad`.
pub fn read_entries(b: &[u8],
2019-03-01 20:04:20 -08:00
old_wad: bool,
old_dat: bool,
2019-03-01 01:27:28 -08:00
siz_app: usize,
siz_ent: usize,
siz_cnk: usize)
2019-03-02 21:44:45 -08:00
-> ResultS<BTreeMap<u16, Entry>>
2019-03-01 01:27:28 -08:00
{
read_data! {
2019-03-18 12:31:14 -07:00
endian: BIG, buf: b, size: 128, start: 0, data {
let dirofs = u32[72] usize;
let numents = u16[76] usize;
}
2019-03-01 01:27:28 -08:00
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
let mut entries = BTreeMap::new();
let mut p = dirofs;
2019-02-18 20:06:34 -08:00
2019-03-01 01:27:28 -08:00
for i in 0..numents {
read_data! {
2019-03-18 12:31:14 -07:00
endian: BIG, buf: b, size: siz_ent, start: p, data {
let offset = u32[0] usize;
let size = u32[4] usize;
let index = u16[8];
}
2019-03-01 01:27:28 -08:00
}
2019-02-08 21:08:53 -08:00
2019-03-01 20:04:20 -08:00
let index = if old_wad {i as u16} else {index};
2019-02-08 21:08:53 -08:00
2019-03-01 20:04:20 -08:00
let chunks = read_chunks(&b[offset..offset + size], old_dat, siz_cnk)?;
2019-03-01 01:27:28 -08:00
let appdata = b[p..p + siz_app].to_vec();
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
entries.insert(index, Entry{chunks, appdata});
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
p += siz_ent + siz_app;
2019-02-08 21:08:53 -08:00
}
2019-03-01 01:27:28 -08:00
Ok(entries)
2019-02-08 21:08:53 -08:00
}
2019-03-01 01:27:28 -08:00
/// Reads a Map file.
pub fn read_wad(b: &[u8]) -> ResultS<Wad>
2019-02-08 21:08:53 -08:00
{
2019-03-01 01:27:28 -08:00
read_data! {
2019-03-18 12:31:14 -07:00
endian: BIG, buf: b, size: 128, start: 0, data {
let ver_wad = u16[0] enum Ver;
let ver_dat = u16[2];
let name = mac_roman_cstr[4; 64] no_try;
let siz_app = u16[78] usize;
let siz_wcnk = u16[80] usize;
let siz_went = u16[82] usize;
}
2019-03-01 01:27:28 -08:00
}
2019-02-08 21:08:53 -08:00
2019-03-09 14:03:20 -08:00
let old_dat = ver_dat == 0;
2019-03-18 12:31:14 -07:00
let old_wad = match ver_wad {
2019-03-01 01:27:28 -08:00
Ver::Base => true,
2019-03-01 20:09:18 -08:00
_ => false,
2019-03-01 01:27:28 -08:00
};
2019-02-18 20:06:34 -08:00
2019-03-01 20:04:20 -08:00
let siz_ent = if old_wad {8 } else {10};
let siz_cnk = if old_wad {12} else {16};
2019-02-18 20:06:34 -08:00
2019-03-01 20:04:20 -08:00
if !old_wad && siz_ent != siz_went {
2019-03-01 01:27:28 -08:00
bail!("invalid entry size");
2019-02-08 21:08:53 -08:00
}
2019-03-01 20:04:20 -08:00
if !old_wad && siz_cnk != siz_wcnk {
2019-03-01 01:27:28 -08:00
bail!("invalid chunk size");
}
2019-03-01 20:04:20 -08:00
let entries = read_entries(b, old_wad, old_dat, siz_app, siz_ent, siz_cnk)?;
2019-03-01 01:27:28 -08:00
2019-03-09 14:03:20 -08:00
Ok(Wad{name, siz_app, entries})
2019-02-08 21:08:53 -08:00
}
2019-03-01 01:27:28 -08:00
/// Any kind of chunk in an `Entry`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
2019-03-13 08:40:12 -07:00
#[derive(Debug, Eq, PartialEq)]
2019-03-01 01:27:28 -08:00
pub enum Chunk
{
2019-03-31 12:04:18 -07:00
/** A `PICT` chunk. */ Pict(image::Image8),
2019-04-01 00:39:47 -07:00
/** A `Minf` chunk. */ Minf(map::minf::Minf),
2019-03-31 12:04:18 -07:00
/** An `iidx` chunk. */ Iidx(Vec<u16>),
2019-04-01 03:17:56 -07:00
/** An `EPNT` chunk. */ Epnt(Vec<map::epnt::Endpoint>),
2019-04-01 00:39:47 -07:00
/** A `PNTS` chunk. */ Pnts(Vec<map::pnts::Point>),
/** A `LINS` chunk. */ Lins(Vec<map::lins::Line>),
/** A `SIDS` chunk. */ Sids(Vec<map::sids::Side>),
/** A `POLY` chunk. */ Poly(Vec<map::poly::Polygon>),
/** A `LITE` chunk. */ Lite(Vec<map::lite::Light>),
/** An `OBJS` chunk. */ Objs(Vec<map::objs::Object>),
/** A `plac` chunk. */ Plac(Vec<map::plac::ObjectFreq>),
/** An `ambi` chunk. */ Ambi(Vec<map::ambi::SoundAmbi>),
/** A `bonk` chunk. */ Bonk(Vec<map::bonk::SoundRand>),
/** A `medi` chunk. */ Medi(Vec<map::medi::Media>),
/** A `plat` chunk. */ Plat(Vec<map::plat::Platform>),
/** A `NOTE` chunk. */ Note(Vec<map::note::Note>),
2019-04-01 02:09:01 -07:00
/** A `term` chunk. */ Term(Vec<map::term::Terminal>),
2019-04-01 01:38:51 -07:00
/** A `FXpx` chunk. */ Fxpx(Vec<phy::fxpx::Effect>),
/** A `MNpx` chunk. */ Mnpx(Vec<phy::mnpx::Monster>),
/** A `PRpx` chunk. */ Prpx(Vec<phy::prpx::Projectile>),
/** A `PXpx` chunk. */ Pxpx(Vec<phy::pxpx::Physics>),
/** A `WPpx` chunk. */ Wppx(Vec<phy::wppx::Weapon>),
2019-03-31 12:04:18 -07:00
2019-03-09 14:03:20 -08:00
/// Any other type of chunk, which may have arbitrary data in it.
Data{/** The name of the chunk. */ iden: Ident,
2019-03-31 12:04:18 -07:00
/** The data. */ data: Vec<u8>},
2019-03-01 01:27:28 -08:00
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
/// An entry containing chunks and application-specific data.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
2019-03-13 08:40:12 -07:00
#[derive(Debug, Eq, PartialEq)]
2019-03-01 01:27:28 -08:00
pub struct Entry
2019-02-08 21:08:53 -08:00
{
2019-03-09 14:03:20 -08:00
/// All of the chunks in this `Entry`.
pub chunks: Vec<Chunk>,
2019-02-08 21:08:53 -08:00
2019-03-09 14:03:20 -08:00
/// The application specific data for this Entry.
pub appdata: Vec<u8>,
2019-02-12 15:03:18 -08:00
}
2019-03-01 01:27:28 -08:00
/// A Map file containing entries.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
2019-03-13 08:40:12 -07:00
#[derive(Debug, Eq, PartialEq)]
2019-03-01 01:27:28 -08:00
pub struct Wad
2019-02-08 21:08:53 -08:00
{
2019-03-09 14:03:20 -08:00
/// The original name of this file.
pub name: String,
/// The size of each `Entry`'s `appdata` field.
pub siz_app: usize,
/// All of the entries in this `Wad`.
2019-03-01 01:27:28 -08:00
pub entries: BTreeMap<u16, Entry>,
2019-02-08 21:08:53 -08:00
}
c_enum! {
2019-03-01 01:27:28 -08:00
/// The version of a `Wad`.
#[derive(Debug)]
enum Ver: u16
2019-02-08 21:08:53 -08:00
{
2019-03-18 09:22:10 -07:00
Base = 0,
Dir = 1,
Over = 2,
Inf = 4,
2019-02-08 21:08:53 -08:00
}
}
// EOF