#![allow(clippy::missing_safety_doc)]
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use crate::aaml::AAML;
pub struct AamlHandle {
inner: AAML,
last_error: Option<CString>,
}
impl AamlHandle {
fn set_error(&mut self, err: impl ToString) {
let msg = err.to_string().replace('\0', "<NUL>");
self.last_error = CString::new(msg).ok();
}
fn clear_error(&mut self) {
self.last_error = None;
}
}
#[unsafe(no_mangle)]
pub extern "C" fn aam_new() -> *mut AamlHandle {
Box::into_raw(Box::new(AamlHandle {
inner: AAML::new(),
last_error: None,
}))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_free(handle: *mut AamlHandle) {
if !handle.is_null() {
unsafe { drop(Box::from_raw(handle)) };
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_parse(handle: *mut AamlHandle, content: *const c_char) -> i32 {
if handle.is_null() || content.is_null() {
return -1;
}
let handle = unsafe { &mut *handle };
let content = match unsafe { CStr::from_ptr(content) }.to_str() {
Ok(s) => s,
Err(e) => {
handle.set_error(e);
return -1;
}
};
match AAML::parse(content) {
Ok(aaml) => {
handle.inner = aaml;
handle.clear_error();
0
}
Err(e) => {
handle.set_error(e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_load(handle: *mut AamlHandle, path: *const c_char) -> i32 {
if handle.is_null() || path.is_null() {
return -1;
}
let handle = unsafe { &mut *handle };
let path = match unsafe { CStr::from_ptr(path) }.to_str() {
Ok(s) => s,
Err(e) => {
handle.set_error(e);
return -1;
}
};
match AAML::load(path) {
Ok(aaml) => {
handle.inner = aaml;
handle.clear_error();
0
}
Err(e) => {
handle.set_error(e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_merge(handle: *mut AamlHandle, content: *const c_char) -> i32 {
if handle.is_null() || content.is_null() {
return -1;
}
let handle = unsafe { &mut *handle };
let content = match unsafe { CStr::from_ptr(content) }.to_str() {
Ok(s) => s,
Err(e) => {
handle.set_error(e);
return -1;
}
};
match handle.inner.merge_content(content) {
Ok(()) => {
handle.clear_error();
0
}
Err(e) => {
handle.set_error(e);
-1
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_find_obj(
handle: *const AamlHandle,
key: *const c_char,
) -> *mut c_char {
if handle.is_null() || key.is_null() {
return std::ptr::null_mut();
}
let handle = unsafe { &*handle };
let key = match unsafe { CStr::from_ptr(key) }.to_str() {
Ok(s) => s,
Err(_) => return std::ptr::null_mut(),
};
match handle.inner.find_obj(key) {
Some(v) => to_c_string(v.as_str()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_find_key(
handle: *const AamlHandle,
value: *const c_char,
) -> *mut c_char {
if handle.is_null() || value.is_null() {
return std::ptr::null_mut();
}
let handle = unsafe { &*handle };
let value = match unsafe { CStr::from_ptr(value) }.to_str() {
Ok(s) => s,
Err(_) => return std::ptr::null_mut(),
};
match handle.inner.find_key(value) {
Some(v) => to_c_string(v.as_str()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_find_deep(
handle: *const AamlHandle,
key: *const c_char,
) -> *mut c_char {
if handle.is_null() || key.is_null() {
return std::ptr::null_mut();
}
let handle = unsafe { &*handle };
let key = match unsafe { CStr::from_ptr(key) }.to_str() {
Ok(s) => s,
Err(_) => return std::ptr::null_mut(),
};
match handle.inner.find_deep(key) {
Some(v) => to_c_string(v.as_str()),
None => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_string_free(s: *mut c_char) {
if !s.is_null() {
unsafe { drop(CString::from_raw(s)) };
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aam_last_error(handle: *const AamlHandle) -> *const c_char {
if handle.is_null() {
return std::ptr::null();
}
let handle = unsafe { &*handle };
match &handle.last_error {
Some(cs) => cs.as_ptr(),
None => std::ptr::null(),
}
}
fn to_c_string(s: &str) -> *mut c_char {
let safe = s.replace('\0', "<NUL>");
CString::new(safe).unwrap().into_raw()
}