Maraiah/src/marathon/wad.rs

144 lines
2.9 KiB
Rust
Raw Normal View History

2019-02-08 21:08:53 -08:00
//! Marathon Wad format handling.
use crate::durandal::{bin::*, err::*, text::mac_roman_conv};
use serde::Serialize;
2019-02-08 21:08:53 -08:00
use std::{collections::BTreeMap, fmt};
impl Wad<'_>
{
2019-02-24 20:34:59 -08:00
pub fn new(b: &[u8]) -> ResultS<Wad<'_>>
2019-02-08 21:08:53 -08:00
{
2019-02-18 20:06:34 -08:00
read_data! {
128, BE in b =>
wadver = u16[0];
dataver = u16[2];
2019-02-21 11:24:20 -08:00
origname = mac_roman_conv[4..68] nt;
2019-02-18 20:06:34 -08:00
dirofs = u32[72] as usize;
numents = u16[76] as usize;
appsize = u16[78] as usize;
wcnksize = u16[80] as usize;
wentsize = u16[82] as usize;
}
2019-02-21 11:24:20 -08:00
let wadver = Ver::from_repr(wadver)?;
2019-02-08 21:08:53 -08:00
2019-02-08 21:53:27 -08:00
let is_old = match wadver {
Ver::Base => true,
_ => false,
};
2019-02-20 15:39:29 -08:00
2019-02-24 20:34:59 -08:00
let entsize = if is_old {8 } else {10};
let cnksize = if is_old {12} else {16};
2019-02-08 21:08:53 -08:00
2019-02-08 21:53:27 -08:00
if entsize != wentsize {
2019-02-10 02:31:57 -08:00
bail!("invalid entry size");
2019-02-08 21:53:27 -08:00
}
if cnksize != wcnksize {
2019-02-10 02:31:57 -08:00
bail!("invalid chunk size");
2019-02-08 21:53:27 -08:00
}
2019-02-08 21:08:53 -08:00
let mut entries = EntryMap::new();
let mut p = dirofs;
for i in 0..numents {
2019-02-18 20:06:34 -08:00
read_data! {
p + entsize, BE in b =>
offset = u32[p] as usize;
size = u32[p + 4] as usize;
index = u16[p + 8];
}
2019-02-24 20:34:59 -08:00
let index = if is_old {i as u16} else {index};
2019-02-08 21:08:53 -08:00
2019-02-18 20:06:34 -08:00
let cnkdata = &b[offset..offset + size];
2019-02-10 02:31:57 -08:00
let chunks = get_chunks(cnkdata, cnksize)?;
2019-02-18 20:06:34 -08:00
let appdata = &b[p..p + appsize];
2019-02-08 21:08:53 -08:00
entries.insert(index, Entry{chunks, appdata});
p += entsize + appsize;
}
2019-02-12 15:03:18 -08:00
Ok(Wad{head: WadHeader{wadver, dataver, appsize, origname}, entries})
2019-02-08 21:08:53 -08:00
}
}
2019-02-24 20:34:59 -08:00
fn get_chunks(b: &[u8], cnksize: usize) -> ResultS<ChunkMap<'_>>
2019-02-08 21:08:53 -08:00
{
let mut chunks = ChunkMap::new();
let mut p = 0;
while p < b.len() {
2019-02-18 20:06:34 -08:00
read_data! {
p + cnksize, BE in b =>
iden = iden[p];
size = u32[p + 8] as usize;
}
2019-02-20 18:33:57 -08:00
let beg = p + cnksize;
let end = beg + size;
2019-02-18 20:06:34 -08:00
chunks.insert(iden, &b[beg..end]);
2019-02-08 21:08:53 -08:00
p = end;
}
Ok(chunks)
}
2019-02-08 21:53:27 -08:00
type Chunk<'a> = &'a [u8];
2019-02-08 21:08:53 -08:00
type ChunkMap<'a> = BTreeMap<Ident, Chunk<'a>>;
2019-02-08 21:53:27 -08:00
type EntryMap<'a> = BTreeMap<u16, Entry<'a>>;
2019-02-08 21:08:53 -08:00
2019-02-12 15:03:18 -08:00
#[derive(Serialize)]
2019-02-08 21:08:53 -08:00
pub struct Entry<'a>
{
2019-02-08 21:53:27 -08:00
pub chunks: ChunkMap<'a>,
pub appdata: &'a [u8],
2019-02-08 21:08:53 -08:00
}
2019-02-12 15:03:18 -08:00
#[derive(Debug, Serialize)]
pub struct WadHeader
{
pub wadver: Ver,
pub dataver: u16,
pub origname: String,
pub appsize: usize,
}
#[derive(Debug, Serialize)]
2019-02-08 21:08:53 -08:00
pub struct Wad<'a>
{
2019-02-12 15:03:18 -08:00
pub head: WadHeader,
2019-02-08 21:53:27 -08:00
pub entries: EntryMap<'a>,
2019-02-08 21:08:53 -08:00
}
c_enum! {
#[derive(Debug, Serialize)]
2019-02-08 21:08:53 -08:00
pub enum Ver: u16
{
0 => Base,
1 => Dir,
2 => Over,
4 => Inf,
}
}
impl fmt::Debug for Entry<'_>
{
2019-02-24 20:34:59 -08:00
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
2019-02-08 21:08:53 -08:00
{
write!(f, "Entry{{ ")?;
2019-02-13 21:19:36 -08:00
for iden in self.chunks.keys() {
2019-02-08 21:53:27 -08:00
write!(f, "{} ", mac_roman_conv(iden))?;
}
2019-02-13 21:19:36 -08:00
if !self.appdata.is_empty() {
2019-02-08 21:53:27 -08:00
write!(f, "\nappdata: {:?} ", self.appdata)?;
}
2019-02-08 21:08:53 -08:00
write!(f, "}}")
}
}
// EOF