use std::ffi::{CString, c_char, c_void};
use yara_x::MetaValue;
use crate::{
_yrx_set_last_error, YRX_METADATA, YRX_METADATA_BYTES, YRX_METADATA_TYPE,
YRX_METADATA_VALUE, YRX_PATTERN, YRX_RESULT,
};
pub struct YRX_RULE<'a, 'r>(yara_x::Rule<'a, 'r>);
impl<'a, 'r> YRX_RULE<'a, 'r> {
pub fn new(rule: yara_x::Rule<'a, 'r>) -> Self {
Self(rule)
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rule_identifier(
rule: *const YRX_RULE,
ident: &mut *const u8,
len: &mut usize,
) -> YRX_RESULT {
if let Some(rule) = rule.as_ref() {
*ident = rule.0.identifier().as_ptr();
*len = rule.0.identifier().len();
_yrx_set_last_error::<String>(None);
YRX_RESULT::YRX_SUCCESS
} else {
YRX_RESULT::YRX_INVALID_ARGUMENT
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rule_namespace(
rule: *const YRX_RULE,
ns: &mut *const u8,
len: &mut usize,
) -> YRX_RESULT {
if let Some(rule) = rule.as_ref() {
*ns = rule.0.namespace().as_ptr();
*len = rule.0.namespace().len();
_yrx_set_last_error::<String>(None);
YRX_RESULT::YRX_SUCCESS
} else {
YRX_RESULT::YRX_INVALID_ARGUMENT
}
}
pub type YRX_METADATA_CALLBACK =
extern "C" fn(metadata: *const YRX_METADATA, user_data: *mut c_void) -> ();
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rule_iter_metadata(
rule: *const YRX_RULE,
callback: YRX_METADATA_CALLBACK,
user_data: *mut c_void,
) -> YRX_RESULT {
let metadata_iter = if let Some(rule) = rule.as_ref() {
rule.0.metadata()
} else {
return YRX_RESULT::YRX_INVALID_ARGUMENT;
};
for (identifier, value) in metadata_iter {
let identifier = CString::new(identifier).unwrap();
let string;
let (ty, val) = match value {
MetaValue::Integer(v) => {
(YRX_METADATA_TYPE::YRX_I64, YRX_METADATA_VALUE { r#i64: v })
}
MetaValue::Float(v) => {
(YRX_METADATA_TYPE::YRX_F64, YRX_METADATA_VALUE { r#f64: v })
}
MetaValue::Bool(v) => (
YRX_METADATA_TYPE::YRX_BOOLEAN,
YRX_METADATA_VALUE { boolean: v },
),
MetaValue::String(v) => {
string = CString::new(v).unwrap();
(
YRX_METADATA_TYPE::YRX_STRING,
YRX_METADATA_VALUE { string: string.as_ptr() },
)
}
MetaValue::Bytes(v) => (
YRX_METADATA_TYPE::YRX_BYTES,
YRX_METADATA_VALUE {
bytes: YRX_METADATA_BYTES {
length: v.len(),
data: v.as_ptr(),
},
},
),
};
callback(
&YRX_METADATA {
identifier: identifier.as_ptr(),
value_type: ty,
value: val,
},
user_data,
)
}
YRX_RESULT::YRX_SUCCESS
}
pub type YRX_PATTERN_CALLBACK =
extern "C" fn(pattern: *const YRX_PATTERN, user_data: *mut c_void) -> ();
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rule_iter_patterns(
rule: *const YRX_RULE,
callback: YRX_PATTERN_CALLBACK,
user_data: *mut c_void,
) -> YRX_RESULT {
let patterns_iter = if let Some(rule) = rule.as_ref() {
rule.0.patterns()
} else {
return YRX_RESULT::YRX_INVALID_ARGUMENT;
};
for pattern in patterns_iter {
callback(&YRX_PATTERN::new(pattern), user_data)
}
YRX_RESULT::YRX_SUCCESS
}
pub type YRX_TAG_CALLBACK =
extern "C" fn(tag: *const c_char, user_data: *mut c_void) -> ();
#[unsafe(no_mangle)]
pub unsafe extern "C" fn yrx_rule_iter_tags(
rule: *const YRX_RULE,
callback: YRX_TAG_CALLBACK,
user_data: *mut c_void,
) -> YRX_RESULT {
let tags_iter = if let Some(rule) = rule.as_ref() {
rule.0.tags()
} else {
return YRX_RESULT::YRX_INVALID_ARGUMENT;
};
for tag in tags_iter {
let tag_name = CString::new(tag.identifier()).unwrap();
callback(tag_name.as_ptr(), user_data)
}
YRX_RESULT::YRX_SUCCESS
}