td_shim_interface/td_uefi_pi/pi/
guid.rs1use core::{convert::TryInto, mem::size_of, ptr::slice_from_raw_parts, str::FromStr};
2
3use scroll::{Pread, Pwrite};
4
5const GUID_STRING_LEN: usize = 36;
8const GUID_SPLITTER: u8 = b'-';
9
10#[repr(C)]
13#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Pwrite, Pread)]
14pub struct Guid {
15 f0: u32,
16 f1: u16,
17 f2: u16,
18 f3: [u8; 8],
19}
20
21#[derive(Debug)]
22pub enum GuidParseError {
23 InvalidInput,
24}
25
26impl Guid {
27 pub const fn from_fields(f0: u32, f1: u16, f2: u16, f3: [u8; 8]) -> Guid {
29 Self { f0, f1, f2, f3 }
30 }
31
32 pub fn as_bytes(&self) -> &[u8; 16] {
33 unsafe {
35 (&*slice_from_raw_parts(self as *const Self as *const u8, size_of::<Self>()))
36 .try_into()
37 .unwrap()
38 }
39 }
40
41 pub fn from_bytes(buffer: &[u8; 16]) -> Guid {
42 let f0 = u32::from_le_bytes(buffer[0..4].try_into().unwrap());
43 let f1 = u16::from_le_bytes(buffer[4..6].try_into().unwrap());
44 let f2 = u16::from_le_bytes(buffer[6..8].try_into().unwrap());
45 let mut f3: [u8; 8] = [0; 8];
46 f3.copy_from_slice(&buffer[8..]);
47
48 Self { f0, f1, f2, f3 }
49 }
50}
51
52impl FromStr for Guid {
53 type Err = GuidParseError;
54
55 fn from_str(s: &str) -> Result<Self, Self::Err> {
59 let b = s.as_bytes();
60 if b.len() != GUID_STRING_LEN
61 || b[8] != GUID_SPLITTER
62 || b[13] != GUID_SPLITTER
63 || b[18] != GUID_SPLITTER
64 || b[23] != GUID_SPLITTER
65 {
66 return Err(GuidParseError::InvalidInput);
67 }
68
69 let parse_hex = |s: &str| -> Option<u64> {
70 for c in s.as_bytes() {
71 if !c.is_ascii_hexdigit() {
72 return None;
73 }
74 }
75 u64::from_str_radix(s, 16).ok()
76 };
77
78 let f0 = parse_hex(&s[0..8]).ok_or(GuidParseError::InvalidInput)? as u32;
80 let f1 = parse_hex(&s[9..13]).ok_or(GuidParseError::InvalidInput)? as u16;
81 let f2 = parse_hex(&s[14..18]).ok_or(GuidParseError::InvalidInput)? as u16;
82 let mut f3 = parse_hex(&s[19..23]).ok_or(GuidParseError::InvalidInput)? << 48;
83 f3 |= parse_hex(&s[24..36]).ok_or(GuidParseError::InvalidInput)?;
84
85 Ok(Self {
87 f0,
88 f1,
89 f2,
90 f3: u64::to_be_bytes(f3),
91 })
92 }
93}
94
95#[cfg(test)]
96mod test {
97 use super::*;
98
99 #[test]
100 fn test_guid() {
101 let guid_bytes = [
103 0x5E, 0x8C, 0x16, 0xF9, 0xB2, 0xCE, 0xaa, 0x4f, 0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F,
104 0xA1, 0xE4,
105 ];
106 let guid_field = Guid::from_fields(
107 0xF9168C5E,
108 0xCEB2,
109 0x4faa,
110 [0xB6, 0xBF, 0x32, 0x9B, 0xF3, 0x9F, 0xA1, 0xE4],
111 );
112
113 assert_eq!(&guid_bytes, guid_field.as_bytes());
114
115 let guid_str = Guid::from_str("F9168C5E-CEB2-4faa-B6BF-329BF39FA1E4").unwrap();
116 assert_eq!(&guid_bytes, guid_str.as_bytes());
117
118 let guid_str = Guid::from_str("F9168C5E");
119 assert!(guid_str.is_err());
120
121 let guid_str = Guid::from_str("F9168C5E-CEB2-4faa-B6BF-329");
122 assert!(guid_str.is_err());
123
124 let guid_str = Guid::from_str("F9168C5E-CEB2-4faaB6-BF-329BF39FA1E4");
125 assert!(guid_str.is_err());
126
127 let guid_str = Guid::from_str("+9168C5E-CEB2-4faa-B6BF-329BF39FA1E4");
128 assert!(guid_str.is_err());
129
130 let guid_str = Guid::from_str("F9168C5ECCEB2C4faaCB6BFC329BF39FA1E4");
131 assert!(guid_str.is_err());
132 }
133}