diff --git a/Cargo.toml b/Cargo.toml index 84ba3ad..2069da8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ rust-version = "1.70.0" [lib] name = "tf_demo_parser" path = "src/lib.rs" +crate-type = ["lib", "cdylib"] [[bin]] name = "parse_demo" diff --git a/src/lib.rs b/src/lib.rs index 1f399d0..642c7d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,10 @@ #![cfg_attr(not(test), deny(clippy::indexing_slicing))] #![cfg_attr(not(test), deny(clippy::panic))] +use std::ffi::{c_char, CStr, CString}; +use std::fs; pub use bitbuffer::Result as ReadResult; +use serde::{Deserialize, Serialize}; pub use crate::demo::{ message::MessageType, @@ -13,6 +16,7 @@ pub use crate::demo::{ }, Demo, Stream, }; +use crate::demo::header::Header; #[cfg(feature = "codegen")] pub mod codegen; @@ -85,3 +89,56 @@ fn test_roundtrip_encode< read.pos() ); } + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct JsonDemo { + header: Header, + #[serde(flatten)] + state: MatchState, +} + +#[no_mangle] +pub extern "C" fn analyze_demo(path: *const c_char) -> *mut c_char { + let c_str = unsafe { CStr::from_ptr(path) }; + let str_slice = match c_str.to_str() { + Ok(s) => s, + Err(_) => return std::ptr::null_mut(), + }; + + let file = match fs::read(str_slice) { + Ok(f) => f, + Err(_) => return std::ptr::null_mut(), + }; + + let demo = Demo::new(&file); + let parser = DemoParser::new(demo.get_stream()); + let (header, state) = match parser.parse() { + Ok(results) => results, + Err(_) => return std::ptr::null_mut(), + }; + + let demo_json = JsonDemo { header, state }; + let result = match serde_json::to_string(&demo_json) { + Ok(json) => json, + Err(_) => return std::ptr::null_mut(), + }; + + // Convert the Rust string to a C string to return + let c_string = match CString::new(result) { + Ok(c_str) => c_str, + Err(_) => return std::ptr::null_mut(), + }; + + c_string.into_raw() +} + +#[no_mangle] +pub extern "C" fn free_string(s: *mut c_char) { + unsafe { + // Reclaim the CString to properly deallocate memory + if !s.is_null() { + let _ = CString::from_raw(s); + } + } +}