summaryrefslogtreecommitdiff
path: root/vendor/windows-strings/src/hstring_header.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/windows-strings/src/hstring_header.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/windows-strings/src/hstring_header.rs')
-rw-r--r--vendor/windows-strings/src/hstring_header.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/vendor/windows-strings/src/hstring_header.rs b/vendor/windows-strings/src/hstring_header.rs
new file mode 100644
index 00000000..39401102
--- /dev/null
+++ b/vendor/windows-strings/src/hstring_header.rs
@@ -0,0 +1,70 @@
+use super::*;
+
+pub const HSTRING_REFERENCE_FLAG: u32 = 1;
+
+#[repr(C)]
+pub struct HStringHeader {
+ pub flags: u32,
+ pub len: u32,
+ pub _0: u32,
+ pub _1: u32,
+ pub data: *mut u16,
+ pub count: RefCount,
+ pub buffer_start: u16,
+}
+
+impl HStringHeader {
+ pub fn alloc(len: u32) -> *mut Self {
+ if len == 0 {
+ return core::ptr::null_mut();
+ }
+
+ // Allocate enough space for header and two bytes per character.
+ // The space for the terminating null character is already accounted for inside of `HStringHeader`.
+ let bytes = core::mem::size_of::<Self>() + 2 * len as usize;
+
+ let header =
+ unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) } as *mut Self;
+
+ if header.is_null() {
+ panic!("allocation failed");
+ }
+
+ unsafe {
+ // Use `ptr::write` (since `header` is uninitialized). `HStringHeader` is safe to be all zeros.
+ header.write(core::mem::MaybeUninit::<Self>::zeroed().assume_init());
+ (*header).len = len;
+ (*header).count = RefCount::new(1);
+ (*header).data = &mut (*header).buffer_start;
+ }
+
+ header
+ }
+
+ pub unsafe fn free(header: *mut Self) {
+ if header.is_null() {
+ return;
+ }
+
+ unsafe {
+ bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _);
+ }
+ }
+
+ pub fn duplicate(&self) -> *mut Self {
+ if self.flags & HSTRING_REFERENCE_FLAG == 0 {
+ // If this is not a "fast pass" string then simply increment the reference count.
+ self.count.add_ref();
+ self as *const Self as *mut Self
+ } else {
+ // Otherwise, allocate a new string and copy the value into the new string.
+ let copy = Self::alloc(self.len);
+ // SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
+ // We copy `len + 1` characters since `len` does not account for the terminating null character.
+ unsafe {
+ core::ptr::copy_nonoverlapping(self.data, (*copy).data, self.len as usize + 1);
+ }
+ copy
+ }
+ }
+}