pe_assembler/formats/lib/
reader.rs

1use crate::types::coff::{ArchiveMember, ArchiveMemberHeader, CoffFileType, CoffInfo, StaticLibrary};
2use byteorder::{LittleEndian, ReadBytesExt};
3use gaia_types::{helpers::Architecture, reader::BinaryReader, GaiaError};
4use std::{
5    fs::File,
6    io::{Cursor, Read, Seek},
7    path::Path,
8};
9
10/// LIB 结构,惰性读取器
11#[derive(Debug)]
12pub struct LibReader<R> {
13    viewer: BinaryReader<R, LittleEndian>,
14    lazy_library: Option<StaticLibrary>,
15    lazy_info: Option<CoffInfo>,
16    diagnostics: Vec<GaiaError>,
17}
18
19impl<R> LibReader<R> {
20    pub fn new(reader: R) -> Self {
21        Self { viewer: BinaryReader::new(reader), lazy_library: None, lazy_info: None, diagnostics: vec![] }
22    }
23}
24
25impl<R: Read + Seek> LibReader<R> {
26    /// 检测是否为有效的静态库文件
27    pub fn is_valid_lib(&mut self) -> Result<bool, GaiaError> {
28        let mut magic = [0u8; 8];
29        self.viewer.read_exact(&mut magic)?;
30        self.viewer.seek(std::io::SeekFrom::Start(0))?;
31        Ok(&magic == b"!<arch>\n")
32    }
33
34    /// 查看静态库文件信息
35    pub fn view(&mut self) -> Result<CoffInfo, GaiaError> {
36        if let Some(ref info) = self.lazy_info {
37            return Ok(info.clone());
38        }
39
40        let info = self.create_lib_info()?;
41        self.lazy_info = Some(info.clone());
42        Ok(info)
43    }
44
45    /// 读取静态库
46    pub fn read_library(&mut self) -> Result<&StaticLibrary, GaiaError> {
47        if self.lazy_library.is_none() {
48            self.lazy_library = Some(self.read_library_force()?);
49        }
50        match self.lazy_library.as_ref() {
51            Some(s) => Ok(s),
52            None => unreachable!(),
53        }
54    }
55
56    /// 强制读取静态库(不使用缓存)
57    fn read_library_force(&mut self) -> Result<StaticLibrary, GaiaError> {
58        // 验证文件头
59        if !self.is_valid_lib()? {
60            return Err(GaiaError::invalid_data("不是有效的静态库文件"));
61        }
62
63        // 跳过文件头 "!<arch>\n" (8字节)
64        self.viewer.seek(std::io::SeekFrom::Start(8))?;
65
66        let mut members = Vec::new();
67        let mut symbol_index = Vec::new();
68        let file_size = self.get_file_size()?;
69
70        println!("开始解析库文件,文件大小: {} bytes", file_size);
71        println!("跳过文件头后,从位置8开始读取成员");
72
73        // 读取所有成员
74        while self.viewer.get_position() < file_size {
75            let current_pos = self.viewer.get_position();
76            println!("当前位置: {}, 剩余: {} bytes", current_pos, file_size - current_pos);
77
78            // 检查是否还有足够的数据读取成员头(60字节)
79            if current_pos + 60 > file_size {
80                println!("剩余数据不足60字节,停止解析");
81                break;
82            }
83
84            match self.read_member() {
85                Ok(member) => {
86                    println!("读取到成员: '{}', 大小: {} bytes", member.header.name, member.header.size);
87
88                    // 检查是否是符号表(支持传统格式"/"和现代格式"/<ECSYMBOLS>")
89                    if member.header.name == "/" || member.header.name.starts_with("/<ECSYMBOLS>") {
90                        println!("发现符号表: '{}', 开始解析符号", member.header.name);
91                        println!("符号表数据大小: {} bytes", member.data.len());
92                        if member.data.len() >= 4 {
93                            let symbol_count_be =
94                                u32::from_be_bytes([member.data[0], member.data[1], member.data[2], member.data[3]]);
95                            println!("符号表头部显示符号数量: {}", symbol_count_be);
96                            // 打印前16个字节的十六进制内容
97                            let preview_len = std::cmp::min(16, member.data.len());
98                            let hex_preview: String =
99                                member.data[..preview_len].iter().map(|b| format!("{:02X}", b)).collect::<Vec<_>>().join(" ");
100                            println!("符号表前{}字节内容: {}", preview_len, hex_preview);
101                        }
102                        // 这是符号表,解析符号
103                        match self.parse_symbol_table(&member.data, members.len()) {
104                            Ok(symbols) => {
105                                println!("成功解析 {} 个符号", symbols.len());
106                                if !symbols.is_empty() {
107                                    println!("前5个符号: {:?}", &symbols[..std::cmp::min(5, symbols.len())]);
108                                }
109                                symbol_index.extend(symbols);
110                            }
111                            Err(e) => {
112                                println!("符号表解析失败: {:?}", e);
113                            }
114                        }
115                    }
116                    else if member.header.name == "//" {
117                        println!("发现扩展名称表,跳过");
118                        // 这是扩展名称表,跳过
119                    }
120                    else {
121                        println!("发现普通成员: {}", member.header.name);
122                        // 这是普通成员
123                    }
124                    members.push(member);
125                }
126                Err(e) => {
127                    // 如果读取失败,记录错误但继续
128                    println!("读取成员失败: {:?}", e);
129                    self.add_diagnostic(e);
130                    break;
131                }
132            }
133        }
134
135        println!("解析完成,总成员数: {}, 总符号数: {}", members.len(), symbol_index.len());
136        Ok(StaticLibrary { signature: "!<arch>\n".to_string(), members, symbol_index })
137    }
138
139    /// 创建库信息
140    fn create_lib_info(&mut self) -> Result<CoffInfo, GaiaError> {
141        let file_size = self.get_file_size()?;
142        let library = self.read_library()?;
143
144        Ok(CoffInfo {
145            file_type: CoffFileType::StaticLibrary,
146            target_arch: Architecture::Unknown,
147            section_count: 0,
148            symbol_count: library.symbol_index.len() as u32,
149            file_size,
150            timestamp: 0,
151        })
152    }
153
154    /// 获取文件大小
155    pub fn get_file_size(&mut self) -> Result<u64, GaiaError> {
156        let current_pos = self.viewer.get_position();
157        let size = self.viewer.seek(std::io::SeekFrom::End(0))?;
158        self.viewer.set_position(current_pos)?;
159        Ok(size)
160    }
161
162    /// 读取成员
163    fn read_member(&mut self) -> Result<ArchiveMember, GaiaError> {
164        let header = self.read_member_header()?;
165        let mut data = vec![0u8; header.size as usize];
166        self.viewer.read_exact(&mut data)?;
167
168        // 对齐到偶数边界
169        if header.size % 2 == 1 {
170            self.viewer.read_u8()?;
171        }
172
173        // 尝试解析 COFF 对象(如果数据是有效的 COFF 格式)
174        let coff_object = if data.len() > 20 {
175            // 尝试从数据中读取 COFF 对象
176            // 这里暂时返回 None,因为需要一个具体的 CoffReader 实现
177            // TODO: 实现一个简单的 COFF 对象解析器
178            None
179        }
180        else {
181            None
182        };
183
184        Ok(ArchiveMember { header, data, coff_object })
185    }
186
187    /// 解析符号表
188    fn parse_symbol_table(&self, data: &[u8], member_index: usize) -> Result<Vec<(String, usize)>, GaiaError> {
189        let mut symbols = Vec::new();
190
191        if data.len() < 4 {
192            return Ok(symbols);
193        }
194
195        // 读取符号数量(前4个字节,大端序)
196        let symbol_count = u32::from_be_bytes([data[0], data[1], data[2], data[3]]) as usize;
197
198        if symbol_count == 0 || symbol_count > 100000 {
199            // 符号数量不合理,可能不是标准的符号表格式
200            return Ok(symbols);
201        }
202
203        // 跳过符号偏移表(每个符号4字节偏移)
204        let string_table_start = 4 + symbol_count * 4;
205
206        if string_table_start >= data.len() {
207            return Ok(symbols);
208        }
209
210        // 解析字符串表
211        let string_data = &data[string_table_start..];
212        let mut current_pos = 0;
213
214        while current_pos < string_data.len() && symbols.len() < symbol_count {
215            // 查找下一个null终止符
216            if let Some(null_pos) = string_data[current_pos..].iter().position(|&b| b == 0) {
217                if null_pos > 0 {
218                    if let Ok(symbol_name) = std::str::from_utf8(&string_data[current_pos..current_pos + null_pos]) {
219                        symbols.push((symbol_name.to_string(), member_index));
220                    }
221                }
222                current_pos += null_pos + 1;
223            }
224            else {
225                break;
226            }
227        }
228
229        Ok(symbols)
230    }
231
232    /// 读取成员头
233    fn read_member_header(&mut self) -> Result<ArchiveMemberHeader, GaiaError> {
234        let mut name = [0u8; 16];
235        self.viewer.read_exact(&mut name)?;
236
237        let mut date = [0u8; 12];
238        self.viewer.read_exact(&mut date)?;
239
240        let mut uid = [0u8; 6];
241        self.viewer.read_exact(&mut uid)?;
242
243        let mut gid = [0u8; 6];
244        self.viewer.read_exact(&mut gid)?;
245
246        let mut mode = [0u8; 8];
247        self.viewer.read_exact(&mut mode)?;
248
249        let mut size = [0u8; 10];
250        self.viewer.read_exact(&mut size)?;
251
252        let mut end_chars = [0u8; 2];
253        self.viewer.read_exact(&mut end_chars)?;
254
255        println!("成员头结束符: {:02X} {:02X} (期望: 60 0A)", end_chars[0], end_chars[1]);
256
257        if &end_chars != b"`\n" {
258            return Err(GaiaError::invalid_data("无效的成员头结束符"));
259        }
260
261        // 解析字段 - ar格式的字段都是ASCII字符串,右填充空格
262        let name_str = std::str::from_utf8(&name).map_err(|_| GaiaError::invalid_data("无效的名称字段"))?;
263        // ar格式中名称以斜杠结尾,然后用空格填充
264        let name = name_str.trim_end_matches(' ').trim_end_matches('/').to_string();
265
266        let date_str = std::str::from_utf8(&date).map_err(|_| GaiaError::invalid_data("无效的日期字段"))?;
267        let timestamp = date_str.trim_end_matches(' ').parse::<u32>().unwrap_or(0);
268
269        let uid_str = std::str::from_utf8(&uid).map_err(|_| GaiaError::invalid_data("无效的用户ID字段"))?;
270        let user_id = uid_str.trim_end_matches(' ').parse::<u16>().unwrap_or(0);
271
272        let gid_str = std::str::from_utf8(&gid).map_err(|_| GaiaError::invalid_data("无效的组ID字段"))?;
273        let group_id = gid_str.trim_end_matches(' ').parse::<u16>().unwrap_or(0);
274
275        let mode_str = std::str::from_utf8(&mode).map_err(|_| GaiaError::invalid_data("无效的模式字段"))?;
276        let mode = u32::from_str_radix(mode_str.trim_end_matches(' '), 8).unwrap_or(0); // 模式字段是八进制
277
278        let size_str = std::str::from_utf8(&size).map_err(|_| GaiaError::invalid_data("无效的大小字段"))?;
279        let size = size_str.trim_end_matches(' ').parse::<u32>().unwrap_or(0);
280        Ok(ArchiveMemberHeader { name, timestamp, user_id, group_id, mode, size })
281    }
282}
283
284// 诊断信息相关的实现
285impl<R: ReadBytesExt> LibReader<R> {
286    pub fn get_diagnostics(&self) -> &[GaiaError] {
287        &self.diagnostics
288    }
289
290    pub fn add_diagnostic(&mut self, diagnostic: GaiaError) {
291        self.diagnostics.push(diagnostic);
292    }
293}
294
295// 静态方法和便利函数
296impl LibReader<File> {
297    /// 从文件创建 LibReader
298    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, GaiaError> {
299        let file = File::open(path.as_ref()).map_err(|e| GaiaError::invalid_data(&format!("无法打开文件: {}", e)))?;
300        Ok(Self::new(file))
301    }
302
303    /// 检测文件类型
304    pub fn detect_file_type<P: AsRef<Path>>(path: P) -> Result<CoffFileType, GaiaError> {
305        let mut file = File::open(path.as_ref()).map_err(|e| GaiaError::invalid_data(&format!("无法打开文件: {}", e)))?;
306
307        let mut magic = [0u8; 8];
308        file.read_exact(&mut magic).map_err(|e| GaiaError::invalid_data(&format!("读取文件头失败: {}", e)))?;
309
310        // 检查是否为静态库文件
311        if &magic == b"!<arch>\n" {
312            return Ok(CoffFileType::StaticLibrary);
313        }
314
315        // 检查是否为 PE 文件
316        if magic[0] == 0x4D && magic[1] == 0x5A {
317            // DOS 头签名 "MZ"
318            return Ok(CoffFileType::Executable);
319        }
320
321        // 默认为对象文件
322        Ok(CoffFileType::Object)
323    }
324
325    /// 获取文件信息
326    pub fn get_file_info<P: AsRef<Path>>(path: P) -> Result<CoffInfo, GaiaError> {
327        let file_type = Self::detect_file_type(&path)?;
328        let _metadata = std::fs::metadata(&path).map_err(|e| GaiaError::invalid_data(&format!("获取文件元数据失败: {}", e)))?;
329
330        match file_type {
331            CoffFileType::StaticLibrary => {
332                let mut reader = Self::from_file(&path)?;
333                reader.view()
334            }
335            _ => Err(GaiaError::invalid_data("不支持的文件类型")),
336        }
337    }
338}
339
340// 便利函数,保持向后兼容
341pub fn read_lib_from_bytes(data: &[u8]) -> Result<StaticLibrary, GaiaError> {
342    let mut reader = LibReader::new(Cursor::new(data));
343    reader.read_library().map(|lib| lib.clone())
344}
345
346pub fn read_lib_from_file<P: AsRef<Path>>(path: P) -> Result<StaticLibrary, GaiaError> {
347    let mut reader = LibReader::from_file(path)?;
348    reader.read_library().map(|lib| lib.clone())
349}