use num_traits::FromPrimitive;
use windows::Win32::System::Diagnostics::Etw;
#[derive(Debug, Clone)]
pub enum PropertyError {
UnimplementedType(&'static str),
}
impl std::fmt::Display for PropertyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnimplementedType(s) => write!(f, "unimplemented type: {}", s),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PropertyCount {
Count(u16),
Index(u16),
}
impl Default for PropertyCount {
fn default() -> Self {
PropertyCount::Count(0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PropertyLength {
Length(u16),
Index(u16),
}
impl Default for PropertyLength {
fn default() -> Self {
PropertyLength::Length(0)
}
}
#[derive(Debug, Clone)]
pub enum PropertyInfo {
Value {
in_type: TdhInType,
out_type: TdhOutType,
length: PropertyLength,
},
Array {
in_type: TdhInType,
out_type: TdhOutType,
length: PropertyLength,
count: PropertyCount,
},
}
impl Default for PropertyInfo {
fn default() -> Self {
PropertyInfo::Value {
in_type: Default::default(),
out_type: Default::default(),
length: Default::default(),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Property {
pub name: String,
pub flags: PropertyFlags,
pub info: PropertyInfo,
}
#[doc(hidden)]
impl Property {
pub fn new(name: String, property: &Etw::EVENT_PROPERTY_INFO) -> Result<Self, PropertyError> {
let flags = PropertyFlags::from(property.Flags);
if flags.contains(PropertyFlags::PROPERTY_STRUCT) {
Err(PropertyError::UnimplementedType("structure"))
} else if flags.contains(PropertyFlags::PROPERTY_HAS_CUSTOM_SCHEMA) {
Err(PropertyError::UnimplementedType("has custom schema"))
} else {
let ot = unsafe { property.Anonymous1.nonStructType.OutType };
let it = unsafe { property.Anonymous1.nonStructType.InType };
let length = if flags.contains(PropertyFlags::PROPERTY_PARAM_LENGTH) {
PropertyLength::Index(unsafe { property.Anonymous3.lengthPropertyIndex })
} else {
PropertyLength::Length(unsafe { property.Anonymous3.length })
};
let count = if flags.contains(PropertyFlags::PROPERTY_PARAM_COUNT) {
unsafe {
if property.Anonymous2.countPropertyIndex > 1 {
Some(PropertyCount::Index(property.Anonymous2.countPropertyIndex))
} else {
None
}
}
} else {
unsafe {
if property.Anonymous2.count > 1 {
Some(PropertyCount::Count(property.Anonymous2.count))
} else {
None
}
}
};
let out_type = FromPrimitive::from_u16(ot).unwrap_or(TdhOutType::OutTypeNull);
let in_type = FromPrimitive::from_u16(it).unwrap_or(TdhInType::InTypeNull);
match count {
Some(c) => Ok(Property {
name,
flags,
info: PropertyInfo::Array {
in_type,
out_type,
length,
count: c,
},
}),
None => Ok(Property {
name,
flags,
info: PropertyInfo::Value {
in_type,
out_type,
length,
},
}),
}
}
}
}
#[repr(u16)]
#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq, Eq, Default)]
pub enum TdhInType {
#[default]
InTypeNull,
InTypeUnicodeString,
InTypeAnsiString,
InTypeInt8, InTypeUInt8, InTypeInt16, InTypeUInt16, InTypeInt32, InTypeUInt32, InTypeInt64, InTypeUInt64, InTypeFloat, InTypeDouble, InTypeBoolean, InTypeBinary, InTypeGuid,
InTypePointer,
InTypeFileTime, InTypeSystemTime, InTypeSid, InTypeHexInt32,
InTypeHexInt64,
InTypeCountedString = 300,
}
#[repr(u16)]
#[derive(Debug, Clone, Copy, FromPrimitive, ToPrimitive, PartialEq, Eq, Default)]
pub enum TdhOutType {
#[default]
OutTypeNull,
OutTypeString,
OutTypeDateTime,
OutTypeInt8, OutTypeUInt8, OutTypeInt16, OutTypeUInt16, OutTypeInt32, OutTypeUInt32, OutTypeInt64, OutTypeUInt64, OutTypeFloat, OutTypeDouble, OutTypeBoolean, OutTypeGuid,
OutTypeHexBinary,
OutTypeHexInt8,
OutTypeHexInt16,
OutTypeHexInt32,
OutTypeHexInt64,
OutTypePid,
OutTypeTid,
OutTypePort,
OutTypeIpv4,
OutTypeIpv6,
OutTypeWin32Error = 30,
OutTypeNtStatus = 31,
OutTypeHResult = 32,
OutTypeJson = 34,
OutTypeUtf8 = 35,
OutTypePkcs7 = 36,
OutTypeCodePointer = 37,
OutTypeDatetimeUtc = 38,
}
bitflags! {
#[derive(Default)]
pub struct PropertyFlags: u32 {
const PROPERTY_STRUCT = 0x1;
const PROPERTY_PARAM_LENGTH = 0x2;
const PROPERTY_PARAM_COUNT = 0x4;
const PROPERTY_WBEMXML_FRAGMENT = 0x8;
const PROPERTY_PARAM_FIXED_LENGTH = 0x10;
const PROPERTY_PARAM_FIXED_COUNT = 0x20;
const PROPERTY_HAS_TAGS = 0x40;
const PROPERTY_HAS_CUSTOM_SCHEMA = 0x80;
}
}
impl From<Etw::PROPERTY_FLAGS> for PropertyFlags {
fn from(val: Etw::PROPERTY_FLAGS) -> Self {
let flags: i32 = val.0;
PropertyFlags::from_bits_truncate(flags as u32)
}
}