225 lines
6.1 KiB
Rust
225 lines
6.1 KiB
Rust
//! Marathon Wad format handling.
|
|
|
|
use crate::{durandal::{bin::*, err::*, image, text::mac_roman_cstr},
|
|
marathon::{map, phy, pict, trm}};
|
|
use std::collections::BTreeMap;
|
|
|
|
/// Reads all chunks in an entry.
|
|
pub fn read_chunks(b: &[u8], old_dat: bool, siz_cnk: usize)
|
|
-> ResultS<Vec<Chunk>>
|
|
{
|
|
let mut chunks = Vec::new();
|
|
let mut p = 0;
|
|
|
|
let map_read_minfo = if old_dat {map::read_old_minf} else {map::read_minf};
|
|
let map_read_sides = if old_dat {map::read_old_sids} else {map::read_sids};
|
|
let map_read_polys = if old_dat {map::read_old_poly} else {map::read_poly};
|
|
let map_read_light = if old_dat {map::read_old_lite} else {map::read_lite};
|
|
|
|
while p < b.len() {
|
|
read_data! {
|
|
p + siz_cnk, BE in b =>
|
|
iden = Ident[p];
|
|
size = u32[p + 8] usize;
|
|
}
|
|
|
|
let beg = p + siz_cnk;
|
|
let end = beg + size;
|
|
let data = &b[beg..end];
|
|
|
|
chunks.push(match &iden.0 {
|
|
b"PICT" => Chunk::Pict(pict::load_pict(data)?),
|
|
b"Minf" => Chunk::Minf(map_read_minfo(data)?),
|
|
b"iidx" => Chunk::Iidx(rd_array(data, map::read_iidx)?),
|
|
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_sides)?),
|
|
b"POLY" => Chunk::Poly(rd_array(data, map_read_polys)?),
|
|
b"OBJS" => Chunk::Objs(rd_array(data, map::read_objs)?),
|
|
b"LITE" => Chunk::Lite(rd_array(data, map_read_light)?),
|
|
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)?),
|
|
b"NOTE" => Chunk::Note(rd_array(data, map::read_note)?),
|
|
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()},
|
|
});
|
|
|
|
p = end;
|
|
}
|
|
|
|
Ok(chunks)
|
|
}
|
|
|
|
/// Reads all entries in a `Wad`.
|
|
pub fn read_entries(b: &[u8],
|
|
old_wad: bool,
|
|
old_dat: bool,
|
|
siz_app: usize,
|
|
siz_ent: usize,
|
|
siz_cnk: usize)
|
|
-> ResultS<BTreeMap<u16, Entry>>
|
|
{
|
|
read_data! {
|
|
128, BE in b =>
|
|
dirofs = u32[72] usize;
|
|
numents = u16[76] usize;
|
|
}
|
|
|
|
let mut entries = BTreeMap::new();
|
|
let mut p = dirofs;
|
|
|
|
for i in 0..numents {
|
|
read_data! {
|
|
p + siz_ent, BE in b =>
|
|
offset = u32[p] usize;
|
|
size = u32[p + 4] usize;
|
|
index = u16[p + 8];
|
|
}
|
|
|
|
let index = if old_wad {i as u16} else {index};
|
|
|
|
let chunks = read_chunks(&b[offset..offset + size], old_dat, siz_cnk)?;
|
|
let appdata = b[p..p + siz_app].to_vec();
|
|
|
|
entries.insert(index, Entry{chunks, appdata});
|
|
|
|
p += siz_ent + siz_app;
|
|
}
|
|
|
|
Ok(entries)
|
|
}
|
|
|
|
/// Reads a Map file.
|
|
pub fn read_wad(b: &[u8]) -> ResultS<Wad>
|
|
{
|
|
read_data! {
|
|
128, BE in b =>
|
|
ver_wad = u16[0];
|
|
ver_dat = u16[2];
|
|
name = mac_roman_cstr[4..68] no_try;
|
|
siz_app = u16[78] usize;
|
|
siz_wcnk = u16[80] usize;
|
|
siz_went = u16[82] usize;
|
|
}
|
|
|
|
let old_dat = ver_dat == 0;
|
|
let old_wad = match Ver::from_repr(ver_wad)? {
|
|
Ver::Base => true,
|
|
_ => false,
|
|
};
|
|
|
|
let siz_ent = if old_wad {8 } else {10};
|
|
let siz_cnk = if old_wad {12} else {16};
|
|
|
|
if !old_wad && siz_ent != siz_went {
|
|
bail!("invalid entry size");
|
|
}
|
|
|
|
if !old_wad && siz_cnk != siz_wcnk {
|
|
bail!("invalid chunk size");
|
|
}
|
|
|
|
let entries = read_entries(b, old_wad, old_dat, siz_app, siz_ent, siz_cnk)?;
|
|
|
|
Ok(Wad{name, siz_app, entries})
|
|
}
|
|
|
|
/// Any kind of chunk in an `Entry`.
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub enum Chunk
|
|
{
|
|
/// A `PICT` chunk.
|
|
Pict(image::Image8),
|
|
/// A `Minf` chunk.
|
|
Minf(map::Minf),
|
|
/// An `iidx` chunk.
|
|
Iidx(Vec<u16>),
|
|
/// A `PNTS` chunk.
|
|
Pnts(Vec<map::Point>),
|
|
/// A `LINS` chunk.
|
|
Lins(Vec<map::Line>),
|
|
/// A `SIDS` chunk.
|
|
Sids(Vec<map::Side>),
|
|
/// A `POLY` chunk.
|
|
Poly(Vec<map::Polygon>),
|
|
/// A `LITE` chunk.
|
|
Lite(Vec<map::Light>),
|
|
/// An `OBJS` chunk.
|
|
Objs(Vec<map::Object>),
|
|
/// A `plac` chunk.
|
|
Plac(Vec<map::ObjectFreq>),
|
|
/// An `ambi` chunk.
|
|
Ambi(Vec<map::SoundAmbi>),
|
|
/// A `bonk` chunk.
|
|
Bonk(Vec<map::SoundRand>),
|
|
/// A `medi` chunk.
|
|
Medi(Vec<map::Media>),
|
|
/// A `plat` chunk.
|
|
Plat(Vec<map::Platform>),
|
|
/// A `NOTE` chunk.
|
|
Note(Vec<map::Note>),
|
|
/// A `term` chunk.
|
|
Term(Vec<trm::Terminal>),
|
|
/// A `FXpx` chunk.
|
|
Fxpx(Vec<phy::Effect>),
|
|
/// A `MNpx` chunk.
|
|
Mnpx(Vec<phy::Monster>),
|
|
/// A `PRpx` chunk.
|
|
Prpx(Vec<phy::Projectile>),
|
|
/// A `PXpx` chunk.
|
|
Pxpx(Vec<phy::Physics>),
|
|
/// A `WPpx` chunk.
|
|
Wppx(Vec<phy::Weapon>),
|
|
/// Any other type of chunk, which may have arbitrary data in it.
|
|
Data{/** The name of the chunk. */ iden: Ident,
|
|
/** The data. */ data: Vec<u8>},
|
|
}
|
|
|
|
/// An entry containing chunks and application-specific data.
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct Entry
|
|
{
|
|
/// All of the chunks in this `Entry`.
|
|
pub chunks: Vec<Chunk>,
|
|
|
|
/// The application specific data for this Entry.
|
|
pub appdata: Vec<u8>,
|
|
}
|
|
|
|
/// A Map file containing entries.
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub struct Wad
|
|
{
|
|
/// 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`.
|
|
pub entries: BTreeMap<u16, Entry>,
|
|
}
|
|
|
|
c_enum! {
|
|
/// The version of a `Wad`.
|
|
#[derive(Debug, serde::Serialize)]
|
|
pub enum Ver: u16
|
|
{
|
|
0 => Base,
|
|
1 => Dir,
|
|
2 => Over,
|
|
4 => Inf,
|
|
}
|
|
}
|
|
|
|
// EOF
|