luadec/
ffi.rs

1use luadec_sys::{
2    DecompileResult, luadec_decompile_buffer, luadec_free_result, 
3    luadec_get_result, luadec_get_error
4};
5use std::ffi::CStr;
6use crate::error::{DecompileError, Result};
7
8/// Safe wrapper around the C decompilation function
9pub fn decompile_bytecode_raw(bytecode: &[u8]) -> Result<String> {
10    if bytecode.is_empty() {
11        return Err(DecompileError::InvalidBytecode("Empty bytecode".to_string()));
12    }
13    
14    let result_ptr = unsafe {
15        luadec_decompile_buffer(
16            bytecode.as_ptr() as *const i8,
17            bytecode.len(),
18        )
19    };
20    
21    if result_ptr.is_null() {
22        return Err(DecompileError::InternalError("Failed to get result".to_string()));
23    }
24    
25    // Ensure we always free the result, even if we return early
26    let _guard = ResultGuard(result_ptr);
27    
28    // Check for errors first
29    let error_ptr = unsafe { luadec_get_error(result_ptr) };
30    if !error_ptr.is_null() {
31        let error_cstr = unsafe { CStr::from_ptr(error_ptr) };
32        let error_msg = error_cstr.to_string_lossy().to_string();
33        return Err(DecompileError::DecompilationFailed(error_msg));
34    }
35    
36    // Get the result
37    let result_cstr_ptr = unsafe { luadec_get_result(result_ptr) };
38    if result_cstr_ptr.is_null() {
39        return Err(DecompileError::InternalError("No result returned".to_string()));
40    }
41    
42    let result_cstr = unsafe { CStr::from_ptr(result_cstr_ptr) };
43    let result_string = result_cstr.to_string_lossy().to_string();
44    
45    Ok(result_string)
46}
47
48/// RAII guard to ensure C memory is freed
49struct ResultGuard(*mut DecompileResult);
50
51impl Drop for ResultGuard {
52    fn drop(&mut self) {
53        unsafe {
54            luadec_free_result(self.0);
55        }
56    }
57}