Maraiah/src/marathon/wad.rs

197 lines
5.1 KiB
Rust
Raw Normal View History

2019-02-08 21:08:53 -08:00
//! Marathon Wad format handling.
2019-03-01 01:27:28 -08:00
use crate::durandal::{bin::*, err::*, image, text::mac_roman_conv};
use crate::marathon::{map, phy, pict, trm};
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.
pub fn read_chunks(b: &[u8], siz_cnk: usize) -> 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;
while p < b.len() {
2019-02-18 20:06:34 -08:00
read_data! {
2019-03-01 01:27:28 -08:00
p + siz_cnk, BE in b =>
iden = Ident[p];
size = u32[p + 8] as 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];
let chunk = match &iden {
b"PICT" => Chunk::Pict(pict::load_pict(data)?),
b"Minf" => Chunk::Minf(map::read_minf(data)?),
b"EPNT" => Chunk::Pnts(rd_array(data, map::read_epnt)?),
b"PNTS" => Chunk::Pnts(rd_array(data, map::read_pnts)?),
b"LINS" => Chunk::Lins(rd_array(data, map::read_lins)?),
b"SIDS" => Chunk::Sids(rd_array(data, map::read_sids)?),
b"POLY" => Chunk::Poly(rd_array(data, map::read_poly)?),
b"LITE" => Chunk::Lite(rd_array(data, map::read_lite)?),
b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?),
b"plac" => Chunk::Plac(rd_array(data, map::read_plac)?),
b"ambi" => Chunk::Ambi(rd_array(data, map::read_ambi)?),
b"bonk" => Chunk::Bonk(rd_array(data, map::read_bonk)?),
b"medi" => Chunk::Medi(rd_array(data, map::read_medi)?),
b"plat" => Chunk::Plat(rd_array(data, map::read_plat)?),
2019-03-01 03:22:27 -08:00
b"NOTE" => Chunk::Note(rd_array(data, map::read_note)?),
2019-03-01 01:27:28 -08:00
b"term" => Chunk::Term(rd_array(data, trm::read_term)?),
b"FXpx" => Chunk::Fxpx(rd_array(data, phy::read_fxpx)?),
b"MNpx" => Chunk::Mnpx(rd_array(data, phy::read_mnpx)?),
b"PRpx" => Chunk::Prpx(rd_array(data, phy::read_prpx)?),
b"PXpx" => Chunk::Pxpx(rd_array(data, phy::read_pxpx)?),
b"WPpx" => Chunk::Wppx(rd_array(data, phy::read_wppx)?),
_ => Chunk::Data{iden, data: data.to_vec()},
2019-02-08 21:53:27 -08:00
};
2019-02-20 15:39:29 -08:00
2019-03-01 01:27:28 -08:00
chunks.push(chunk);
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],
is_old: bool,
siz_app: usize,
siz_ent: usize,
siz_cnk: usize)
-> ResultS<BTreeMap<u16, Entry>>
{
read_data! {
128, BE in b =>
dirofs = u32[72] as usize;
numents = u16[76] as usize;
}
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! {
p + siz_ent, BE in b =>
offset = u32[p] as usize;
size = u32[p + 4] as usize;
index = u16[p + 8];
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
let index = if is_old {i as u16} else {index};
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
let chunks = read_chunks(&b[offset..offset + size], siz_cnk)?;
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! {
128, BE in b =>
ver_wad = u16[0];
ver_dat = u16[2];
name = mac_roman_conv[4..68] nt;
siz_app = u16[78] as usize;
siz_wcnk = u16[80] as usize;
siz_went = u16[82] as usize;
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
let ver_wad = Ver::from_repr(ver_wad)?;
2019-02-18 20:06:34 -08:00
2019-03-01 01:27:28 -08:00
let is_old = match ver_wad {
Ver::Base => true,
_ => false,
};
2019-02-18 20:06:34 -08:00
2019-03-01 01:27:28 -08:00
let siz_ent = if is_old {8 } else {10};
let siz_cnk = if is_old {12} else {16};
2019-02-18 20:06:34 -08:00
2019-03-01 01:58:02 -08:00
if 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 01:58:02 -08:00
if siz_cnk != siz_wcnk {
2019-03-01 01:27:28 -08:00
bail!("invalid chunk size");
}
let entries = read_entries(b, is_old, siz_app, siz_ent, siz_cnk)?;
Ok(Wad{head: WadHeader{ver_wad, ver_dat, siz_app, name}, entries})
2019-02-08 21:08:53 -08:00
}
2019-03-01 01:27:28 -08:00
/// Any kind of chunk in an `Entry`.
2019-03-01 03:22:27 -08:00
#[derive(Debug, serde::Serialize)]
2019-03-01 01:27:28 -08:00
pub enum Chunk
{
Pict(image::Image8),
Minf(map::Minf),
Pnts(Vec<map::Point>),
Lins(Vec<map::Line>),
Sids(Vec<map::Side>),
Poly(Vec<map::Polygon>),
Lite(Vec<map::Light>),
Objs(Vec<map::Object>),
Plac(Vec<map::ObjectFreq>),
Ambi(Vec<map::SoundAmbi>),
Bonk(Vec<map::SoundRand>),
Medi(Vec<map::Media>),
Plat(Vec<map::Platform>),
2019-03-01 03:22:27 -08:00
Note(Vec<map::Note>),
2019-03-01 01:27:28 -08:00
Term(Vec<trm::Terminal>),
Fxpx(Vec<phy::Effect>),
Mnpx(Vec<phy::Monster>),
Prpx(Vec<phy::Projectile>),
Pxpx(Vec<phy::Physics>),
Wppx(Vec<phy::Weapon>),
Data{iden: Ident, data: Vec<u8>},
}
2019-02-08 21:08:53 -08:00
2019-03-01 01:27:28 -08:00
/// An entry containing chunks and application-specific data.
2019-03-01 03:22:27 -08:00
#[derive(Debug, serde::Serialize)]
2019-03-01 01:27:28 -08:00
pub struct Entry
2019-02-08 21:08:53 -08:00
{
2019-03-01 01:27:28 -08:00
pub chunks: Vec<Chunk>,
pub appdata: Vec<u8>,
2019-02-08 21:08:53 -08:00
}
2019-03-01 01:27:28 -08:00
/// The header of a `Wad`.
2019-03-01 03:22:27 -08:00
#[derive(Debug, serde::Serialize)]
2019-02-12 15:03:18 -08:00
pub struct WadHeader
{
2019-03-01 01:27:28 -08:00
pub ver_wad: Ver,
pub ver_dat: u16,
pub name: String,
pub siz_app: usize,
2019-02-12 15:03:18 -08:00
}
2019-03-01 01:27:28 -08:00
/// A Map file containing entries.
2019-03-01 03:22:27 -08:00
#[derive(Debug, serde::Serialize)]
2019-03-01 01:27:28 -08:00
pub struct Wad
2019-02-08 21:08:53 -08:00
{
2019-02-12 15:03:18 -08:00
pub head: WadHeader,
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`.
2019-03-01 03:22:27 -08:00
#[derive(Debug, serde::Serialize)]
2019-02-08 21:08:53 -08:00
pub enum Ver: u16
{
0 => Base,
1 => Dir,
2 => Over,
4 => Inf,
}
}
// EOF