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#[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 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#[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 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#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
115#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
116pub enum SectorHeaderSize {
117 #[default]
119 Normal,
120 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}