wraith/km/
string.rs

1//! Kernel-mode string types (UNICODE_STRING, ANSI_STRING)
2
3use core::ffi::c_void;
4use core::ptr::NonNull;
5use alloc::vec::Vec;
6
7use super::allocator::{PoolAllocator, PoolTag, PoolType};
8use super::error::{KmError, KmResult};
9
10/// Windows UNICODE_STRING structure
11#[repr(C)]
12#[derive(Debug, Clone, Copy)]
13pub struct UnicodeStringRaw {
14    pub length: u16,
15    pub maximum_length: u16,
16    pub buffer: *mut u16,
17}
18
19impl Default for UnicodeStringRaw {
20    fn default() -> Self {
21        Self {
22            length: 0,
23            maximum_length: 0,
24            buffer: core::ptr::null_mut(),
25        }
26    }
27}
28
29/// safe wrapper around UNICODE_STRING
30pub struct UnicodeString {
31    inner: UnicodeStringRaw,
32    owned: bool,
33}
34
35impl UnicodeString {
36    /// create empty unicode string
37    pub const fn empty() -> Self {
38        Self {
39            inner: UnicodeStringRaw {
40                length: 0,
41                maximum_length: 0,
42                buffer: core::ptr::null_mut(),
43            },
44            owned: false,
45        }
46    }
47
48    /// create from static wide string (null-terminated)
49    ///
50    /// # Safety
51    /// s must be a valid null-terminated wide string that outlives this struct
52    pub const unsafe fn from_static(s: &'static [u16]) -> Self {
53        let len = (s.len() - 1) * 2; // exclude null terminator
54        Self {
55            inner: UnicodeStringRaw {
56                length: len as u16,
57                maximum_length: (s.len() * 2) as u16,
58                buffer: s.as_ptr() as *mut u16,
59            },
60            owned: false,
61        }
62    }
63
64    /// create owned copy from &str
65    pub fn from_str(s: &str) -> KmResult<Self> {
66        let wide: Vec<u16> = s.encode_utf16().chain(core::iter::once(0)).collect();
67        Self::from_wide_owned(wide)
68    }
69
70    /// create from wide string (takes ownership)
71    pub fn from_wide_owned(mut wide: Vec<u16>) -> KmResult<Self> {
72        let len_bytes = (wide.len() - 1) * 2; // exclude null terminator
73        let max_bytes = wide.len() * 2;
74
75        // ensure null terminator
76        if wide.last() != Some(&0) {
77            wide.push(0);
78        }
79
80        let ptr = wide.as_mut_ptr();
81        core::mem::forget(wide); // we now own this memory
82
83        Ok(Self {
84            inner: UnicodeStringRaw {
85                length: len_bytes as u16,
86                maximum_length: max_bytes as u16,
87                buffer: ptr,
88            },
89            owned: true,
90        })
91    }
92
93    /// get raw structure for FFI
94    pub fn as_raw(&self) -> &UnicodeStringRaw {
95        &self.inner
96    }
97
98    /// get mutable raw structure for FFI
99    pub fn as_raw_mut(&mut self) -> &mut UnicodeStringRaw {
100        &mut self.inner
101    }
102
103    /// get pointer to raw structure
104    pub fn as_ptr(&self) -> *const UnicodeStringRaw {
105        &self.inner
106    }
107
108    /// get mutable pointer to raw structure
109    pub fn as_mut_ptr(&mut self) -> *mut UnicodeStringRaw {
110        &mut self.inner
111    }
112
113    /// get string length in bytes
114    pub fn len(&self) -> usize {
115        self.inner.length as usize
116    }
117
118    /// check if string is empty
119    pub fn is_empty(&self) -> bool {
120        self.inner.length == 0
121    }
122
123    /// get as wide string slice (without null terminator)
124    pub fn as_wide(&self) -> &[u16] {
125        if self.inner.buffer.is_null() || self.inner.length == 0 {
126            return &[];
127        }
128        // SAFETY: buffer is valid for length bytes
129        unsafe {
130            core::slice::from_raw_parts(
131                self.inner.buffer,
132                (self.inner.length / 2) as usize,
133            )
134        }
135    }
136}
137
138impl Drop for UnicodeString {
139    fn drop(&mut self) {
140        if self.owned && !self.inner.buffer.is_null() {
141            // reconstruct Vec to deallocate
142            let cap = (self.inner.maximum_length / 2) as usize;
143            let len = cap; // we allocated this many
144            // SAFETY: we allocated this buffer via Vec
145            unsafe {
146                let _ = Vec::from_raw_parts(self.inner.buffer, len, cap);
147            }
148        }
149    }
150}
151
152/// Windows ANSI_STRING structure
153#[repr(C)]
154#[derive(Debug, Clone, Copy)]
155pub struct AnsiStringRaw {
156    pub length: u16,
157    pub maximum_length: u16,
158    pub buffer: *mut u8,
159}
160
161impl Default for AnsiStringRaw {
162    fn default() -> Self {
163        Self {
164            length: 0,
165            maximum_length: 0,
166            buffer: core::ptr::null_mut(),
167        }
168    }
169}
170
171/// safe wrapper around ANSI_STRING
172pub struct AnsiString {
173    inner: AnsiStringRaw,
174    owned: bool,
175}
176
177impl AnsiString {
178    /// create empty ansi string
179    pub const fn empty() -> Self {
180        Self {
181            inner: AnsiStringRaw {
182                length: 0,
183                maximum_length: 0,
184                buffer: core::ptr::null_mut(),
185            },
186            owned: false,
187        }
188    }
189
190    /// create from static byte string
191    ///
192    /// # Safety
193    /// s must be a valid null-terminated string that outlives this struct
194    pub const unsafe fn from_static(s: &'static [u8]) -> Self {
195        let len = s.len() - 1; // exclude null terminator
196        Self {
197            inner: AnsiStringRaw {
198                length: len as u16,
199                maximum_length: s.len() as u16,
200                buffer: s.as_ptr() as *mut u8,
201            },
202            owned: false,
203        }
204    }
205
206    /// create owned copy from &str
207    pub fn from_str(s: &str) -> KmResult<Self> {
208        let mut bytes: Vec<u8> = s.as_bytes().to_vec();
209        bytes.push(0); // null terminator
210
211        let len = s.len();
212        let max_len = bytes.len();
213        let ptr = bytes.as_mut_ptr();
214        core::mem::forget(bytes);
215
216        Ok(Self {
217            inner: AnsiStringRaw {
218                length: len as u16,
219                maximum_length: max_len as u16,
220                buffer: ptr,
221            },
222            owned: true,
223        })
224    }
225
226    /// get raw structure for FFI
227    pub fn as_raw(&self) -> &AnsiStringRaw {
228        &self.inner
229    }
230
231    /// get as byte slice (without null terminator)
232    pub fn as_bytes(&self) -> &[u8] {
233        if self.inner.buffer.is_null() || self.inner.length == 0 {
234            return &[];
235        }
236        // SAFETY: buffer is valid for length bytes
237        unsafe {
238            core::slice::from_raw_parts(self.inner.buffer, self.inner.length as usize)
239        }
240    }
241}
242
243impl Drop for AnsiString {
244    fn drop(&mut self) {
245        if self.owned && !self.inner.buffer.is_null() {
246            let cap = self.inner.maximum_length as usize;
247            // SAFETY: we allocated this buffer via Vec
248            unsafe {
249                let _ = Vec::from_raw_parts(self.inner.buffer, cap, cap);
250            }
251        }
252    }
253}
254
255/// helper macro to create static unicode strings
256#[macro_export]
257macro_rules! unicode_str {
258    ($s:literal) => {{
259        const WIDE: &[u16] = &$crate::km::string::encode_wide_const($s);
260        // SAFETY: static lifetime
261        unsafe { $crate::km::string::UnicodeString::from_static(WIDE) }
262    }};
263}
264
265/// compile-time wide string encoding (limited to ASCII)
266pub const fn encode_wide_const<const N: usize>(s: &str) -> [u16; N] {
267    let bytes = s.as_bytes();
268    let mut result = [0u16; N];
269    let mut i = 0;
270    while i < bytes.len() && i < N - 1 {
271        result[i] = bytes[i] as u16;
272        i += 1;
273    }
274    result
275}