runefs/
sector.rs

1use nom::{
2    combinator::rest,
3    number::complete::{be_u16, be_u24, be_u32, be_u8},
4};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::{archive::ArchiveRef, error::ReadError};
9
10pub const SECTOR_HEADER_SIZE: usize = 8;
11pub const SECTOR_EXPANDED_HEADER_SIZE: usize = 10;
12pub const SECTOR_DATA_SIZE: usize = 512;
13pub const SECTOR_EXPANDED_DATA_SIZE: usize = 510;
14pub const SECTOR_SIZE: usize = SECTOR_HEADER_SIZE + SECTOR_DATA_SIZE;
15
16/// A section of data read from the `Dat2` file.
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
19pub struct Sector<'a> {
20    pub header: SectorHeader,
21    pub data_block: &'a [u8],
22}
23
24impl<'a> Sector<'a> {
25    /// Creates a sector from the given buffer using the header size to correctly initiate
26    /// the root sector.
27    /// 
28    /// # Errors
29    /// 
30    /// Either a `SectorHeader` couldn't be initiated due to a wrong buffer or 
31    /// there are no more bytes after the initial header.
32    pub fn new(buffer: &'a [u8], header_size: &SectorHeaderSize) -> crate::Result<Self> {
33        let (buffer, header) = SectorHeader::new(buffer, header_size)?;
34        let (_, data_block) = rest(buffer)?;
35
36        Ok(Self { header, data_block })
37    }
38}
39
40/// A section header containing validation and its next sector.
41#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
42#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
43pub struct SectorHeader {
44    pub archive_id: u32,
45    pub chunk: usize,
46    pub next: usize,
47    pub index_id: u8,
48}
49
50impl<'a> SectorHeader {
51    /// Constructs a sector header from the given buffer.
52    /// 
53    /// Each sector is guaranteed to have a length of 520 bytes. The header size
54    /// will be either 8 or 10 bytes, making the data size either 512 or 510 bytes 
55    /// respectively. Only when the archive id exceeds `u16::MAX` will the header size
56    /// be expanded (meaning a 10 byte header).
57    /// 
58    /// # Errors
59    /// 
60    /// The header buffer needs to be exactly `SectorHeaderSize`, otherwise you will
61    /// get a parser error. 
62    pub fn new(
63        buffer: &'a [u8],
64        header_size: &SectorHeaderSize,
65    ) -> crate::Result<(&'a [u8], Self)> {
66        let (buffer, archive_id) = match header_size {
67            SectorHeaderSize::Normal => {
68                let (buffer, archive_id) = be_u16(buffer)?;
69                (buffer, archive_id as u32)
70            }
71            SectorHeaderSize::Expanded => be_u32(buffer)?,
72        };
73        let (buffer, chunk) = be_u16(buffer)?;
74        let (buffer, next) = be_u24(buffer)?;
75        let (buffer, index_id) = be_u8(buffer)?;
76
77        Ok((
78            buffer,
79            Self {
80                archive_id,
81                chunk: chunk as usize,
82                next: next as usize,
83                index_id,
84            },
85        ))
86    }
87
88    pub const fn validate(
89        &self,
90        archive_id: u32,
91        chunk: usize,
92        index_id: u8,
93    ) -> Result<(), ReadError> {
94        if self.archive_id != archive_id {
95            return Err(ReadError::SectorArchiveMismatch(
96                self.archive_id,
97                archive_id,
98            ));
99        }
100
101        if self.chunk != chunk {
102            return Err(ReadError::SectorChunkMismatch(self.chunk, chunk));
103        }
104
105        if self.index_id != index_id {
106            return Err(ReadError::SectorIndexMismatch(self.index_id, index_id));
107        }
108
109        Ok(())
110    }
111}
112
113/// Used to convey a sector's header size when parsing from a raw buffer.
114#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
115#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
116pub enum SectorHeaderSize {
117    /// 8 byte header length.
118    #[default]
119    Normal,
120    /// 10 byte header length.
121    Expanded,
122}
123
124impl From<&ArchiveRef> for SectorHeaderSize {
125    fn from(archive: &ArchiveRef) -> Self {
126        if archive.id > u16::MAX.into() {
127            Self::Expanded
128        } else {
129            Self::Normal
130        }
131    }
132}
133
134#[test]
135fn header_size_normal() -> crate::Result<()> {
136    let archive = ArchiveRef {
137        id: u16::MAX as u32,
138        index_id: 0,
139        sector: 0,
140        length: 0,
141    };
142    let header_size = SectorHeaderSize::from(&archive);
143
144    assert_eq!(header_size, SectorHeaderSize::Normal);
145
146    Ok(())
147}
148
149#[test]
150fn header_size_expanded() -> crate::Result<()> {
151    let archive = ArchiveRef {
152        id: (u16::MAX as u32) + 1,
153        index_id: 0,
154        sector: 0,
155        length: 0,
156    };
157    let header_size = SectorHeaderSize::from(&archive);
158
159    assert_eq!(header_size, SectorHeaderSize::Expanded);
160
161    Ok(())
162}
163
164#[test]
165fn parse_header() -> crate::Result<()> {
166    let buffer = &[0, 0, 0, 0, 0, 0, 2, 255];
167    let (_, header) = SectorHeader::new(buffer, &SectorHeaderSize::Normal)?;
168
169    assert_eq!(
170        header,
171        SectorHeader {
172            archive_id: 0,
173            chunk: 0,
174            next: 2,
175            index_id: 255
176        }
177    );
178
179    Ok(())
180}
181
182#[test]
183fn header_validation() {
184    let header = SectorHeader {
185        archive_id: 0,
186        chunk: 0,
187        next: 2,
188        index_id: 255,
189    };
190
191    assert_eq!(
192        header.validate(1, 0, 255),
193        Err(ReadError::SectorArchiveMismatch(header.archive_id, 1))
194    );
195    assert_eq!(
196        header.validate(0, 1, 255),
197        Err(ReadError::SectorChunkMismatch(header.chunk, 1))
198    );
199    assert_eq!(
200        header.validate(0, 0, 0),
201        Err(ReadError::SectorIndexMismatch(header.index_id, 0))
202    );
203}