1use crate::block::{EntryBlock, FileExtBlock, OfsDataBlock};
4use crate::constants::*;
5use crate::error::{AffsError, Result};
6use crate::types::{BlockDevice, FsType};
7
8pub struct FileReader<'a, D: BlockDevice> {
27 device: &'a D,
28 fs_type: FsType,
29 file_size: u32,
31 remaining: u32,
33 block_index: u32,
35 blocks_in_current: u32,
37 index_in_current: u32,
39 data_blocks: [u32; MAX_DATABLK],
41 next_extension: u32,
43 current_data_block: u32,
45 offset_in_block: usize,
47 buf: [u8; BLOCK_SIZE],
49}
50
51impl<'a, D: BlockDevice> FileReader<'a, D> {
52 pub fn new(device: &'a D, fs_type: FsType, header_block: u32) -> Result<Self> {
59 let mut buf = [0u8; BLOCK_SIZE];
60 device
61 .read_block(header_block, &mut buf)
62 .map_err(|()| AffsError::BlockReadError)?;
63
64 let entry = EntryBlock::parse(&buf)?;
65
66 if !entry.is_file() {
67 return Err(AffsError::NotAFile);
68 }
69
70 let file_size = entry.byte_size;
71 let blocks_in_current = entry.high_seq as u32;
72
73 let mut data_blocks = [0u32; MAX_DATABLK];
75 data_blocks.copy_from_slice(&entry.hash_table);
76
77 Ok(Self {
78 device,
79 fs_type,
80 file_size,
81 remaining: file_size,
82 block_index: 0,
83 blocks_in_current,
84 index_in_current: 0,
85 data_blocks,
86 next_extension: entry.extension,
87 current_data_block: entry.first_data,
88 offset_in_block: 0,
89 buf,
90 })
91 }
92
93 pub fn from_entry(device: &'a D, fs_type: FsType, entry: &EntryBlock) -> Result<Self> {
97 if !entry.is_file() {
98 return Err(AffsError::NotAFile);
99 }
100
101 let file_size = entry.byte_size;
102 let blocks_in_current = entry.high_seq as u32;
103
104 let mut data_blocks = [0u32; MAX_DATABLK];
105 data_blocks.copy_from_slice(&entry.hash_table);
106
107 Ok(Self {
108 device,
109 fs_type,
110 file_size,
111 remaining: file_size,
112 block_index: 0,
113 blocks_in_current,
114 index_in_current: 0,
115 data_blocks,
116 next_extension: entry.extension,
117 current_data_block: entry.first_data,
118 offset_in_block: 0,
119 buf: [0u8; BLOCK_SIZE],
120 })
121 }
122
123 #[inline]
125 pub const fn size(&self) -> u32 {
126 self.file_size
127 }
128
129 #[inline]
131 pub const fn remaining(&self) -> u32 {
132 self.remaining
133 }
134
135 #[inline]
137 pub const fn is_eof(&self) -> bool {
138 self.remaining == 0
139 }
140
141 #[inline]
143 pub const fn position(&self) -> u32 {
144 self.file_size - self.remaining
145 }
146
147 pub fn read(&mut self, out: &mut [u8]) -> Result<usize> {
151 if self.remaining == 0 || out.is_empty() {
152 return Ok(0);
153 }
154
155 let mut total_read = 0;
156
157 while total_read < out.len() && self.remaining > 0 {
158 if self.offset_in_block == 0 || self.offset_in_block >= self.data_block_size() {
160 self.read_next_data_block()?;
161 }
162
163 let data_size = self.current_block_data_size();
165 let available = data_size.saturating_sub(self.offset_in_block);
166 let to_read = available
167 .min(out.len() - total_read)
168 .min(self.remaining as usize);
169
170 if to_read == 0 {
171 break;
172 }
173
174 let data_start = self.data_offset();
176 let src = &self.buf
177 [data_start + self.offset_in_block..data_start + self.offset_in_block + to_read];
178 out[total_read..total_read + to_read].copy_from_slice(src);
179
180 total_read += to_read;
181 self.offset_in_block += to_read;
182 self.remaining -= to_read as u32;
183 }
184
185 Ok(total_read)
186 }
187
188 pub fn read_all(&mut self, out: &mut [u8]) -> Result<usize> {
193 if out.len() < self.remaining as usize {
194 return Err(AffsError::BufferTooSmall);
195 }
196
197 let mut total = 0;
198 while self.remaining > 0 {
199 let n = self.read(&mut out[total..])?;
200 if n == 0 {
201 break;
202 }
203 total += n;
204 }
205 Ok(total)
206 }
207
208 #[inline]
210 const fn data_block_size(&self) -> usize {
211 match self.fs_type {
212 FsType::Ofs => OFS_DATA_SIZE,
213 FsType::Ffs => FFS_DATA_SIZE,
214 }
215 }
216
217 #[inline]
219 const fn data_offset(&self) -> usize {
220 match self.fs_type {
221 FsType::Ofs => OfsDataBlock::HEADER_SIZE,
222 FsType::Ffs => 0,
223 }
224 }
225
226 fn current_block_data_size(&self) -> usize {
228 match self.fs_type {
229 FsType::Ofs => {
230 let header = OfsDataBlock::parse(&self.buf).ok();
233 header.map(|h| h.data_size as usize).unwrap_or(0)
234 }
235 FsType::Ffs => {
236 let block_size = FFS_DATA_SIZE;
238 let remaining = self.remaining as usize + self.offset_in_block;
239 remaining.min(block_size)
240 }
241 }
242 }
243
244 fn read_next_data_block(&mut self) -> Result<()> {
246 let block = self.get_next_data_block()?;
247 if block == 0 {
248 return Err(AffsError::EndOfFile);
249 }
250
251 self.device
252 .read_block(block, &mut self.buf)
253 .map_err(|()| AffsError::BlockReadError)?;
254
255 if matches!(self.fs_type, FsType::Ofs) {
257 let _ = OfsDataBlock::parse(&self.buf)?;
258 }
259
260 self.offset_in_block = 0;
261 self.block_index += 1;
262 Ok(())
263 }
264
265 fn get_next_data_block(&mut self) -> Result<u32> {
267 match self.fs_type {
268 FsType::Ofs => self.get_next_ofs_block(),
269 FsType::Ffs => self.get_next_ffs_block(),
270 }
271 }
272
273 fn get_next_ofs_block(&mut self) -> Result<u32> {
275 if self.block_index == 0 {
276 return Ok(self.current_data_block);
279 }
280
281 let header = OfsDataBlock::parse(&self.buf)?;
284 self.current_data_block = header.next_data;
285 Ok(self.current_data_block)
286 }
287
288 fn get_next_ffs_block(&mut self) -> Result<u32> {
290 if self.index_in_current >= self.blocks_in_current {
292 if self.next_extension == 0 {
293 return Ok(0); }
295
296 self.device
298 .read_block(self.next_extension, &mut self.buf)
299 .map_err(|()| AffsError::BlockReadError)?;
300
301 let ext = FileExtBlock::parse(&self.buf)?;
302
303 self.data_blocks.copy_from_slice(&ext.data_blocks);
305 self.blocks_in_current = ext.high_seq as u32;
306 self.next_extension = ext.extension;
307 self.index_in_current = 0;
308 }
309
310 if self.index_in_current >= self.blocks_in_current {
311 return Ok(0);
312 }
313
314 let idx = self.index_in_current as usize;
316 let block = if idx < MAX_DATABLK {
317 self.data_blocks[MAX_DATABLK - 1 - idx]
318 } else {
319 0
320 };
321
322 self.index_in_current += 1;
323 Ok(block)
324 }
325
326 pub fn seek(&mut self, position: u32) -> Result<()> {
331 if position > self.file_size {
332 return Err(AffsError::EndOfFile);
333 }
334
335 if position == self.position() {
336 return Ok(());
337 }
338
339 if position < self.position() {
342 return Err(AffsError::InvalidState);
345 }
346
347 let mut discard = [0u8; 512];
349 let mut to_skip = position - self.position();
350 while to_skip > 0 {
351 let n = self.read(&mut discard[..to_skip.min(512) as usize])?;
352 if n == 0 {
353 return Err(AffsError::EndOfFile);
354 }
355 to_skip -= n as u32;
356 }
357
358 Ok(())
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365
366 struct DummyDevice;
367
368 impl BlockDevice for DummyDevice {
369 fn read_block(&self, _block: u32, _buf: &mut [u8; 512]) -> core::result::Result<(), ()> {
370 Err(())
371 }
372 }
373
374 #[test]
375 fn test_file_reader_error_on_bad_device() {
376 let device = DummyDevice;
377 let result = FileReader::new(&device, FsType::Ffs, 100);
378 assert!(result.is_err());
379 }
380}