//! 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> { pub map: ChunkMap<'a>, pub ext: &'a[u8], } #[derive(Debug)] pub struct Wad<'a> { ver: Ver, dvr: u16, ext: usize, nam: String, pub ent: EntryMap<'a>, } #[derive(Debug)] pub enum Ver { MI, M2, M1Dir, M1 } 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 { const SIZE_ENTRY_NEW: usize = 10; const SIZE_ENTRY_OLD: usize = 8; let b = &b[try_mac_header(b)..]; let ver = b_u16b(&b[ .. 2]); let dvr = b_u16b(&b[ 2.. 4]); let nam = &b[ 4..68]; // 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; // hdr = b_u16b(&b[80..82]); // bsz = b_u16b(&b[82..84]); // pck = b_u32b(&b[84..88]); let ver = match ver { 4 => Ver::MI, 2 => Ver::M2, 1 => Ver::M1Dir, 0 => Ver::M1, _ => panic!("invalid wad version {}", ver), }; let mut map = EntryMap::new(); let mut p = dir; let o = match ver {Ver::M1 | Ver::M1Dir => true, _ => false}; let h = if o {SIZE_ENTRY_OLD} else {SIZE_ENTRY_NEW}; for i in 0..num { let ofs = b_u32b(&b[p ..p+ 4]) as usize; let len = b_u32b(&b[p+4..p+ 8]) as usize; let ind = if o {i as u16} else {b_u16b(&b[p+8..p+10])}; let ent = Entry{map: get_chunks(&b[ofs..ofs+len], o), ext: &b[p+h..p+h+ext]}; map.insert(ind, ent); p += h + ext; } Wad{ver, dvr, ext, nam: mac_roman_conv(nam), ent: map} } } fn get_chunks(b: &[u8], o: bool) -> ChunkMap { const SIZE_CHUNK_NEW: usize = 16; const SIZE_CHUNK_OLD: usize = 12; let mut map = ChunkMap::new(); let mut p = 0; let h = if o {SIZE_CHUNK_OLD} else {SIZE_CHUNK_NEW}; while p < b.len() { let k = b_iden(&b[p ..p+ 4]); // nx = b_u32b(&b[p+ 4..p+ 8]); let l = b_u32b(&b[p+ 8..p+12]) as usize; // o = b_u32b(&b[p+12..p+16]); map.insert(k, &b[p+h ..p+h+l]); p += l + h; } map } // EOF