Skip to main content

winreg_format/
flags.rs

1//! Bitflags and enums for registry cell fields.
2
3use bitflags::bitflags;
4
5bitflags! {
6    /// NK cell flags (offset 0x02 in NK cell, u16).
7    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
8    pub struct KeyFlags: u16 {
9        const VOLATILE      = 0x0001;
10        const HIVE_EXIT     = 0x0002;
11        const HIVE_ENTRY    = 0x0004;
12        const NO_DELETE     = 0x0008;
13        const SYM_LINK      = 0x0010;
14        const COMP_NAME     = 0x0020;
15        const PREDEF_HANDLE = 0x0040;
16        const VIRT_MIRRORED = 0x0080;
17        const VIRT_TARGET   = 0x0100;
18        const VIRTUAL_STORE = 0x0200;
19    }
20}
21
22bitflags! {
23    /// VK cell flags (offset 0x10 in VK cell, u16).
24    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
25    pub struct ValueFlags: u16 {
26        const COMP_NAME = 0x0001;
27    }
28}
29
30/// Registry value data type (offset 0x0C in VK cell, u32).
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32#[repr(u32)]
33pub enum ValueType {
34    None = 0,
35    Sz = 1,
36    ExpandSz = 2,
37    Binary = 3,
38    Dword = 4,
39    DwordBigEndian = 5,
40    Link = 6,
41    MultiSz = 7,
42    ResourceList = 8,
43    FullResourceDescriptor = 9,
44    ResourceRequirementsList = 10,
45    Qword = 11,
46    Unknown(u32),
47}
48
49impl ValueType {
50    pub fn from_raw(raw: u32) -> Self {
51        match raw {
52            0 => Self::None,
53            1 => Self::Sz,
54            2 => Self::ExpandSz,
55            3 => Self::Binary,
56            4 => Self::Dword,
57            5 => Self::DwordBigEndian,
58            6 => Self::Link,
59            7 => Self::MultiSz,
60            8 => Self::ResourceList,
61            9 => Self::FullResourceDescriptor,
62            10 => Self::ResourceRequirementsList,
63            11 => Self::Qword,
64            other => Self::Unknown(other),
65        }
66    }
67
68    pub fn name(&self) -> &str {
69        match self {
70            Self::None => "REG_NONE",
71            Self::Sz => "REG_SZ",
72            Self::ExpandSz => "REG_EXPAND_SZ",
73            Self::Binary => "REG_BINARY",
74            Self::Dword => "REG_DWORD",
75            Self::DwordBigEndian => "REG_DWORD_BIG_ENDIAN",
76            Self::Link => "REG_LINK",
77            Self::MultiSz => "REG_MULTI_SZ",
78            Self::ResourceList => "REG_RESOURCE_LIST",
79            Self::FullResourceDescriptor => "REG_FULL_RESOURCE_DESCRIPTOR",
80            Self::ResourceRequirementsList => "REG_RESOURCE_REQUIREMENTS_LIST",
81            Self::Qword => "REG_QWORD",
82            Self::Unknown(_) => "REG_UNKNOWN",
83        }
84    }
85}
86
87impl std::fmt::Display for ValueType {
88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89        write!(f, "{}", self.name())
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn key_flags_comp_name() {
99        let flags = KeyFlags::COMP_NAME | KeyFlags::HIVE_ENTRY;
100        assert!(flags.contains(KeyFlags::COMP_NAME));
101        assert!(flags.contains(KeyFlags::HIVE_ENTRY));
102        assert!(!flags.contains(KeyFlags::VOLATILE));
103    }
104
105    #[test]
106    fn value_type_roundtrip() {
107        for raw in 0..=11 {
108            let vt = ValueType::from_raw(raw);
109            assert_ne!(vt.name(), "REG_UNKNOWN");
110        }
111        assert!(matches!(ValueType::from_raw(99), ValueType::Unknown(99)));
112    }
113
114    #[test]
115    fn value_type_display() {
116        assert_eq!(ValueType::Sz.to_string(), "REG_SZ");
117        assert_eq!(ValueType::Dword.to_string(), "REG_DWORD");
118        assert_eq!(ValueType::MultiSz.to_string(), "REG_MULTI_SZ");
119    }
120}