pe_assembler/formats/lib/
reader.rs1use 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#[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 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 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 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 fn read_library_force(&mut self) -> Result<StaticLibrary, GaiaError> {
58 if !self.is_valid_lib()? {
60 return Err(GaiaError::invalid_data("不是有效的静态库文件"));
61 }
62
63 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 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 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 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 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 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 }
120 else {
121 println!("发现普通成员: {}", member.header.name);
122 }
124 members.push(member);
125 }
126 Err(e) => {
127 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 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 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 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 if header.size % 2 == 1 {
170 self.viewer.read_u8()?;
171 }
172
173 let coff_object = if data.len() > 20 {
175 None
179 }
180 else {
181 None
182 };
183
184 Ok(ArchiveMember { header, data, coff_object })
185 }
186
187 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 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 return Ok(symbols);
201 }
202
203 let string_table_start = 4 + symbol_count * 4;
205
206 if string_table_start >= data.len() {
207 return Ok(symbols);
208 }
209
210 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 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 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 let name_str = std::str::from_utf8(&name).map_err(|_| GaiaError::invalid_data("无效的名称字段"))?;
263 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); 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
284impl<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
295impl LibReader<File> {
297 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 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 if &magic == b"!<arch>\n" {
312 return Ok(CoffFileType::StaticLibrary);
313 }
314
315 if magic[0] == 0x4D && magic[1] == 0x5A {
317 return Ok(CoffFileType::Executable);
319 }
320
321 Ok(CoffFileType::Object)
323 }
324
325 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
340pub 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}