pe_assembler/formats/obj/
reader.rs

1use crate::{
2    helpers::CoffReader,
3    types::coff::{CoffHeader, CoffInfo, CoffObject, SectionHeader},
4};
5use byteorder::LittleEndian;
6use gaia_types::{BinaryReader, GaiaDiagnostics, GaiaError};
7use std::{
8    fs::File,
9    io::{Read, Seek},
10    path::Path,
11};
12
13/// COFF 对象文件 (.obj) 结构,惰性读取器
14#[derive(Debug)]
15pub struct ObjReader<R> {
16    /// 二进制读取器(已定位到对象文件起始位置)
17    viewer: BinaryReader<R, LittleEndian>,
18    lazy_header: Option<CoffHeader>,
19    lazy_section_headers: Option<Vec<SectionHeader>>,
20    lazy_object: Option<CoffObject>,
21    lazy_info: Option<CoffInfo>,
22    diagnostics: Vec<GaiaError>,
23}
24
25impl<R> ObjReader<R> {
26    pub fn new(reader: R) -> Self {
27        Self {
28            viewer: BinaryReader::new(reader),
29            lazy_header: None,
30            lazy_section_headers: None,
31            lazy_object: None,
32            lazy_info: None,
33            diagnostics: vec![],
34        }
35    }
36}
37
38impl<W: Read + Seek> CoffReader<W> for ObjReader<W> {
39    fn get_viewer(&mut self) -> &mut BinaryReader<W, LittleEndian> {
40        &mut self.viewer
41    }
42
43    fn add_diagnostics(&mut self, error: impl Into<GaiaError>) {
44        self.diagnostics.push(error.into());
45    }
46
47    fn get_cached_section_headers(&self) -> Option<&Vec<SectionHeader>> {
48        self.lazy_section_headers.as_ref()
49    }
50
51    fn set_cached_section_headers(&mut self, headers: Vec<SectionHeader>) {
52        self.lazy_section_headers = Some(headers);
53    }
54
55    fn read_header_once(&mut self) -> Result<&CoffHeader, GaiaError> {
56        if self.lazy_header.is_none() {
57            self.lazy_header = Some(self.read_header_force()?);
58        }
59        match self.lazy_header.as_ref() {
60            Some(s) => Ok(s),
61            None => unreachable!(),
62        }
63    }
64
65    fn read_object_once(&mut self) -> Result<&CoffObject, GaiaError> {
66        if self.lazy_object.is_none() {
67            self.lazy_object = Some(self.read_object_force()?);
68        }
69        match self.lazy_object.as_ref() {
70            Some(s) => Ok(s),
71            None => unreachable!(),
72        }
73    }
74}
75
76impl<W: Read + Seek> ObjReader<W> {
77    /// 读取完整的 COFF 对象(惰性读取,会缓存结果)
78    pub fn read_object(mut self) -> GaiaDiagnostics<CoffObject> {
79        match self.read_object_once() {
80            Ok(_) => match self.lazy_object {
81                Some(object) => GaiaDiagnostics { result: Ok(object), diagnostics: self.diagnostics },
82                None => unreachable!(),
83            },
84            Err(error) => GaiaDiagnostics { result: Err(error), diagnostics: self.diagnostics },
85        }
86    }
87
88    /// 查看 COFF 对象文件信息
89    pub fn view(&mut self) -> Result<CoffInfo, GaiaError> {
90        if let Some(ref info) = self.lazy_info {
91            return Ok(info.clone());
92        }
93
94        let info = self.create_coff_info()?;
95        self.lazy_info = Some(info.clone());
96        Ok(info)
97    }
98}
99
100impl ObjReader<File> {
101    /// 从文件创建 COFF 读取器
102    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, GaiaError> {
103        let file = File::open(path).map_err(|e| GaiaError::invalid_data(&format!("无法打开文件: {}", e)))?;
104        Ok(Self::new(file))
105    }
106}
107
108// 便利函数,保持向后兼容
109pub fn read_coff_from_file<P: AsRef<Path>>(path: P) -> Result<CoffObject, GaiaError> {
110    let reader = ObjReader::<File>::from_file(path)?;
111    let result = reader.read_object();
112    result.result
113}