dfirtk_eventdata/
event_id.rs1use std::{
2 convert::{TryFrom, TryInto},
3 fmt::Display,
4};
5
6use anyhow::bail;
7use darling::FromMeta;
8use evtx::SerializedEvtxRecord;
9use quote::quote;
10use serde::Serialize;
11use serde_json::Value;
12
13use super::EvtxFieldView;
14
15#[derive(PartialEq, Eq, Clone, Debug, Serialize)]
16pub struct EventId(pub u16);
17
18impl TryFrom<&SerializedEvtxRecord<Value>> for EventId {
19 type Error = anyhow::Error;
20
21 fn try_from(record: &SerializedEvtxRecord<Value>) -> Result<Self, Self::Error> {
22 let event_id = &record.data["Event"]["System"]["EventID"];
23
24 let event_id = match event_id.get("#text") {
25 Some(eid) => eid,
26 None => event_id,
27 };
28
29 if let Some(event_id) = event_id.as_u64() {
30 let id: u16 = event_id.try_into()?;
31 Ok(Self(id))
32 } else {
33 bail!("event id cannot be converted to u16: {event_id}")
34 }
35 }
36}
37
38impl EventId {
39 pub fn value(&self) -> u16 {
40 self.0
41 }
42}
43
44const EVENT_ID_MAX_LENGTH: usize = 5;
45impl EvtxFieldView for EventId {
46 fn maximum_display_length(&self) -> usize {
47 EVENT_ID_MAX_LENGTH
48 }
49
50 fn value_with_padding(&self) -> String {
51 format!("{:5}", self.0)
52 }
53}
54
55impl From<EventId> for u16 {
56 fn from(me: EventId) -> Self {
57 me.0
58 }
59}
60
61impl From<u16> for EventId {
62 fn from(id: u16) -> Self {
63 Self(id)
64 }
65}
66
67impl Display for EventId {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 self.0.fmt(f)
70 }
71}
72
73impl FromMeta for EventId {
74 fn from_value(value: &darling::export::syn::Lit) -> darling::Result<Self> {
75 match value {
76 darling::export::syn::Lit::Int(lit) => Ok(Self::from(lit.base10_parse::<u16>()?)),
77 _ => Err(darling::Error::unknown_value("invalid event id")),
78 }
79 }
80}
81
82impl quote::ToTokens for EventId {
83 fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) {
84 let me = self.0;
85 tokens.extend(quote!(
86 {
87 use dfirtk_eventdata::EventId;
88 EventId(#me)
89 }
90 ))
91 }
92}