1use crate::error::{Iso9660Error, Result};
4use crate::types::{FileEntry, SECTOR_SIZE};
5use gpt_disk_io::BlockIo;
6use gpt_disk_types::Lba;
7
8pub struct FileReader<'a, B: BlockIo> {
13 block_io: &'a mut B,
14 file: FileEntry,
15 position: u64,
16}
17
18impl<'a, B: BlockIo> FileReader<'a, B> {
19 pub fn new(block_io: &'a mut B, file: FileEntry) -> Self {
21 Self {
22 block_io,
23 file,
24 position: 0,
25 }
26 }
27
28 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
32 if self.position >= self.file.size {
33 return Ok(0);
34 }
35
36 let remaining = (self.file.size - self.position) as usize;
37 let to_read = buffer.len().min(remaining);
38
39 if to_read == 0 {
40 return Ok(0);
41 }
42
43 let start_sector = (self.position / SECTOR_SIZE as u64) as u32;
45 let offset_in_sector = (self.position % SECTOR_SIZE as u64) as usize;
46
47 let mut bytes_read = 0;
48 let mut sector_buf = [0u8; SECTOR_SIZE];
49 let mut current_sector = start_sector;
50 let mut current_offset = offset_in_sector;
51
52 while bytes_read < to_read {
53 let lba = Lba(self.file.extent_lba as u64 + current_sector as u64);
54 self.block_io.read_blocks(lba, &mut sector_buf)
55 .map_err(|_| Iso9660Error::IoError)?;
56
57 let available = SECTOR_SIZE - current_offset;
58 let chunk_size = available.min(to_read - bytes_read);
59
60 buffer[bytes_read..bytes_read + chunk_size]
61 .copy_from_slice(§or_buf[current_offset..current_offset + chunk_size]);
62
63 bytes_read += chunk_size;
64 current_sector += 1;
65 current_offset = 0; }
67
68 self.position += bytes_read as u64;
69 Ok(bytes_read)
70 }
71
72 pub fn seek(&mut self, pos: u64) {
74 self.position = pos.min(self.file.size);
75 }
76
77 pub fn seek_relative(&mut self, offset: i64) {
79 let new_pos = if offset < 0 {
80 self.position.saturating_sub((-offset) as u64)
81 } else {
82 self.position.saturating_add(offset as u64)
83 };
84 self.position = new_pos.min(self.file.size);
85 }
86
87 pub fn position(&self) -> u64 {
89 self.position
90 }
91
92 pub fn size(&self) -> u64 {
94 self.file.size
95 }
96
97 pub fn is_eof(&self) -> bool {
99 self.position >= self.file.size
100 }
101
102 pub fn remaining(&self) -> u64 {
104 self.file.size.saturating_sub(self.position)
105 }
106}