use std::ffi::{CString, c_char, c_int, c_void};
use std::mem::ManuallyDrop;
use std::slice;
use yara_x::errors::SerializationError;
use crate::{_yrx_set_last_error, YRX_BUFFER, YRX_RESULT, YRX_RULE};
pub struct YRX_RULES(yara_x::Rules);
impl YRX_RULES {
pub fn boxed(rules: yara_x::Rules) -> Box<Self> {
Box::new(Self(rules))
}
#[inline]
pub fn inner(&self) -> &yara_x::Rules {
&self.0
}
}
pub type YRX_RULE_CALLBACK =
extern "C" fn(rule: *const YRX_RULE, user_data: *mut c_void) -> ();
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_iter(
rules: *const YRX_RULES,
callback: YRX_RULE_CALLBACK,
user_data: *mut c_void,
) -> YRX_RESULT {
if let Some(rules) = rules.as_ref() {
for r in rules.inner().iter() {
let rule = YRX_RULE::new(r);
callback(&rule as *const YRX_RULE, user_data);
}
YRX_RESULT::YRX_SUCCESS
} else {
YRX_RESULT::YRX_INVALID_ARGUMENT
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_count(rules: *mut YRX_RULES) -> c_int {
if let Some(rules) = rules.as_ref() {
rules.inner().iter().len() as c_int
} else {
-1
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_serialize(
rules: *const YRX_RULES,
buf: &mut *mut YRX_BUFFER,
) -> YRX_RESULT {
if let Some(rules) = rules.as_ref() {
match rules.inner().serialize() {
Ok(serialized) => {
let serialized = serialized.into_boxed_slice();
let mut serialized = ManuallyDrop::new(serialized);
*buf = Box::into_raw(Box::new(YRX_BUFFER {
data: serialized.as_mut_ptr(),
length: serialized.len(),
}));
_yrx_set_last_error::<SerializationError>(None);
YRX_RESULT::YRX_SUCCESS
}
Err(err) => {
_yrx_set_last_error(Some(err));
YRX_RESULT::YRX_SERIALIZATION_ERROR
}
}
} else {
YRX_RESULT::YRX_INVALID_ARGUMENT
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_deserialize(
data: *const u8,
len: usize,
rules: &mut *mut YRX_RULES,
) -> YRX_RESULT {
match yara_x::Rules::deserialize(slice::from_raw_parts(data, len)) {
Ok(r) => {
*rules = Box::into_raw(YRX_RULES::boxed(r));
_yrx_set_last_error::<SerializationError>(None);
YRX_RESULT::YRX_SUCCESS
}
Err(err) => {
_yrx_set_last_error(Some(err));
YRX_RESULT::YRX_SERIALIZATION_ERROR
}
}
}
pub type YRX_IMPORT_CALLBACK =
extern "C" fn(module_name: *const c_char, user_data: *mut c_void) -> ();
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_iter_imports(
rules: *const YRX_RULES,
callback: YRX_IMPORT_CALLBACK,
user_data: *mut c_void,
) -> YRX_RESULT {
if let Some(rules) = rules.as_ref() {
for import in rules.inner().imports() {
let import = CString::new(import).unwrap();
callback(import.as_ptr(), user_data);
}
YRX_RESULT::YRX_SUCCESS
} else {
YRX_RESULT::YRX_INVALID_ARGUMENT
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rules_destroy(rules: *mut YRX_RULES) {
drop(Box::from_raw(rules))
}