use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;
use crate::regex::Regex;
mod time;
pub use time::Time;
#[allow(clippy::cast_precision_loss)]
mod math;
pub use math::Math;
#[cfg(feature = "hash")]
mod hash;
#[cfg(feature = "hash")]
pub use hash::Hash;
#[cfg(feature = "object")]
pub(crate) mod elf;
#[cfg(feature = "object")]
pub use elf::Elf;
#[cfg(feature = "object")]
mod macho;
#[cfg(feature = "object")]
pub use macho::MachO;
#[cfg(feature = "object")]
mod pe;
#[cfg(feature = "object")]
pub use pe::Pe;
pub trait Module: Send + Sync {
fn get_name(&self) -> &'static str;
fn get_static_values(&self) -> HashMap<&'static str, StaticValue> {
HashMap::new()
}
fn get_dynamic_types(&self) -> HashMap<&'static str, Type> {
HashMap::new()
}
fn get_dynamic_values(&self, _ctx: &mut ScanContext) -> HashMap<&'static str, Value> {
HashMap::new()
}
}
impl std::fmt::Debug for Box<dyn Module> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Module")
.field("name", &self.get_name())
.finish()
}
}
pub struct ScanContext<'a> {
pub mem: &'a [u8],
pub module_data: ModuleDataMap,
}
impl std::fmt::Debug for ScanContext<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScanContext").finish()
}
}
#[derive(Default)]
pub struct ModuleDataMap(HashMap<TypeId, Box<dyn Any + Send + Sync>>);
pub trait ModuleData: Module {
type Data: Any + Send + Sync;
}
impl ModuleDataMap {
pub fn insert<T: Module + ModuleData + 'static>(&mut self, data: T::Data) {
let _r = self.0.insert(TypeId::of::<T>(), Box::new(data));
}
#[must_use]
pub fn get<T: Module + ModuleData + 'static>(&self) -> Option<&T::Data> {
self.0
.get(&TypeId::of::<T>())
.and_then(|v| v.downcast_ref())
}
}
#[derive(Clone)]
pub enum Value {
Integer(i64),
Float(f64),
Bytes(Vec<u8>),
Regex(Regex),
Boolean(bool),
Object(HashMap<&'static str, Value>),
Array(Vec<Value>),
Dictionary(HashMap<Vec<u8>, Value>),
Function(
#[allow(clippy::type_complexity)]
Arc<Box<dyn Fn(&ScanContext, Vec<Value>) -> Option<Value> + Send + Sync>>,
),
}
impl std::fmt::Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
Self::Bytes(arg0) => {
let mut t = f.debug_tuple("Bytes");
match std::str::from_utf8(arg0) {
Ok(v) => t.field(&v).finish(),
Err(_) => t.field(arg0).finish(),
}
}
Self::Regex(arg0) => f.debug_tuple("Regex").field(arg0).finish(),
Self::Boolean(arg0) => f.debug_tuple("Boolean").field(arg0).finish(),
Self::Object(arg0) => f.debug_tuple("Object").field(arg0).finish(),
Self::Array(arg0) => f.debug_tuple("Array").field(arg0).finish(),
Self::Dictionary(arg0) => f.debug_tuple("Dictionary").field(arg0).finish(),
Self::Function(_) => f.debug_struct("Function").finish(),
}
}
}
#[derive(Clone)]
pub enum StaticValue {
Integer(i64),
Float(f64),
Bytes(Vec<u8>),
Regex(Regex),
Boolean(bool),
Object(HashMap<&'static str, StaticValue>),
Function {
fun: fn(&ScanContext, Vec<Value>) -> Option<Value>,
arguments_types: Vec<Vec<Type>>,
return_type: Type,
},
}
impl std::fmt::Debug for StaticValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
Self::Float(arg0) => f.debug_tuple("Float").field(arg0).finish(),
Self::Bytes(arg0) => f.debug_tuple("Bytes").field(arg0).finish(),
Self::Regex(arg0) => f.debug_tuple("Regex").field(arg0).finish(),
Self::Boolean(arg0) => f.debug_tuple("Boolean").field(arg0).finish(),
Self::Object(arg0) => f.debug_tuple("Object").field(arg0).finish(),
Self::Function {
fun,
arguments_types,
return_type,
} => f
.debug_struct("Function")
.field("fun", &(*fun as usize))
.field("arguments_types", arguments_types)
.field("return_type", return_type)
.finish(),
}
}
}
impl Value {
pub fn bytes<T: Into<Vec<u8>>>(v: T) -> Self {
Self::Bytes(v.into())
}
#[must_use]
pub fn object<const N: usize>(v: [(&'static str, Value); N]) -> Self {
Self::Object(v.into())
}
pub fn function<F>(f: F) -> Self
where
F: Fn(&ScanContext, Vec<Value>) -> Option<Value> + Send + Sync + 'static,
{
Self::Function(Arc::new(Box::new(f)))
}
}
impl StaticValue {
pub fn bytes<T: Into<Vec<u8>>>(v: T) -> Self {
Self::Bytes(v.into())
}
#[must_use]
pub fn object<const N: usize>(v: [(&'static str, StaticValue); N]) -> Self {
Self::Object(v.into())
}
pub fn function(
fun: fn(&ScanContext, Vec<Value>) -> Option<Value>,
arguments_types: Vec<Vec<Type>>,
return_type: Type,
) -> Self {
Self::Function {
fun,
arguments_types,
return_type,
}
}
}
#[derive(Clone, Debug)]
pub enum Type {
Integer,
Float,
Bytes,
Regex,
Boolean,
Object(HashMap<&'static str, Type>),
Array {
value_type: Box<Type>,
},
Dictionary {
value_type: Box<Type>,
},
Function {
arguments_types: Vec<Vec<Type>>,
return_type: Box<Type>,
},
}
impl Type {
#[must_use]
pub fn object<const N: usize>(v: [(&'static str, Type); N]) -> Self {
Self::Object(v.into())
}
#[must_use]
pub fn array(value_type: Type) -> Self {
Self::Array {
value_type: Box::new(value_type),
}
}
#[must_use]
pub fn dict(value_type: Type) -> Self {
Self::Dictionary {
value_type: Box::new(value_type),
}
}
#[must_use]
pub fn function(arguments_types: Vec<Vec<Type>>, return_type: Type) -> Self {
Self::Function {
arguments_types,
return_type: Box::new(return_type),
}
}
}
macro_rules! try_from_value {
($ty:ty, $name:ident) => {
impl TryFrom<Value> for $ty {
type Error = ();
fn try_from(value: Value) -> Result<$ty, ()> {
match value {
Value::$name(v) => Ok(v),
_ => Err(()),
}
}
}
};
}
try_from_value!(i64, Integer);
try_from_value!(f64, Float);
try_from_value!(Vec<u8>, Bytes);
try_from_value!(Regex, Regex);
try_from_value!(bool, Boolean);
macro_rules! from_prim {
($ty:ty, $name:ident) => {
impl From<$ty> for Value {
fn from(v: $ty) -> Value {
Value::$name(v.into())
}
}
};
}
from_prim!(i64, Integer);
from_prim!(u32, Integer);
from_prim!(i32, Integer);
from_prim!(u16, Integer);
from_prim!(i16, Integer);
from_prim!(u8, Integer);
from_prim!(i8, Integer);
from_prim!(f64, Float);
from_prim!(Vec<u8>, Bytes);
from_prim!(Regex, Regex);
from_prim!(bool, Boolean);
macro_rules! try_from_value_integer {
($ty:ty) => {
impl TryFrom<$ty> for Value {
type Error = <i64 as TryFrom<$ty>>::Error;
fn try_from(v: $ty) -> Result<Value, Self::Error> {
v.try_into().map(Value::Integer)
}
}
};
}
try_from_value_integer!(u64);
try_from_value_integer!(usize);
#[cfg(test)]
mod tests {
use super::*;
use crate::test_helpers::{test_type_traits, test_type_traits_non_clonable};
#[test]
fn test_types_traits() {
test_type_traits(Value::Integer(0));
test_type_traits(StaticValue::Integer(0));
test_type_traits(Type::Integer);
test_type_traits_non_clonable(Time);
test_type_traits_non_clonable(Math);
#[cfg(feature = "hash")]
test_type_traits_non_clonable(Hash);
#[cfg(feature = "object")]
{
test_type_traits_non_clonable(Elf);
test_type_traits_non_clonable(MachO);
test_type_traits_non_clonable(Pe);
}
assert_eq!(format!("{:?}", Value::Integer(0)), "Integer(0)");
assert_eq!(format!("{:?}", Value::Float(0.0)), "Float(0.0)");
assert_eq!(format!("{:?}", Value::Bytes(Vec::new())), "Bytes(\"\")");
assert_eq!(format!("{:?}", Value::Bytes(vec![255])), "Bytes([255])");
assert_eq!(
format!(
"{:?}",
Value::Regex(Regex::from_str("", false, false).unwrap())
),
"Regex(Regex())"
);
assert_eq!(format!("{:?}", Value::Boolean(true)), "Boolean(true)");
assert_eq!(format!("{:?}", Value::Object(HashMap::new())), "Object({})");
assert_eq!(format!("{:?}", Value::Array(Vec::new())), "Array([])");
assert_eq!(
format!("{:?}", Value::Dictionary(HashMap::new())),
"Dictionary({})"
);
assert!(format!("{:?}", Value::function(|_, _| None)).starts_with("Function"));
assert_eq!(format!("{:?}", StaticValue::Integer(0)), "Integer(0)");
assert_eq!(format!("{:?}", StaticValue::Float(0.0)), "Float(0.0)");
assert_eq!(format!("{:?}", StaticValue::Bytes(Vec::new())), "Bytes([])");
assert_eq!(format!("{:?}", StaticValue::Bytes(vec![2])), "Bytes([2])");
assert_eq!(
format!(
"{:?}",
StaticValue::Regex(Regex::from_str("", false, false).unwrap())
),
"Regex(Regex())"
);
assert_eq!(format!("{:?}", StaticValue::Boolean(true)), "Boolean(true)");
assert_eq!(
format!("{:?}", StaticValue::Object(HashMap::new())),
"Object({})"
);
assert!(format!(
"{:?}",
StaticValue::Function {
fun: |_, _| None,
arguments_types: Vec::new(),
return_type: Type::Boolean
}
)
.starts_with("Function"));
}
}