summaryrefslogtreecommitdiff
path: root/vendor/windows-registry/src/data.rs
blob: a456394d673921008b4fbd4ef6fdbd1775a9ce5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use super::*;

// Minimal `Vec<u8>` replacement providing at least `u16` alignment so that it can be used for wide strings.
pub struct Data {
    ptr: *mut u8,
    len: usize,
}

impl Data {
    // Creates a buffer with the specified length of zero bytes.
    pub fn new(len: usize) -> Self {
        unsafe {
            let bytes = Self::alloc(len);

            if len > 0 {
                core::ptr::write_bytes(bytes.ptr, 0, len);
            }

            bytes
        }
    }

    // Returns the buffer as a slice of u16 for reading wide characters.
    pub fn as_wide(&self) -> &[u16] {
        if self.ptr.is_null() {
            &[]
        } else {
            unsafe { core::slice::from_raw_parts(self.ptr as *const u16, self.len / 2) }
        }
    }

    // Creates a buffer by copying the bytes from the slice.
    pub fn from_slice(slice: &[u8]) -> Self {
        unsafe {
            let bytes = Self::alloc(slice.len());

            if !slice.is_empty() {
                core::ptr::copy_nonoverlapping(slice.as_ptr(), bytes.ptr, slice.len());
            }

            bytes
        }
    }

    // Allocates an uninitialized buffer.
    unsafe fn alloc(len: usize) -> Self {
        if len == 0 {
            Self {
                ptr: null_mut(),
                len: 0,
            }
        } else {
            // This pointer will have at least 8 byte alignment.
            let ptr = unsafe { HeapAlloc(GetProcessHeap(), 0, len) as *mut u8 };

            if ptr.is_null() {
                panic!("allocation failed");
            }

            Self { ptr, len }
        }
    }
}

impl Drop for Data {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            unsafe {
                HeapFree(GetProcessHeap(), 0, self.ptr as *mut _);
            }
        }
    }
}

impl Deref for Data {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            &[]
        } else {
            unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
        }
    }
}

impl core::ops::DerefMut for Data {
    fn deref_mut(&mut self) -> &mut [u8] {
        if self.ptr.is_null() {
            &mut []
        } else {
            unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
        }
    }
}

impl Clone for Data {
    fn clone(&self) -> Self {
        Self::from_slice(self)
    }
}

impl PartialEq for Data {
    fn eq(&self, other: &Self) -> bool {
        self.deref() == other.deref()
    }
}

impl Eq for Data {}

impl core::fmt::Debug for Data {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        self.deref().fmt(f)
    }
}

impl<const N: usize> From<[u8; N]> for Data {
    fn from(from: [u8; N]) -> Self {
        Self::from_slice(&from)
    }
}