windows_strings/
hstring_header.rs

1use super::*;
2
3pub const HSTRING_REFERENCE_FLAG: u32 = 1;
4
5#[repr(C)]
6pub struct HStringHeader {
7    pub flags: u32,
8    pub len: u32,
9    pub _0: u32,
10    pub _1: u32,
11    pub data: *mut u16,
12    pub count: RefCount,
13    pub buffer_start: u16,
14}
15
16impl HStringHeader {
17    pub fn alloc(len: u32) -> *mut Self {
18        if len == 0 {
19            return core::ptr::null_mut();
20        }
21
22        // Allocate enough space for header and two bytes per character.
23        // The space for the terminating null character is already accounted for inside of `HStringHeader`.
24        let bytes = core::mem::size_of::<Self>() + 2 * len as usize;
25
26        let header =
27            unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) } as *mut Self;
28
29        if header.is_null() {
30            panic!("allocation failed");
31        }
32
33        unsafe {
34            // Use `ptr::write` (since `header` is unintialized). `HStringHeader` is safe to be all zeros.
35            header.write(core::mem::MaybeUninit::<Self>::zeroed().assume_init());
36            (*header).len = len;
37            (*header).count = RefCount::new(1);
38            (*header).data = &mut (*header).buffer_start;
39        }
40
41        header
42    }
43
44    pub unsafe fn free(header: *mut Self) {
45        if header.is_null() {
46            return;
47        }
48
49        unsafe {
50            bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _);
51        }
52    }
53
54    pub fn duplicate(&self) -> *mut Self {
55        if self.flags & HSTRING_REFERENCE_FLAG == 0 {
56            // If this is not a "fast pass" string then simply increment the reference count.
57            self.count.add_ref();
58            self as *const Self as *mut Self
59        } else {
60            // Otherwise, allocate a new string and copy the value into the new string.
61            let copy = Self::alloc(self.len);
62            // SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
63            // We copy `len + 1` characters since `len` does not account for the terminating null character.
64            unsafe {
65                core::ptr::copy_nonoverlapping(self.data, (*copy).data, self.len as usize + 1);
66            }
67            copy
68        }
69    }
70}