//! Marathon Wad format handling. use std::collections::BTreeMap; use std::fmt; use durandal::bin::*; use durandal::machead::try_mac_header; use durandal::text::mac_roman_conv; type Chunk <'a> = &'a[u8]; type ChunkMap<'a> = BTreeMap>; type EntryMap<'a> = BTreeMap>; pub struct Entry<'a> { map: ChunkMap<'a>, ext: &'a[u8], } #[derive(Debug)] pub struct Wad<'a> { ver: u16, dvr: u16, ext: usize, nam: String, ent: EntryMap<'a>, } impl<'a> fmt::Debug for Entry<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Entry {{ ")?; for (k, _) in &self.map {write!(f, "{} ", mac_roman_conv(&k[..]))?} write!(f, "}}") } } impl<'a> Wad<'a> { pub fn new(b: &[u8]) -> Wad { let b = &b[try_mac_header(b)..]; let ver = b_u16b(&b[ 0.. 2]); let dvr = b_u16b(&b[ 2.. 4]); let nam = &b[ 4..68]; let crc = b_u32b(&b[68..72]); let dir = b_u32b(&b[72..76]) as usize; let num = b_u16b(&b[76..78]) as usize; let ext = b_u16b(&b[78..80]) as usize; println!("{:x}", crc); Wad{ver, dvr, ext, nam: mac_roman_conv(nam), ent: get_entries(num, ext, dir, b)} } } fn get_entries(num: usize, ext: usize, dir: usize, b: &[u8]) -> EntryMap { let mut p = dir; let mut map = EntryMap::new(); for _ in 0..num { let ofs = b_u32b(&b[p+0..p+ 4]) as usize; let len = b_u32b(&b[p+4..p+ 8]) as usize; let ind = b_u16b(&b[p+8..p+10]); let ent = Entry{map: get_chunks(&b[ ofs.. ofs+len]), ext: &b[p+10..p+10+ext]}; map.insert(ind, ent); p += 10 + ext; } map } fn get_chunks(b: &[u8]) -> ChunkMap { let mut p = 0; let mut map = ChunkMap::new(); while p < b.len() { let k = b_iden(&b[p+ 0..p+ 4]); // nx = b_u32b(&b[p+ 4..p+ 8]); let l = b_u32b(&b[p+ 8..p+12]) as usize; // ?? = b_u32b(&b[p+12..p+16]); map.insert(k, &b[p+16..p+ l]); p += l + 16; } map } // EOF