rgpre/import/rob/
index.rs1use super::{RobHeader, RobSegment, parser};
2use crate::{Result, error::Error};
3use std::io::{Read, Seek, SeekFrom};
4
5pub struct RobIndex {
7 pub header: RobHeader,
8 pub segments: Vec<RobSegment>,
10 offsets: Vec<u64>,
11}
12impl RobIndex {
13 pub fn read(reader: &mut (impl Read + Seek)) -> Result<Self> {
15 let length = reader.seek(SeekFrom::End(0))?;
16 reader.seek(SeekFrom::Start(0))?;
17 let mut bytes = [0; 20];
18 reader.read_exact(&mut bytes)?;
19 let (remaining, header) = parser::parse_rob_header(&bytes)?;
20 let mut position = 20 - remaining.len() as u64;
21 if u64::from(header.num_segments) > length.saturating_sub(position) / 80 {
22 return Err(Error::Parse("ROB segment count exceeds file length".into()));
23 }
24 let mut segments = Vec::new();
25 let mut offsets = Vec::new();
26 for index in 0..header.num_segments {
27 reader.seek(SeekFrom::Start(position))?;
28 let mut bytes = [0; 80];
29 reader.read_exact(&mut bytes)?;
30 let (_, segment) = parser::parse_rob_segment_header(&bytes)?;
31 position += 80;
32 offsets.push(position);
33 if !segment.points_to_external_file() {
34 position += u64::from(segment.data_size);
35 }
36 if position > length {
37 return Err(Error::Parse(format!(
38 "ROB segment {index}: payload exceeds file length"
39 )));
40 }
41 segments.push(segment);
42 }
43 Ok(Self {
44 header,
45 segments,
46 offsets,
47 })
48 }
49
50 pub fn read_segment(
52 &self,
53 reader: &mut (impl Read + Seek),
54 index: usize,
55 ) -> Result<RobSegment> {
56 let mut segment = self
57 .segments
58 .get(index)
59 .ok_or_else(|| Error::Parse(format!("ROB segment {index} missing")))?
60 .clone();
61 if !segment.points_to_external_file() {
62 reader.seek(SeekFrom::Start(self.offsets[index]))?;
63 segment.data.resize(
64 usize::try_from(segment.data_size).map_err(|e| Error::Parse(e.to_string()))?,
65 0,
66 );
67 reader.read_exact(&mut segment.data)?;
68 }
69 Ok(segment)
70 }
71}