windows_strings/
literals.rs1#[macro_export]
3macro_rules! s {
4 ($s:literal) => {
5 $crate::PCSTR::from_raw(::core::concat!($s, '\0').as_ptr())
6 };
7}
8
9#[macro_export]
11macro_rules! w {
12 ($s:literal) => {{
13 const INPUT: &[u8] = $s.as_bytes();
14 const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1;
15 const OUTPUT: &[u16; OUTPUT_LEN] = {
16 let mut buffer = [0; OUTPUT_LEN];
17 let mut input_pos = 0;
18 let mut output_pos = 0;
19 while let Some((mut code_point, new_pos)) = $crate::decode_utf8_char(INPUT, input_pos) {
20 input_pos = new_pos;
21 if code_point <= 0xffff {
22 buffer[output_pos] = code_point as u16;
23 output_pos += 1;
24 } else {
25 code_point -= 0x10000;
26 buffer[output_pos] = 0xd800 + (code_point >> 10) as u16;
27 output_pos += 1;
28 buffer[output_pos] = 0xdc00 + (code_point & 0x3ff) as u16;
29 output_pos += 1;
30 }
31 }
32 &{ buffer }
33 };
34 $crate::PCWSTR::from_raw(OUTPUT.as_ptr())
35 }};
36}
37
38#[macro_export]
40macro_rules! h {
41 ($s:literal) => {{
42 const INPUT: &[u8] = $s.as_bytes();
43 const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1;
44 #[allow(clippy::declare_interior_mutable_const)]
45 const RESULT: $crate::HSTRING = {
46 if OUTPUT_LEN == 1 {
47 unsafe { ::core::mem::transmute(::core::ptr::null::<u16>()) }
48 } else {
49 const OUTPUT: $crate::PCWSTR = $crate::w!($s);
50 const HEADER: $crate::HSTRING_HEADER = $crate::HSTRING_HEADER {
51 flags: 0x11,
52 len: (OUTPUT_LEN - 1) as u32,
53 padding1: 0,
54 padding2: 0,
55 ptr: OUTPUT.as_ptr(),
56 };
57 unsafe {
59 ::core::mem::transmute::<&$crate::HSTRING_HEADER, $crate::HSTRING>(&HEADER)
60 }
61 }
62 };
63 #[allow(clippy::borrow_interior_mutable_const)]
64 &RESULT
65 }};
66}
67
68#[doc(hidden)]
69pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usize)> {
70 if bytes.len() == pos {
71 return None;
72 }
73 let ch = bytes[pos] as u32;
74 pos += 1;
75 if ch <= 0x7f {
76 return Some((ch, pos));
77 }
78 if (ch & 0xe0) == 0xc0 {
79 if bytes.len() - pos < 1 {
80 return None;
81 }
82 let ch2 = bytes[pos] as u32;
83 pos += 1;
84 if (ch2 & 0xc0) != 0x80 {
85 return None;
86 }
87 let result: u32 = ((ch & 0x1f) << 6) | (ch2 & 0x3f);
88 if result <= 0x7f {
89 return None;
90 }
91 return Some((result, pos));
92 }
93 if (ch & 0xf0) == 0xe0 {
94 if bytes.len() - pos < 2 {
95 return None;
96 }
97 let ch2 = bytes[pos] as u32;
98 pos += 1;
99 let ch3 = bytes[pos] as u32;
100 pos += 1;
101 if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 {
102 return None;
103 }
104 let result = ((ch & 0x0f) << 12) | ((ch2 & 0x3f) << 6) | (ch3 & 0x3f);
105 if result <= 0x7ff || (0xd800 <= result && result <= 0xdfff) {
106 return None;
107 }
108 return Some((result, pos));
109 }
110 if (ch & 0xf8) == 0xf0 {
111 if bytes.len() - pos < 3 {
112 return None;
113 }
114 let ch2 = bytes[pos] as u32;
115 pos += 1;
116 let ch3 = bytes[pos] as u32;
117 pos += 1;
118 let ch4 = bytes[pos] as u32;
119 pos += 1;
120 if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 || (ch4 & 0xc0) != 0x80 {
121 return None;
122 }
123 let result =
124 ((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f);
125 if result <= 0xffff || 0x10ffff < result {
126 return None;
127 }
128 return Some((result, pos));
129 }
130 None
131}
132
133#[doc(hidden)]
134#[repr(C)]
135pub struct HSTRING_HEADER {
136 pub flags: u32,
137 pub len: u32,
138 pub padding1: u32,
139 pub padding2: u32,
140 pub ptr: *const u16,
141}
142
143#[doc(hidden)]
144pub const fn utf16_len(bytes: &[u8]) -> usize {
145 let mut pos = 0;
146 let mut len = 0;
147 while let Some((code_point, new_pos)) = decode_utf8_char(bytes, pos) {
148 pos = new_pos;
149 len += if code_point <= 0xffff { 1 } else { 2 };
150 }
151 len
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test() {
160 assert_eq!(decode_utf8_char(b"123", 0), Some((0x31, 1)));
161 assert_eq!(decode_utf8_char(b"123", 1), Some((0x32, 2)));
162 assert_eq!(decode_utf8_char(b"123", 2), Some((0x33, 3)));
163 assert_eq!(decode_utf8_char(b"123", 3), None);
164 assert_eq!(utf16_len(b"123"), 3);
165 assert_eq!(utf16_len("α & ω".as_bytes()), 5);
166 }
167}