Skip to main content

lua_assembler/formats/luac/reader/
mod.rs

1#![doc = include_str!("readme.md")]
2
3use crate::{
4    formats::luac::LuacReadConfig,
5    program::{LuaProgram, LuaVersion, LuacCodeObject, LuacHeader},
6};
7use byteorder::{LittleEndian, ReadBytesExt};
8use gaia_types::{BinaryReader, GaiaDiagnostics, GaiaError};
9use std::{
10    cell::RefCell,
11    io::{Read, Seek},
12    sync::OnceLock,
13};
14
15/// LuacInfo 表示 .luac 文件的基本信息视图
16#[derive(Debug, Clone, Copy)]
17pub struct LuacInfo {
18    /// .luac 文件头信息
19    pub header: LuacHeader,
20    /// Lua 版本信息
21    pub version: LuaVersion,
22}
23
24/// 现代化的惰性 .luac 文件读取器
25///
26/// 采用惰性加载模式,只在需要时才解析数据,提高性能。
27/// 使用 `OnceLock` 确保数据只被解析一次。
28#[derive(Debug)]
29pub struct LuacReader<'config, R> {
30    config: &'config LuacReadConfig,
31    reader: RefCell<BinaryReader<R, LittleEndian>>,
32    info: OnceLock<LuacInfo>,
33    program: OnceLock<LuaProgram>,
34}
35
36impl LuacReadConfig {
37    /// 创建一个新的 LuacReader 实例
38    ///
39    /// # 参数
40    ///
41    /// * `reader` - 实现了 Read + Seek 的数据源
42    ///
43    /// # 返回值
44    ///
45    /// 返回一个新的 LuacReader 实例
46    pub fn as_reader<R: Read + Seek>(&self, reader: R) -> LuacReader<'_, R> {
47        LuacReader::new(reader, self)
48    }
49}
50
51impl<'config, R> LuacReader<'config, R> {
52    /// 创建一个新的 LuacReader 实例
53    ///
54    /// # 参数
55    ///
56    /// * `reader` - 实现了 Read + Seek 的数据源
57    /// * `config` - 读取配置
58    ///
59    /// # 返回值
60    ///
61    /// 返回一个新的 LuacReader 实例
62    pub fn new(reader: R, config: &'config LuacReadConfig) -> Self {
63        Self { config, reader: RefCell::new(BinaryReader::new(reader)), info: Default::default(), program: Default::default() }
64    }
65
66    /// 完成读取并返回 LuaProgram 结果
67    ///
68    /// # 返回值
69    ///
70    /// 返回包含 LuaProgram 和诊断信息的 GaiaDiagnostics
71    pub fn finish(self) -> GaiaDiagnostics<LuaProgram>
72    where
73        R: Read + Seek,
74    {
75        match self.get_program() {
76            Ok(program) => {
77                let errors = self.reader.borrow_mut().take_errors();
78                GaiaDiagnostics { result: Ok(program.clone()), diagnostics: errors }
79            }
80            Err(e) => {
81                let errors = self.reader.borrow_mut().take_errors();
82                GaiaDiagnostics { result: Err(e), diagnostics: errors }
83            }
84        }
85    }
86}
87
88impl<'config, R: Read + Seek> LuacReader<'config, R> {
89    /// 获取解析后的 LuaProgram
90    ///
91    /// # 返回值
92    ///
93    /// 返回 LuaProgram 的引用,如果解析失败则返回错误
94    pub fn get_program(&self) -> Result<&LuaProgram, GaiaError> {
95        match self.program.get() {
96            Some(program) => Ok(program),
97            None => {
98                let program = self.read_program()?;
99                Ok(self.program.get_or_init(|| program))
100            }
101        }
102    }
103
104    /// 获取 .luac 文件的基本信息
105    ///
106    /// # 返回值
107    ///
108    /// 返回 LuacInfo 的引用,如果解析失败则返回错误
109    pub fn get_info(&self) -> Result<&LuacInfo, GaiaError> {
110        match self.info.get() {
111            Some(info) => Ok(info),
112            None => {
113                let info = self.read_info()?;
114                Ok(self.info.get_or_init(|| info))
115            }
116        }
117    }
118
119    fn read_info(&self) -> Result<LuacInfo, GaiaError> {
120        let mut reader = self.reader.borrow_mut();
121
122        // 重新定位到文件开头
123        reader.seek(std::io::SeekFrom::Start(0))?;
124
125        // 检查文件是否为空
126        let current_pos = reader.stream_position()?;
127        reader.seek(std::io::SeekFrom::End(0))?;
128        let file_size = reader.stream_position()?;
129        reader.seek(std::io::SeekFrom::Start(current_pos))?;
130
131        if file_size == 0 {
132            return Err(GaiaError::custom_error("File is empty".to_string()));
133        }
134
135        // 读取 .luac 文件头
136        let header = self.read_header(&mut reader)?;
137
138        // 从配置或头部确定版本
139        let version = if self.config.version != LuaVersion::Unknown {
140            self.config.version
141        }
142        else {
143            LuaVersion::from_byte(header.version.to_byte())
144        };
145
146        Ok(LuacInfo { header, version })
147    }
148
149    fn read_program(&self) -> Result<LuaProgram, GaiaError> {
150        let mut reader = self.reader.borrow_mut();
151
152        // 重新定位到文件开头
153        reader.seek(std::io::SeekFrom::Start(0))?;
154
155        // 读取头部信息
156        let header = self.read_header(&mut reader)?;
157
158        // 确定 Lua 版本
159        let version = if self.config.version != LuaVersion::Unknown {
160            self.config.version
161        }
162        else {
163            LuaVersion::from_byte(header.version.to_byte())
164        };
165
166        // 读取代码对象
167        let code_object = self.read_code_object(&mut reader)?;
168
169        // 构建 LuaProgram
170        let program = LuaProgram { header, code_object };
171
172        Ok(program)
173    }
174
175    fn read_header(&self, reader: &mut BinaryReader<R, LittleEndian>) -> Result<LuacHeader, GaiaError> {
176        // 读取 Lua 字节码魔数 "\x1bLua"
177        let mut magic = [0u8; 4];
178        reader.read_exact(&mut magic).map_err(|e| GaiaError::custom_error(format!("Failed to read magic bytes: {}", e)))?;
179
180        // 验证魔数(如果配置要求检查)
181        if self.config.check_magic_head {
182            let expected_magic = [0x1b, b'L', b'u', b'a'];
183            if magic != expected_magic {
184                return Err(GaiaError::custom_error(format!(
185                    "Invalid Lua bytecode magic: expected {:?}, got {:?}",
186                    expected_magic, magic
187                )));
188            }
189        }
190
191        // 读取版本信息
192        let version_byte =
193            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read version byte: {}", e)))?;
194        let version = LuaVersion::from_byte(version_byte);
195
196        // 读取格式版本
197        let format_version =
198            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read format version: {}", e)))?;
199
200        // 读取字节序标识
201        let endianness = reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read endianness: {}", e)))?;
202
203        // 读取各种大小信息
204        let int_size = reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read int_size: {}", e)))?;
205        let size_t_size =
206            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read size_t_size: {}", e)))?;
207        let instruction_size =
208            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read instruction_size: {}", e)))?;
209        let lua_number_size =
210            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read lua_number_size: {}", e)))?;
211        let integral_flag =
212            reader.read_u8().map_err(|e| GaiaError::custom_error(format!("Failed to read integral_flag: {}", e)))?;
213
214        Ok(LuacHeader {
215            magic,
216            version,
217            format_version,
218            endianness,
219            int_size,
220            size_t_size,
221            instruction_size,
222            lua_number_size,
223            integral_flag,
224            flags: 0,
225            timestamp: None,
226            size: None,
227            hash: None,
228        })
229    }
230
231    fn read_code_object(&self, _reader: &mut BinaryReader<R, LittleEndian>) -> Result<LuacCodeObject, GaiaError> {
232        // 暂时返回默认的代码对象
233        // 完整的实现需要解析 Lua 字节码的复杂结构
234        Ok(LuacCodeObject {
235            source_name: String::new(),
236            first_line: 0,
237            last_line: 0,
238            num_params: 0,
239            is_vararg: 0,
240            max_stack_size: 0,
241            nested_functions: Vec::new(),
242            upvalues: Vec::new(),
243            local_vars: Vec::new(),
244            line_info: Vec::new(),
245            co_argcount: 0,
246            co_nlocal: 0,
247            co_stacks: 0,
248            num_upval: 0,
249            co_code: Vec::new(),
250            co_consts: Vec::new(),
251            upvalue_n: 0,
252        })
253    }
254}
255
256impl Default for LuaProgram {
257    fn default() -> Self {
258        Self { header: LuacHeader::default(), code_object: LuacCodeObject::default() }
259    }
260}
261
262impl Default for LuacHeader {
263    fn default() -> Self {
264        Self {
265            magic: [0x1b, b'L', b'u', b'a'],
266            version: LuaVersion::Unknown,
267            format_version: 0,
268            endianness: 1, // 小端序
269            int_size: 4,
270            size_t_size: 8,
271            instruction_size: 4,
272            lua_number_size: 8,
273            integral_flag: 0,
274            flags: 0,
275            timestamp: None,
276            size: None,
277            hash: None,
278        }
279    }
280}
281
282impl Default for LuacCodeObject {
283    fn default() -> Self {
284        Self {
285            source_name: String::new(),
286            first_line: 0,
287            last_line: 0,
288            num_params: 0,
289            is_vararg: 0,
290            max_stack_size: 0,
291            nested_functions: Vec::new(),
292            upvalues: Vec::new(),
293            local_vars: Vec::new(),
294            line_info: Vec::new(),
295            co_argcount: 0,
296            co_nlocal: 0,
297            co_stacks: 0,
298            num_upval: 0,
299            co_code: Vec::new(),
300            co_consts: Vec::new(),
301            upvalue_n: 0,
302        }
303    }
304}