1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
//! WAD submodule.
//! Contains the actual WAD struct and helper functions.

use super::structures::*;
use std::path::Path;
use std::fs;
use std::io::Read;
use std::mem::{transmute, size_of};

/// Error type for working with the WAD file.
#[derive(Debug)]
pub enum WadError {
    EntryNotFound(String),
}

/// The actual WAD itself. Contains the WAD header, all directory entries and all the data stored in the WAD.
#[derive(Debug)]
pub struct Wad {
    pub header: Header,
    pub directory: Vec<DirEntry>,
    pub data_offset: usize,
    pub data: Vec<u8>
}
impl Wad {
    /// Parses a Header from a WAD file and returns it.
    pub fn parse_header(h: &[u8]) -> Header {
        let mut buf = [0u8; size_of::<Header>()];
        (&h[0..]).read(&mut buf).unwrap();
        unsafe {
            transmute(buf)
        }
    }
    /// Parses all of the DirEntries in the WAD file and returns them.
    pub fn parse_entries(count: usize, d: &[u8]) -> Vec<DirEntry> {
        let mut tmp = Vec::new();
        let mut tmp_entry = DirEntry {
            ptr: 0,
            size: 0,
            name: [0;8]
        };
        let mut buf = [0u8; size_of::<DirEntry>()];
        for i in 0..count {
            (&d[i*size_of::<DirEntry>()..]).read(&mut buf).unwrap();
            tmp_entry = unsafe {transmute(buf)};
            tmp.push(tmp_entry);
        }
        tmp
    }
    /// Loads a WAD file
    pub fn load(path: &Path) -> Wad {
        let mut file = fs::File::open(path).unwrap();
        let mut bytes = Vec::with_capacity(file.metadata().unwrap().len() as usize);
        file.read_to_end(&mut bytes).unwrap();

        let header = Self::parse_header(&bytes);
        let entries = Self::parse_entries(header.entry_no as usize, &bytes[header.dir_ptr as usize..]);

        let offset = entries[0].ptr as usize;

        let data = (&bytes[offset..header.dir_ptr as usize]).to_vec();

        Wad {
            header: header,
            directory: entries,
            data_offset: offset,
            data: data
        }
    }

    /// Indexes a WAD file for an entry.
    pub fn get_entry(&self, name: &[u8;8]) -> Result<Vec<Vec<u8>>, WadError> {
        let mut tmp = Vec::new();
        for entry in self.directory.iter() {
            if entry.name == *name {
                tmp.push(Vec::from(&self.data[entry.ptr as usize - self.data_offset..entry.size as usize]));
                break;
            }
        }
        if tmp.len() == 0 {
            Err(WadError::EntryNotFound(String::from_utf8(name.to_vec()).unwrap()))
        } else {
            Ok(tmp)
        }
    }
    pub unsafe fn get_entry_as<T>(&self, name: &[u8;8]) -> Result<Vec<&T>, WadError> {
        let entries = &self.get_entry(name)?[..];
        let mut tmp = Vec::new();

        for entry in entries.iter() {
            tmp.push((entry.as_ptr() as *const T).as_ref().unwrap());
        }

        Ok(tmp)
    }
}