iso9660_forensic/
file_reader.rs1use std::io::{self, Read, Seek, SeekFrom};
7
8use crate::sector::{read_sector_data, SectorMode};
9
10type Extent = (u32, u32);
12
13pub struct IsoFileReader<R> {
17 inner: R,
18 mode: SectorMode,
19 extents: Vec<Extent>, total: u32, ext_idx: usize, ext_pos: u32, sector_buf: [u8; 2048],
26 buf_start: u32, buf_valid: usize, buf_pos: usize, }
30
31impl<R: Read + Seek> IsoFileReader<R> {
32 pub(crate) fn new(
33 inner: R,
34 mode: SectorMode,
35 primary_lba: u32,
36 primary_size: u32,
37 extra_extents: Vec<Extent>,
38 ) -> Self {
39 let total = primary_size + extra_extents.iter().map(|e| e.1).sum::<u32>();
40 let mut extents = Vec::with_capacity(1 + extra_extents.len());
41 extents.push((primary_lba, primary_size));
42 extents.extend_from_slice(&extra_extents);
43
44 Self {
45 inner,
46 mode,
47 extents,
48 total,
49 ext_idx: 0,
50 ext_pos: 0,
51 sector_buf: [0u8; 2048],
52 buf_start: u32::MAX, buf_valid: 0,
54 buf_pos: 0,
55 }
56 }
57
58 pub fn size(&self) -> u32 {
60 self.total
61 }
62
63 fn ensure_buf(&mut self) -> io::Result<()> {
65 if self.ext_idx >= self.extents.len() {
66 return Ok(());
67 }
68 let (lba, size) = self.extents[self.ext_idx];
69 if size == 0 {
70 return Ok(());
71 }
72 let sector_start = (self.ext_pos / 2048) * 2048;
73 if self.buf_start == sector_start {
74 return Ok(()); }
76 let sector_idx = sector_start / 2048;
77 read_sector_data(
78 &mut self.inner,
79 self.mode,
80 lba as u64 + sector_idx as u64,
81 &mut self.sector_buf,
82 )
83 .map_err(|e| io::Error::other(e.to_string()))?;
84
85 let remaining_in_extent = size - sector_start;
86 self.buf_valid = remaining_in_extent.min(2048) as usize;
87 self.buf_start = sector_start;
88 self.buf_pos = (self.ext_pos - sector_start) as usize;
89 Ok(())
90 }
91}
92
93impl<R: Read + Seek> Seek for IsoFileReader<R> {
94 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
95 let current_abs: i64 = {
96 let before: u32 = self.extents[..self.ext_idx].iter().map(|e| e.1).sum();
97 before as i64 + self.ext_pos as i64
98 };
99 let new_abs = match pos {
100 SeekFrom::Start(p) => p as i64,
101 SeekFrom::End(p) => self.total as i64 + p,
102 SeekFrom::Current(p) => current_abs + p,
103 };
104 let new_abs = new_abs.clamp(0, self.total as i64) as u32;
105
106 let mut remaining = new_abs;
108 let mut new_idx = self.extents.len(); let mut new_pos = 0u32;
110 for (i, &(_, size)) in self.extents.iter().enumerate() {
111 if remaining < size || (remaining == size && i + 1 == self.extents.len()) {
112 new_idx = i;
113 new_pos = remaining;
114 break;
115 }
116 remaining -= size;
117 }
118
119 self.ext_idx = new_idx;
120 self.ext_pos = new_pos;
121 self.buf_start = u32::MAX; self.buf_valid = 0;
123 self.buf_pos = 0;
124
125 Ok(new_abs as u64)
126 }
127}
128
129impl<R: Read + Seek> Read for IsoFileReader<R> {
130 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
131 if buf.is_empty() {
132 return Ok(0);
133 }
134 let mut written = 0;
135 while written < buf.len() {
136 if self.ext_idx >= self.extents.len() {
137 break;
138 }
139 let (_, size) = self.extents[self.ext_idx];
140 if self.ext_pos >= size {
141 self.ext_idx += 1;
143 self.ext_pos = 0;
144 self.buf_start = u32::MAX;
145 continue;
146 }
147 self.ensure_buf()?;
148 let available = self.buf_valid - self.buf_pos;
149 if available == 0 {
150 break;
151 }
152 let to_copy = available.min(buf.len() - written);
153 buf[written..written + to_copy]
154 .copy_from_slice(&self.sector_buf[self.buf_pos..self.buf_pos + to_copy]);
155 written += to_copy;
156 self.buf_pos += to_copy;
157 self.ext_pos += to_copy as u32;
158 }
159 Ok(written)
160 }
161}