summaryrefslogtreecommitdiff
path: root/vendor/windows-strings/src
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
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/windows-strings/src')
-rw-r--r--vendor/windows-strings/src/bindings.rs19
-rw-r--r--vendor/windows-strings/src/bstr.rs166
-rw-r--r--vendor/windows-strings/src/decode.rs58
-rw-r--r--vendor/windows-strings/src/hstring.rs392
-rw-r--r--vendor/windows-strings/src/hstring_builder.rs100
-rw-r--r--vendor/windows-strings/src/hstring_header.rs70
-rw-r--r--vendor/windows-strings/src/lib.rs47
-rw-r--r--vendor/windows-strings/src/literals.rs169
-rw-r--r--vendor/windows-strings/src/pcstr.rs64
-rw-r--r--vendor/windows-strings/src/pcwstr.rs97
-rw-r--r--vendor/windows-strings/src/pstr.rs64
-rw-r--r--vendor/windows-strings/src/pwstr.rs88
-rw-r--r--vendor/windows-strings/src/ref_count.rs27
13 files changed, 1361 insertions, 0 deletions
diff --git a/vendor/windows-strings/src/bindings.rs b/vendor/windows-strings/src/bindings.rs
new file mode 100644
index 00000000..2e0ad17d
--- /dev/null
+++ b/vendor/windows-strings/src/bindings.rs
@@ -0,0 +1,19 @@
+#![allow(
+ non_snake_case,
+ non_upper_case_globals,
+ non_camel_case_types,
+ dead_code,
+ clippy::all
+)]
+
+windows_link::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE);
+windows_link::link!("kernel32.dll" "system" fn HeapAlloc(hheap : HANDLE, dwflags : HEAP_FLAGS, dwbytes : usize) -> *mut core::ffi::c_void);
+windows_link::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL);
+windows_link::link!("oleaut32.dll" "system" fn SysAllocStringLen(strin : PCWSTR, ui : u32) -> BSTR);
+windows_link::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR));
+windows_link::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32);
+pub type BOOL = i32;
+pub type BSTR = *const u16;
+pub type HANDLE = *mut core::ffi::c_void;
+pub type HEAP_FLAGS = u32;
+pub type PCWSTR = *const u16;
diff --git a/vendor/windows-strings/src/bstr.rs b/vendor/windows-strings/src/bstr.rs
new file mode 100644
index 00000000..486b2602
--- /dev/null
+++ b/vendor/windows-strings/src/bstr.rs
@@ -0,0 +1,166 @@
+use super::*;
+use core::ops::Deref;
+
+/// A BSTR string ([BSTR](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/string-manipulation-functions))
+/// is a length-prefixed wide string.
+#[repr(transparent)]
+pub struct BSTR(*const u16);
+
+impl BSTR {
+ /// Create an empty `BSTR`.
+ ///
+ /// This function does not allocate memory.
+ pub const fn new() -> Self {
+ Self(core::ptr::null_mut())
+ }
+
+ /// Create a `BSTR` from a slice of 16 bit characters (wchars).
+ pub fn from_wide(value: &[u16]) -> Self {
+ if value.is_empty() {
+ return Self::new();
+ }
+
+ let result = unsafe {
+ Self(bindings::SysAllocStringLen(
+ value.as_ptr(),
+ value.len().try_into().unwrap(),
+ ))
+ };
+
+ if result.is_empty() {
+ panic!("allocation failed");
+ }
+
+ result
+ }
+
+ /// # Safety
+ #[doc(hidden)]
+ pub unsafe fn from_raw(raw: *const u16) -> Self {
+ Self(raw)
+ }
+
+ /// # Safety
+ #[doc(hidden)]
+ pub fn into_raw(self) -> *const u16 {
+ unsafe { core::mem::transmute(self) }
+ }
+}
+
+impl Deref for BSTR {
+ type Target = [u16];
+
+ fn deref(&self) -> &[u16] {
+ let len = if self.0.is_null() {
+ 0
+ } else {
+ unsafe { bindings::SysStringLen(self.0) as usize }
+ };
+
+ if len > 0 {
+ unsafe { core::slice::from_raw_parts(self.0, len) }
+ } else {
+ // This ensures that if `as_ptr` is called on the slice that the resulting pointer
+ // will still refer to a null-terminated string.
+ const EMPTY: [u16; 1] = [0];
+ &EMPTY[..0]
+ }
+ }
+}
+
+impl Clone for BSTR {
+ fn clone(&self) -> Self {
+ Self::from_wide(self)
+ }
+}
+
+impl From<&str> for BSTR {
+ fn from(value: &str) -> Self {
+ let value: alloc::vec::Vec<u16> = value.encode_utf16().collect();
+ Self::from_wide(&value)
+ }
+}
+
+impl From<String> for BSTR {
+ fn from(value: String) -> Self {
+ value.as_str().into()
+ }
+}
+
+impl From<&String> for BSTR {
+ fn from(value: &String) -> Self {
+ value.as_str().into()
+ }
+}
+
+impl TryFrom<&BSTR> for String {
+ type Error = alloc::string::FromUtf16Error;
+
+ fn try_from(value: &BSTR) -> core::result::Result<Self, Self::Error> {
+ String::from_utf16(value)
+ }
+}
+
+impl TryFrom<BSTR> for String {
+ type Error = alloc::string::FromUtf16Error;
+
+ fn try_from(value: BSTR) -> core::result::Result<Self, Self::Error> {
+ String::try_from(&value)
+ }
+}
+
+impl Default for BSTR {
+ fn default() -> Self {
+ Self(core::ptr::null_mut())
+ }
+}
+
+impl core::fmt::Display for BSTR {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::write!(
+ f,
+ "{}",
+ Decode(|| core::char::decode_utf16(self.iter().cloned()))
+ )
+ }
+}
+
+impl core::fmt::Debug for BSTR {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::write!(f, "{self}")
+ }
+}
+
+impl PartialEq for BSTR {
+ fn eq(&self, other: &Self) -> bool {
+ self.deref() == other.deref()
+ }
+}
+
+impl Eq for BSTR {}
+
+impl PartialEq<BSTR> for &str {
+ fn eq(&self, other: &BSTR) -> bool {
+ other == self
+ }
+}
+
+impl PartialEq<BSTR> for String {
+ fn eq(&self, other: &BSTR) -> bool {
+ other == self
+ }
+}
+
+impl<T: AsRef<str> + ?Sized> PartialEq<T> for BSTR {
+ fn eq(&self, other: &T) -> bool {
+ self.iter().copied().eq(other.as_ref().encode_utf16())
+ }
+}
+
+impl Drop for BSTR {
+ fn drop(&mut self) {
+ if !self.0.is_null() {
+ unsafe { bindings::SysFreeString(self.0) }
+ }
+ }
+}
diff --git a/vendor/windows-strings/src/decode.rs b/vendor/windows-strings/src/decode.rs
new file mode 100644
index 00000000..dbc9e2ea
--- /dev/null
+++ b/vendor/windows-strings/src/decode.rs
@@ -0,0 +1,58 @@
+/// An internal helper for decoding an iterator of chars and displaying them
+pub struct Decode<F>(pub F);
+
+impl<F, R, E> core::fmt::Display for Decode<F>
+where
+ F: Clone + FnOnce() -> R,
+ R: IntoIterator<Item = core::result::Result<char, E>>,
+{
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ use core::fmt::Write;
+ let iter = self.0.clone();
+ for c in iter().into_iter() {
+ f.write_char(c.unwrap_or(core::char::REPLACEMENT_CHARACTER))?
+ }
+ Ok(())
+ }
+}
+
+/// Mirror of `std::char::decode_utf16` for utf-8.
+pub fn decode_utf8(
+ mut buffer: &[u8],
+) -> impl Iterator<Item = core::result::Result<char, core::str::Utf8Error>> + '_ {
+ let mut current = "".chars();
+ let mut previous_error = None;
+ core::iter::from_fn(move || {
+ loop {
+ match (current.next(), previous_error) {
+ (Some(c), _) => return Some(Ok(c)),
+ // Return the previous error
+ (None, Some(e)) => {
+ previous_error = None;
+ return Some(Err(e));
+ }
+ // We're completely done
+ (None, None) if buffer.is_empty() => return None,
+ (None, None) => {
+ match core::str::from_utf8(buffer) {
+ Ok(s) => {
+ current = s.chars();
+ buffer = &[];
+ }
+ Err(e) => {
+ let (valid, rest) = buffer.split_at(e.valid_up_to());
+ // Skip the invalid sequence and stop completely if we ended early
+ let invalid_sequence_length = e.error_len()?;
+ buffer = &rest[invalid_sequence_length..];
+
+ // Set the current iterator to the valid section and indicate previous error
+ // SAFETY: `valid` is known to be valid utf-8 from error
+ current = unsafe { core::str::from_utf8_unchecked(valid) }.chars();
+ previous_error = Some(e);
+ }
+ }
+ }
+ }
+ }
+ })
+}
diff --git a/vendor/windows-strings/src/hstring.rs b/vendor/windows-strings/src/hstring.rs
new file mode 100644
index 00000000..a8e359f0
--- /dev/null
+++ b/vendor/windows-strings/src/hstring.rs
@@ -0,0 +1,392 @@
+use super::*;
+use core::ops::Deref;
+
+/// An ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
+/// is a reference-counted and immutable UTF-16 string type.
+#[repr(transparent)]
+pub struct HSTRING(pub(crate) *mut HStringHeader);
+
+impl HSTRING {
+ /// Create an empty `HSTRING`.
+ ///
+ /// This function does not allocate memory.
+ pub const fn new() -> Self {
+ Self(core::ptr::null_mut())
+ }
+
+ /// Create a `HSTRING` from a slice of 16 bit characters (wchars).
+ pub fn from_wide(value: &[u16]) -> Self {
+ unsafe { Self::from_wide_iter(value.iter().copied(), value.len()) }
+ }
+
+ /// Get the contents of this `HSTRING` as a String lossily.
+ pub fn to_string_lossy(&self) -> String {
+ String::from_utf16_lossy(self)
+ }
+
+ /// Get the contents of this `HSTRING` as a OsString.
+ #[cfg(feature = "std")]
+ pub fn to_os_string(&self) -> std::ffi::OsString {
+ std::os::windows::ffi::OsStringExt::from_wide(self)
+ }
+
+ /// # Safety
+ /// len must not be less than the number of items in the iterator.
+ unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Self {
+ if len == 0 {
+ return Self::new();
+ }
+
+ let ptr = HStringHeader::alloc(len.try_into().unwrap());
+
+ // Place each utf-16 character into the buffer and
+ // increase len as we go along.
+ for (index, wide) in iter.enumerate() {
+ debug_assert!(index < len);
+
+ unsafe {
+ (*ptr).data.add(index).write(wide);
+ (*ptr).len = index as u32 + 1;
+ }
+ }
+
+ unsafe {
+ // Write a 0 byte to the end of the buffer.
+ (*ptr).data.offset((*ptr).len as isize).write(0);
+ }
+ Self(ptr)
+ }
+
+ fn as_header(&self) -> Option<&HStringHeader> {
+ unsafe { self.0.as_ref() }
+ }
+}
+
+impl Deref for HSTRING {
+ type Target = [u16];
+
+ fn deref(&self) -> &[u16] {
+ if let Some(header) = self.as_header() {
+ unsafe { core::slice::from_raw_parts(header.data, header.len as usize) }
+ } else {
+ // This ensures that if `as_ptr` is called on the slice that the resulting pointer
+ // will still refer to a null-terminated string.
+ const EMPTY: [u16; 1] = [0];
+ &EMPTY[..0]
+ }
+ }
+}
+
+impl Default for HSTRING {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl Clone for HSTRING {
+ fn clone(&self) -> Self {
+ if let Some(header) = self.as_header() {
+ Self(header.duplicate())
+ } else {
+ Self::new()
+ }
+ }
+}
+
+impl Drop for HSTRING {
+ fn drop(&mut self) {
+ if let Some(header) = self.as_header() {
+ // HSTRING_REFERENCE_FLAG indicates a string backed by static or stack memory that is
+ // thus not reference-counted and does not need to be freed.
+ unsafe {
+ if header.flags & HSTRING_REFERENCE_FLAG == 0 && header.count.release() == 0 {
+ HStringHeader::free(self.0);
+ }
+ }
+ }
+ }
+}
+
+unsafe impl Send for HSTRING {}
+unsafe impl Sync for HSTRING {}
+
+impl core::fmt::Display for HSTRING {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "{}",
+ Decode(|| core::char::decode_utf16(self.iter().cloned()))
+ )
+ }
+}
+
+impl core::fmt::Debug for HSTRING {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "\"{self}\"")
+ }
+}
+
+impl From<&str> for HSTRING {
+ fn from(value: &str) -> Self {
+ unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()) }
+ }
+}
+
+impl From<String> for HSTRING {
+ fn from(value: String) -> Self {
+ value.as_str().into()
+ }
+}
+
+impl From<&String> for HSTRING {
+ fn from(value: &String) -> Self {
+ value.as_str().into()
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<&std::path::Path> for HSTRING {
+ fn from(value: &std::path::Path) -> Self {
+ value.as_os_str().into()
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<&std::ffi::OsStr> for HSTRING {
+ fn from(value: &std::ffi::OsStr) -> Self {
+ unsafe {
+ Self::from_wide_iter(
+ std::os::windows::ffi::OsStrExt::encode_wide(value),
+ value.len(),
+ )
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<std::ffi::OsString> for HSTRING {
+ fn from(value: std::ffi::OsString) -> Self {
+ value.as_os_str().into()
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<&std::ffi::OsString> for HSTRING {
+ fn from(value: &std::ffi::OsString) -> Self {
+ value.as_os_str().into()
+ }
+}
+
+impl Eq for HSTRING {}
+
+impl Ord for HSTRING {
+ fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+ self.deref().cmp(other)
+ }
+}
+
+impl core::hash::Hash for HSTRING {
+ fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
+ self.deref().hash(hasher)
+ }
+}
+
+impl PartialOrd for HSTRING {
+ fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for HSTRING {
+ fn eq(&self, other: &Self) -> bool {
+ self.deref() == other.deref()
+ }
+}
+
+impl PartialEq<String> for HSTRING {
+ fn eq(&self, other: &String) -> bool {
+ *self == **other
+ }
+}
+
+impl PartialEq<String> for &HSTRING {
+ fn eq(&self, other: &String) -> bool {
+ **self == **other
+ }
+}
+
+impl PartialEq<&String> for HSTRING {
+ fn eq(&self, other: &&String) -> bool {
+ *self == ***other
+ }
+}
+
+impl PartialEq<str> for HSTRING {
+ fn eq(&self, other: &str) -> bool {
+ self.iter().copied().eq(other.encode_utf16())
+ }
+}
+
+impl PartialEq<str> for &HSTRING {
+ fn eq(&self, other: &str) -> bool {
+ **self == *other
+ }
+}
+
+impl PartialEq<&str> for HSTRING {
+ fn eq(&self, other: &&str) -> bool {
+ *self == **other
+ }
+}
+
+impl PartialEq<HSTRING> for str {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == *self
+ }
+}
+
+impl PartialEq<HSTRING> for &str {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == **self
+ }
+}
+
+impl PartialEq<&HSTRING> for str {
+ fn eq(&self, other: &&HSTRING) -> bool {
+ **other == *self
+ }
+}
+
+impl PartialEq<HSTRING> for String {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == **self
+ }
+}
+
+impl PartialEq<HSTRING> for &String {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == ***self
+ }
+}
+
+impl PartialEq<&HSTRING> for String {
+ fn eq(&self, other: &&HSTRING) -> bool {
+ **other == **self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<std::ffi::OsString> for HSTRING {
+ fn eq(&self, other: &std::ffi::OsString) -> bool {
+ *self == **other
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<std::ffi::OsString> for &HSTRING {
+ fn eq(&self, other: &std::ffi::OsString) -> bool {
+ **self == **other
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<&std::ffi::OsString> for HSTRING {
+ fn eq(&self, other: &&std::ffi::OsString) -> bool {
+ *self == ***other
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<std::ffi::OsStr> for HSTRING {
+ fn eq(&self, other: &std::ffi::OsStr) -> bool {
+ self.iter()
+ .copied()
+ .eq(std::os::windows::ffi::OsStrExt::encode_wide(other))
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<std::ffi::OsStr> for &HSTRING {
+ fn eq(&self, other: &std::ffi::OsStr) -> bool {
+ **self == *other
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<&std::ffi::OsStr> for HSTRING {
+ fn eq(&self, other: &&std::ffi::OsStr) -> bool {
+ *self == **other
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<HSTRING> for std::ffi::OsStr {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == *self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<HSTRING> for &std::ffi::OsStr {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == **self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<&HSTRING> for std::ffi::OsStr {
+ fn eq(&self, other: &&HSTRING) -> bool {
+ **other == *self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<HSTRING> for std::ffi::OsString {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == **self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<HSTRING> for &std::ffi::OsString {
+ fn eq(&self, other: &HSTRING) -> bool {
+ *other == ***self
+ }
+}
+
+#[cfg(feature = "std")]
+impl PartialEq<&HSTRING> for std::ffi::OsString {
+ fn eq(&self, other: &&HSTRING) -> bool {
+ **other == **self
+ }
+}
+
+impl TryFrom<&HSTRING> for String {
+ type Error = alloc::string::FromUtf16Error;
+
+ fn try_from(hstring: &HSTRING) -> core::result::Result<Self, Self::Error> {
+ String::from_utf16(hstring)
+ }
+}
+
+impl TryFrom<HSTRING> for String {
+ type Error = alloc::string::FromUtf16Error;
+
+ fn try_from(hstring: HSTRING) -> core::result::Result<Self, Self::Error> {
+ String::try_from(&hstring)
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<&HSTRING> for std::ffi::OsString {
+ fn from(hstring: &HSTRING) -> Self {
+ hstring.to_os_string()
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<HSTRING> for std::ffi::OsString {
+ fn from(hstring: HSTRING) -> Self {
+ Self::from(&hstring)
+ }
+}
diff --git a/vendor/windows-strings/src/hstring_builder.rs b/vendor/windows-strings/src/hstring_builder.rs
new file mode 100644
index 00000000..fcbe4d98
--- /dev/null
+++ b/vendor/windows-strings/src/hstring_builder.rs
@@ -0,0 +1,100 @@
+use super::*;
+
+/// An [HSTRING] builder that supports preallocating the `HSTRING` to avoid extra allocations and copies.
+///
+/// This is similar to the `WindowsPreallocateStringBuffer` function but implemented directly in Rust for efficiency.
+/// It is implemented as a separate type since [HSTRING] values are immutable.
+pub struct HStringBuilder(*mut HStringHeader);
+
+impl HStringBuilder {
+ /// Creates a preallocated `HSTRING` value.
+ pub fn new(len: usize) -> Self {
+ let header = HStringHeader::alloc(len.try_into().unwrap());
+
+ if len > 0 {
+ unsafe { core::ptr::write_bytes((*header).data, 0, len) };
+ }
+
+ Self(header)
+ }
+
+ /// Shortens the string by removing any trailing 0 characters.
+ pub fn trim_end(&mut self) {
+ if let Some(header) = self.as_header_mut() {
+ while header.len > 0
+ && unsafe { header.data.offset(header.len as isize - 1).read() == 0 }
+ {
+ header.len -= 1;
+ }
+
+ if header.len == 0 {
+ unsafe {
+ HStringHeader::free(self.0);
+ }
+ self.0 = core::ptr::null_mut();
+ }
+ }
+ }
+
+ /// Allows the `HSTRING` to be constructed from bytes.
+ pub fn as_bytes_mut(&mut self) -> &mut [u8] {
+ if let Some(header) = self.as_header() {
+ unsafe {
+ core::slice::from_raw_parts_mut(header.data as *mut _, header.len as usize * 2)
+ }
+ } else {
+ &mut []
+ }
+ }
+
+ fn as_header(&self) -> Option<&HStringHeader> {
+ unsafe { self.0.as_ref() }
+ }
+
+ fn as_header_mut(&mut self) -> Option<&mut HStringHeader> {
+ unsafe { self.0.as_mut() }
+ }
+}
+
+impl From<HStringBuilder> for HSTRING {
+ fn from(value: HStringBuilder) -> Self {
+ if let Some(header) = value.as_header() {
+ unsafe { header.data.offset(header.len as isize).write(0) };
+ let result = Self(value.0);
+ core::mem::forget(value);
+ result
+ } else {
+ Self::new()
+ }
+ }
+}
+
+impl core::ops::Deref for HStringBuilder {
+ type Target = [u16];
+
+ fn deref(&self) -> &[u16] {
+ if let Some(header) = self.as_header() {
+ unsafe { core::slice::from_raw_parts(header.data, header.len as usize) }
+ } else {
+ &[]
+ }
+ }
+}
+
+impl core::ops::DerefMut for HStringBuilder {
+ fn deref_mut(&mut self) -> &mut [u16] {
+ if let Some(header) = self.as_header() {
+ unsafe { core::slice::from_raw_parts_mut(header.data, header.len as usize) }
+ } else {
+ &mut []
+ }
+ }
+}
+
+impl Drop for HStringBuilder {
+ fn drop(&mut self) {
+ unsafe {
+ HStringHeader::free(self.0);
+ }
+ }
+}
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
+ }
+ }
+}
diff --git a/vendor/windows-strings/src/lib.rs b/vendor/windows-strings/src/lib.rs
new file mode 100644
index 00000000..ba12bb17
--- /dev/null
+++ b/vendor/windows-strings/src/lib.rs
@@ -0,0 +1,47 @@
+#![doc = include_str!("../readme.md")]
+#![cfg(windows)]
+#![allow(non_snake_case)]
+#![debugger_visualizer(natvis_file = "../windows-strings.natvis")]
+#![cfg_attr(all(not(feature = "std")), no_std)]
+
+extern crate alloc;
+use alloc::string::String;
+
+mod bstr;
+pub use bstr::*;
+
+mod hstring;
+pub use hstring::*;
+
+mod hstring_builder;
+pub use hstring_builder::*;
+
+mod hstring_header;
+use hstring_header::*;
+
+mod bindings;
+
+mod decode;
+use decode::*;
+
+mod ref_count;
+use ref_count::*;
+
+mod literals;
+pub use literals::*;
+
+mod pcstr;
+pub use pcstr::*;
+
+mod pcwstr;
+pub use pcwstr::*;
+
+mod pstr;
+pub use pstr::*;
+
+mod pwstr;
+pub use pwstr::*;
+
+extern "C" {
+ fn strlen(s: PCSTR) -> usize;
+}
diff --git a/vendor/windows-strings/src/literals.rs b/vendor/windows-strings/src/literals.rs
new file mode 100644
index 00000000..bb27e79a
--- /dev/null
+++ b/vendor/windows-strings/src/literals.rs
@@ -0,0 +1,169 @@
+/// A literal UTF-8 string with a trailing null terminator.
+#[macro_export]
+macro_rules! s {
+ ($s:literal) => {
+ $crate::PCSTR::from_raw(::core::concat!($s, '\0').as_ptr())
+ };
+}
+
+/// A literal UTF-16 wide string with a trailing null terminator.
+#[macro_export]
+macro_rules! w {
+ ($s:literal) => {{
+ const INPUT: &[u8] = $s.as_bytes();
+ const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1;
+ const OUTPUT: &[u16; OUTPUT_LEN] = {
+ let mut buffer = [0; OUTPUT_LEN];
+ let mut input_pos = 0;
+ let mut output_pos = 0;
+ while let Some((mut code_point, new_pos)) = $crate::decode_utf8_char(INPUT, input_pos) {
+ input_pos = new_pos;
+ if code_point <= 0xffff {
+ buffer[output_pos] = code_point as u16;
+ output_pos += 1;
+ } else {
+ code_point -= 0x10000;
+ buffer[output_pos] = 0xd800 + (code_point >> 10) as u16;
+ output_pos += 1;
+ buffer[output_pos] = 0xdc00 + (code_point & 0x3ff) as u16;
+ output_pos += 1;
+ }
+ }
+ &{ buffer }
+ };
+ $crate::PCWSTR::from_raw(OUTPUT.as_ptr())
+ }};
+}
+
+/// A literal HSTRING, length-prefixed wide string with a trailing null terminator.
+#[macro_export]
+macro_rules! h {
+ ($s:literal) => {{
+ const INPUT: &[u8] = $s.as_bytes();
+ const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1;
+ static RESULT: $crate::HSTRING = {
+ if OUTPUT_LEN == 1 {
+ unsafe { ::core::mem::transmute(::core::ptr::null::<u16>()) }
+ } else {
+ const OUTPUT: $crate::PCWSTR = $crate::w!($s);
+ const HEADER: $crate::HSTRING_HEADER = $crate::HSTRING_HEADER {
+ flags: 0x11,
+ len: (OUTPUT_LEN - 1) as u32,
+ padding1: 0,
+ padding2: 0,
+ ptr: OUTPUT.as_ptr(),
+ padding3: 0,
+ padding4: 0,
+ };
+ // SAFETY: an `HSTRING` is exactly equivalent to a pointer to an `HSTRING_HEADER`
+ unsafe {
+ ::core::mem::transmute::<&$crate::HSTRING_HEADER, $crate::HSTRING>(&HEADER)
+ }
+ }
+ };
+ &RESULT
+ }};
+}
+
+#[doc(hidden)]
+pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usize)> {
+ if bytes.len() == pos {
+ return None;
+ }
+ let ch = bytes[pos] as u32;
+ pos += 1;
+ if ch <= 0x7f {
+ return Some((ch, pos));
+ }
+ if (ch & 0xe0) == 0xc0 {
+ if bytes.len() - pos < 1 {
+ return None;
+ }
+ let ch2 = bytes[pos] as u32;
+ pos += 1;
+ if (ch2 & 0xc0) != 0x80 {
+ return None;
+ }
+ let result: u32 = ((ch & 0x1f) << 6) | (ch2 & 0x3f);
+ if result <= 0x7f {
+ return None;
+ }
+ return Some((result, pos));
+ }
+ if (ch & 0xf0) == 0xe0 {
+ if bytes.len() - pos < 2 {
+ return None;
+ }
+ let ch2 = bytes[pos] as u32;
+ pos += 1;
+ let ch3 = bytes[pos] as u32;
+ pos += 1;
+ if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 {
+ return None;
+ }
+ let result = ((ch & 0x0f) << 12) | ((ch2 & 0x3f) << 6) | (ch3 & 0x3f);
+ if result <= 0x7ff || (0xd800 <= result && result <= 0xdfff) {
+ return None;
+ }
+ return Some((result, pos));
+ }
+ if (ch & 0xf8) == 0xf0 {
+ if bytes.len() - pos < 3 {
+ return None;
+ }
+ let ch2 = bytes[pos] as u32;
+ pos += 1;
+ let ch3 = bytes[pos] as u32;
+ pos += 1;
+ let ch4 = bytes[pos] as u32;
+ pos += 1;
+ if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 || (ch4 & 0xc0) != 0x80 {
+ return None;
+ }
+ let result =
+ ((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f);
+ if result <= 0xffff || 0x10ffff < result {
+ return None;
+ }
+ return Some((result, pos));
+ }
+ None
+}
+
+#[doc(hidden)]
+#[repr(C)]
+pub struct HSTRING_HEADER {
+ pub flags: u32,
+ pub len: u32,
+ pub padding1: u32,
+ pub padding2: u32,
+ pub ptr: *const u16,
+ pub padding3: i32,
+ pub padding4: u16,
+}
+
+#[doc(hidden)]
+pub const fn utf16_len(bytes: &[u8]) -> usize {
+ let mut pos = 0;
+ let mut len = 0;
+ while let Some((code_point, new_pos)) = decode_utf8_char(bytes, pos) {
+ pos = new_pos;
+ len += if code_point <= 0xffff { 1 } else { 2 };
+ }
+ len
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test() {
+ assert_eq!(decode_utf8_char(b"123", 0), Some((0x31, 1)));
+ assert_eq!(decode_utf8_char(b"123", 1), Some((0x32, 2)));
+ assert_eq!(decode_utf8_char(b"123", 2), Some((0x33, 3)));
+ assert_eq!(decode_utf8_char(b"123", 3), None);
+ assert_eq!(utf16_len(b"123"), 3);
+ assert_eq!(utf16_len("α & ω".as_bytes()), 5);
+ }
+}
diff --git a/vendor/windows-strings/src/pcstr.rs b/vendor/windows-strings/src/pcstr.rs
new file mode 100644
index 00000000..cd752854
--- /dev/null
+++ b/vendor/windows-strings/src/pcstr.rs
@@ -0,0 +1,64 @@
+use super::*;
+
+/// A pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters.
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct PCSTR(pub *const u8);
+
+impl PCSTR {
+ /// Construct a new `PCSTR` from a raw pointer
+ pub const fn from_raw(ptr: *const u8) -> Self {
+ Self(ptr)
+ }
+
+ /// Construct a null `PCSTR`
+ pub const fn null() -> Self {
+ Self(core::ptr::null())
+ }
+
+ /// Returns a raw pointer to the `PCSTR`
+ pub const fn as_ptr(&self) -> *const u8 {
+ self.0
+ }
+
+ /// Checks whether the `PCSTR` is null
+ pub fn is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ /// String data without the trailing 0
+ ///
+ /// # Safety
+ ///
+ /// The `PCSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn as_bytes(&self) -> &[u8] {
+ unsafe {
+ let len = strlen(*self);
+ core::slice::from_raw_parts(self.0, len)
+ }
+ }
+
+ /// Copy the `PCSTR` into a Rust `String`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PCSTR::as_bytes`.
+ pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> {
+ unsafe { String::from_utf8(self.as_bytes().into()) }
+ }
+
+ /// Allow this string to be displayed.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PCSTR::as_bytes`.
+ pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
+ unsafe { Decode(move || decode_utf8(self.as_bytes())) }
+ }
+}
+
+impl Default for PCSTR {
+ fn default() -> Self {
+ Self::null()
+ }
+}
diff --git a/vendor/windows-strings/src/pcwstr.rs b/vendor/windows-strings/src/pcwstr.rs
new file mode 100644
index 00000000..221bfd9b
--- /dev/null
+++ b/vendor/windows-strings/src/pcwstr.rs
@@ -0,0 +1,97 @@
+use super::*;
+
+/// A pointer to a constant null-terminated string of 16-bit Unicode characters.
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct PCWSTR(pub *const u16);
+
+impl PCWSTR {
+ /// Construct a new `PCWSTR` from a raw pointer
+ pub const fn from_raw(ptr: *const u16) -> Self {
+ Self(ptr)
+ }
+
+ /// Construct a null `PCWSTR`
+ pub const fn null() -> Self {
+ Self(core::ptr::null())
+ }
+
+ /// Returns a raw pointer to the `PCWSTR`
+ pub const fn as_ptr(&self) -> *const u16 {
+ self.0
+ }
+
+ /// Checks whether the `PCWSTR` is null
+ pub fn is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ /// String length without the trailing 0
+ ///
+ /// # Safety
+ ///
+ /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn len(&self) -> usize {
+ extern "C" {
+ fn wcslen(s: *const u16) -> usize;
+ }
+ unsafe { wcslen(self.0) }
+ }
+
+ /// Returns `true` if the string length is zero, and `false` otherwise.
+ ///
+ /// # Safety
+ ///
+ /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn is_empty(&self) -> bool {
+ unsafe { self.len() == 0 }
+ }
+
+ /// String data without the trailing 0
+ ///
+ /// # Safety
+ ///
+ /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn as_wide(&self) -> &[u16] {
+ unsafe { core::slice::from_raw_parts(self.0, self.len()) }
+ }
+
+ /// Copy the `PCWSTR` into a Rust `String`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PCWSTR::as_wide`.
+ pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> {
+ unsafe { String::from_utf16(self.as_wide()) }
+ }
+
+ /// Copy the `PCWSTR` into an `HSTRING`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PCWSTR::as_wide`.
+ pub unsafe fn to_hstring(&self) -> HSTRING {
+ unsafe { HSTRING::from_wide(self.as_wide()) }
+ }
+
+ /// Allow this string to be displayed.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PCWSTR::as_wide`.
+ pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
+ unsafe { Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) }
+ }
+}
+
+impl Default for PCWSTR {
+ fn default() -> Self {
+ Self::null()
+ }
+}
+
+impl AsRef<PCWSTR> for PCWSTR {
+ fn as_ref(&self) -> &Self {
+ self
+ }
+}
diff --git a/vendor/windows-strings/src/pstr.rs b/vendor/windows-strings/src/pstr.rs
new file mode 100644
index 00000000..141d481b
--- /dev/null
+++ b/vendor/windows-strings/src/pstr.rs
@@ -0,0 +1,64 @@
+use super::*;
+
+/// A pointer to a null-terminated string of 8-bit Windows (ANSI) characters.
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct PSTR(pub *mut u8);
+
+impl PSTR {
+ /// Construct a new `PSTR` from a raw pointer
+ pub const fn from_raw(ptr: *mut u8) -> Self {
+ Self(ptr)
+ }
+
+ /// Construct a null `PSTR`
+ pub const fn null() -> Self {
+ Self(core::ptr::null_mut())
+ }
+
+ /// Returns a raw pointer to the `PSTR`
+ pub const fn as_ptr(&self) -> *mut u8 {
+ self.0
+ }
+
+ /// Checks whether the `PSTR` is null
+ pub fn is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ /// String data without the trailing 0
+ ///
+ /// # Safety
+ ///
+ /// The `PSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn as_bytes(&self) -> &[u8] {
+ unsafe {
+ let len = strlen(PCSTR::from_raw(self.0));
+ core::slice::from_raw_parts(self.0, len)
+ }
+ }
+
+ /// Copy the `PSTR` into a Rust `String`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PSTR::as_bytes`.
+ pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> {
+ unsafe { String::from_utf8(self.as_bytes().into()) }
+ }
+
+ /// Allow this string to be displayed.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PSTR::as_bytes`.
+ pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
+ unsafe { Decode(move || decode_utf8(self.as_bytes())) }
+ }
+}
+
+impl Default for PSTR {
+ fn default() -> Self {
+ Self::null()
+ }
+}
diff --git a/vendor/windows-strings/src/pwstr.rs b/vendor/windows-strings/src/pwstr.rs
new file mode 100644
index 00000000..db4d74ac
--- /dev/null
+++ b/vendor/windows-strings/src/pwstr.rs
@@ -0,0 +1,88 @@
+use super::*;
+
+/// A pointer to a null-terminated string of 16-bit Unicode characters.
+#[repr(transparent)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct PWSTR(pub *mut u16);
+
+impl PWSTR {
+ /// Construct a new `PWSTR` from a raw pointer.
+ pub const fn from_raw(ptr: *mut u16) -> Self {
+ Self(ptr)
+ }
+
+ /// Construct a null `PWSTR`.
+ pub const fn null() -> Self {
+ Self(core::ptr::null_mut())
+ }
+
+ /// Returns a raw pointer to the `PWSTR`.
+ pub const fn as_ptr(&self) -> *mut u16 {
+ self.0
+ }
+
+ /// Checks whether the `PWSTR` is null.
+ pub fn is_null(&self) -> bool {
+ self.0.is_null()
+ }
+
+ /// String length without the trailing 0
+ ///
+ /// # Safety
+ ///
+ /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn len(&self) -> usize {
+ unsafe { PCWSTR(self.0).len() }
+ }
+
+ /// Returns `true` if the string length is zero, and `false` otherwise.
+ ///
+ /// # Safety
+ ///
+ /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn is_empty(&self) -> bool {
+ unsafe { self.len() == 0 }
+ }
+
+ /// String data without the trailing 0.
+ ///
+ /// # Safety
+ ///
+ /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
+ pub unsafe fn as_wide(&self) -> &[u16] {
+ unsafe { core::slice::from_raw_parts(self.0, self.len()) }
+ }
+
+ /// Copy the `PWSTR` into a Rust `String`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PWSTR::as_wide`.
+ pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> {
+ unsafe { String::from_utf16(self.as_wide()) }
+ }
+
+ /// Copy the `PWSTR` into an `HSTRING`.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PWSTR::as_wide`.
+ pub unsafe fn to_hstring(&self) -> HSTRING {
+ unsafe { HSTRING::from_wide(self.as_wide()) }
+ }
+
+ /// Allow this string to be displayed.
+ ///
+ /// # Safety
+ ///
+ /// See the safety information for `PWSTR::as_wide`.
+ pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
+ unsafe { Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) }
+ }
+}
+
+impl Default for PWSTR {
+ fn default() -> Self {
+ Self::null()
+ }
+}
diff --git a/vendor/windows-strings/src/ref_count.rs b/vendor/windows-strings/src/ref_count.rs
new file mode 100644
index 00000000..c6309f9f
--- /dev/null
+++ b/vendor/windows-strings/src/ref_count.rs
@@ -0,0 +1,27 @@
+use core::sync::atomic::{fence, AtomicI32, Ordering};
+
+#[repr(transparent)]
+#[derive(Default)]
+pub struct RefCount(pub(crate) AtomicI32);
+
+impl RefCount {
+ pub fn new(count: u32) -> Self {
+ Self(AtomicI32::new(count as i32))
+ }
+
+ pub fn add_ref(&self) -> u32 {
+ (self.0.fetch_add(1, Ordering::Relaxed) + 1) as u32
+ }
+
+ pub fn release(&self) -> u32 {
+ let remaining = self.0.fetch_sub(1, Ordering::Release) - 1;
+
+ match remaining.cmp(&0) {
+ core::cmp::Ordering::Equal => fence(Ordering::Acquire),
+ core::cmp::Ordering::Less => panic!("Object has been over-released."),
+ core::cmp::Ordering::Greater => {}
+ }
+
+ remaining as u32
+ }
+}