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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::slice::SliceIndex;
use byteorder::{ByteOrder, LittleEndian};
use crate::entry::Entry;
use crate::entry_id::EntryId;
use crate::error::Error;
use crate::iterator::*;
use crate::wad::*;
pub struct WadSlice<'a> {
data: &'a [u8],
directory: &'a [RawEntry],
}
impl<'a> WadSlice<'a> {
pub(crate) fn new<'n>(data: &'n [u8], directory: &'n [RawEntry]) -> WadSlice<'n> {
WadSlice { data, directory }
}
pub fn len(&self) -> usize {
self.directory.len()
}
pub fn entry_id_from_raw_entry(raw_entry: &RawEntry) -> EntryId {
let id = unsafe { &*(raw_entry[8..16].as_ptr() as *const _) };
EntryId::from_bytes(id)
}
pub unsafe fn entry_id_unchecked(&self, index: usize) -> EntryId {
let directory_entry = self.directory.get_unchecked(index);
Self::entry_id_from_raw_entry(directory_entry)
}
pub fn entry_id(&self, index: usize) -> Option<EntryId> {
let directory_entry = self.directory.get(index)?;
Some(Self::entry_id_from_raw_entry(directory_entry))
}
pub fn id_iter(&self) -> SliceIdIterator {
SliceIdIterator::new(self)
}
pub fn index_of(&self, id: impl Into<EntryId>) -> Option<usize> {
let id = id.into();
self.id_iter().position(|x| x == id)
}
pub fn entry_from_raw_entry(&self, raw_entry: &RawEntry) -> Result<Entry<'a>, Error> {
let start = LittleEndian::read_i32(&raw_entry[0..4]);
let length = LittleEndian::read_i32(&raw_entry[4..8]);
let id = Self::entry_id_from_raw_entry(raw_entry);
verify!(length >= 0, Error::InvalidEntry);
let length = length as usize;
verify!(start >= 0, Error::InvalidEntry);
let mut start = start as usize;
if length == 0 {
start = HEADER_BYTE_SIZE;
}
verify!(start >= HEADER_BYTE_SIZE, Error::InvalidEntry);
let end = start.checked_add(length).ok_or(Error::InvalidEntry)?;
verify!(end <= self.data.len(), Error::InvalidEntry);
let lump = &self.data[start..end];
Ok(Entry { id, lump })
}
pub unsafe fn entry_unchecked(&self, index: usize) -> Result<Entry<'a>, Error> {
let raw_entry = self.directory.get_unchecked(index);
self.entry_from_raw_entry(raw_entry)
}
pub fn entry(&self, index: usize) -> Result<Entry<'a>, Error> {
let raw_entry = self.directory.get(index).ok_or(Error::OutOfBounds)?;
self.entry_from_raw_entry(raw_entry)
}
pub fn entry_iter(&self) -> SliceEntryIterator {
SliceEntryIterator::new(self)
}
pub fn by_id(&self, id: impl Into<EntryId>) -> Option<&'a [u8]> {
let id = id.into();
let index = self.index_of(id)?;
let entry = self.entry(index).ok()?;
Some(entry.lump)
}
pub fn slice(&self, slice_index: impl SliceIndex<[RawEntry], Output = [RawEntry]>) -> WadSlice<'a> {
WadSlice::new(
self.data,
&self.directory[slice_index],
)
}
}
impl<'a> std::ops::Index<usize> for WadSlice<'a> {
type Output = [u8];
fn index(&self, index: usize) -> &Self::Output {
self.entry(index).unwrap().lump
}
}
impl<'a> From<&'a Wad> for WadSlice<'a> {
fn from(wad: &'a Wad) -> WadSlice<'a> {
wad.as_slice()
}
}