Maraiah/src/marathon/wad.rs

115 lines
3.0 KiB
Rust
Raw Normal View History

2018-09-06 09:01:52 -07:00
//! Marathon Wad format handling.
use crate::durandal::{bin::*, err::*, text::mac_roman_conv};
2018-12-10 23:33:38 -08:00
use std::{collections::BTreeMap, fmt};
2018-09-06 09:01:52 -07:00
2018-12-10 23:33:38 -08:00
impl Wad<'_>
2018-09-06 09:01:52 -07:00
{
2018-09-11 12:07:42 -07:00
pub fn new(b: &[u8]) -> ResultS<Wad>
2018-09-06 09:01:52 -07:00
{
2019-02-05 14:51:49 -08:00
if b.len() < 128 {return Err(err_msg("not enough data for Wad header"));}
2018-12-10 23:32:59 -08:00
let wadver = b.c_u16b( 0)?;
let dataver = b.c_u16b( 2)?;
let origname = mac_roman_conv(&b[4..68]);
// crc = b.c_u32b(68)?;
let dirofs = b.c_u32b(72)? as usize;
let numents = b.c_u16b(76)? as usize;
let appsize = b.c_u16b(78)? as usize;
2019-02-05 23:01:47 -08:00
let wcnksize = b.c_u16b(80)? as usize;
let wentsize = b.c_u16b(82)? as usize;
2018-12-10 23:32:59 -08:00
// parent = b.c_u32b(84)?;
2019-02-05 23:01:47 -08:00
let wadver = Ver::from_repr(wadver)?;
2018-12-10 23:32:59 -08:00
let is_old = match wadver {Ver::Base => true, _ => false};
2019-02-05 23:01:47 -08:00
let entsize = if !is_old {10} else {8 };
let cnksize = if !is_old {16} else {12};
if entsize != wentsize {return Err(err_msg("invalid entry size"));}
if cnksize != wcnksize {return Err(err_msg("invalid chunk size"));}
2018-12-10 23:32:59 -08:00
let mut entries = EntryMap::new();
let mut p = dirofs;
2018-09-09 15:21:17 -07:00
2018-12-11 16:06:51 -08:00
for i in 0..numents {
2018-12-10 23:32:59 -08:00
let offset = b.c_u32b(p )? as usize;
let size = b.c_u32b(p+4)? as usize;
let index = if !is_old {b.c_u16b(p+8)?} else {i as u16};
2018-09-11 12:07:42 -07:00
2019-02-05 14:51:49 -08:00
if offset + size > b.len() {return Err(err_msg("not enough data for entry"));}
2018-09-11 12:07:42 -07:00
2019-02-05 23:01:47 -08:00
let chunks = get_chunks(&b[offset..offset+size], cnksize)?;
let appdata = &b[p..p+appsize];
2018-09-09 15:21:17 -07:00
2018-12-10 23:32:59 -08:00
entries.insert(index, Entry{chunks, appdata});
2018-09-09 15:21:17 -07:00
2018-12-10 23:32:59 -08:00
p += entsize + appsize;
2018-09-09 15:21:17 -07:00
}
2018-09-06 09:01:52 -07:00
2018-12-10 23:32:59 -08:00
Ok(Wad{wadver, dataver, appsize, origname, entries})
2018-09-06 09:01:52 -07:00
}
}
2019-02-05 23:01:47 -08:00
fn get_chunks(b: &[u8], cnksize: usize) -> ResultS<ChunkMap>
2018-09-06 09:01:52 -07:00
{
2018-12-10 23:32:59 -08:00
let mut chunks = ChunkMap::new();
let mut p = 0;
2018-09-06 09:01:52 -07:00
2018-12-11 16:06:51 -08:00
while p < b.len() {
2019-02-05 23:01:47 -08:00
let iden = b.c_iden(p )?;
// ofs = b.c_u32b(p+ 4)?;
let size = b.c_u32b(p+ 8)? as usize;
// pofs = b.c_u32b(p+12)?;
let beg = p + cnksize;
let end = beg + size;
chunks.insert(iden, &b[beg..end]);
2018-12-10 23:32:59 -08:00
p = end;
2018-09-06 09:01:52 -07:00
}
2018-12-10 23:32:59 -08:00
Ok(chunks)
2018-09-06 09:01:52 -07:00
}
2018-12-13 01:06:57 -08:00
type Chunk <'a> = &'a[u8];
type ChunkMap<'a> = BTreeMap<Ident, Chunk<'a>>;
type EntryMap<'a> = BTreeMap<u16 , Entry<'a>>;
pub struct Entry<'a>
{
pub chunks: ChunkMap<'a>,
pub appdata: &'a[u8],
}
#[derive(Debug)]
pub struct Wad<'a>
{
wadver: Ver,
dataver: u16,
origname: String,
appsize: usize,
pub entries: EntryMap<'a>,
}
c_enum! {
#[derive(Debug)]
2018-12-13 01:06:57 -08:00
pub enum Ver: u16
{
0 => Base,
1 => Dir,
2 => Over,
2019-02-05 14:51:49 -08:00
4 => Inf,
2018-12-13 01:06:57 -08:00
}
}
impl fmt::Debug for Entry<'_>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
{
write!(f, "Entry{{ ")?;
2019-02-05 23:01:47 -08:00
for (iden, _) in &self.chunks {write!(f, "{} ", mac_roman_conv(iden))?;}
if self.appdata.len() != 0 {write!(f, "\nappdata: {:?} ", self.appdata)?;}
2018-12-13 01:06:57 -08:00
write!(f, "}}")
}
}
2018-09-06 09:01:52 -07:00
// EOF