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 static RESULT: $crate::HSTRING = {
45 if OUTPUT_LEN == 1 {
46 unsafe { ::core::mem::transmute(::core::ptr::null::<u16>()) }
47 } else {
48 #[repr(C)]
49 struct HSTRING_HEADER {
50 flags: u32,
51 len: u32,
52 padding1: u32,
53 padding2: u32,
54 ptr: *const u16,
55 padding3: i32,
56 padding4: u16,
57 }
58 const OUTPUT: $crate::PCWSTR = $crate::w!($s);
59 const HEADER: HSTRING_HEADER = HSTRING_HEADER {
60 flags: 0x11,
61 len: (OUTPUT_LEN - 1) as u32,
62 padding1: 0,
63 padding2: 0,
64 ptr: OUTPUT.as_ptr(),
65 padding3: 0,
66 padding4: 0,
67 };
68 unsafe { ::core::mem::transmute::<&HSTRING_HEADER, $crate::HSTRING>(&HEADER) }
70 }
71 };
72 &RESULT
73 }};
74}
75
76#[doc(hidden)]
77pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usize)> {
78 if bytes.len() == pos {
79 return None;
80 }
81 let ch = bytes[pos] as u32;
82 pos += 1;
83 if ch <= 0x7f {
84 return Some((ch, pos));
85 }
86 if (ch & 0xe0) == 0xc0 {
87 if bytes.len() - pos < 1 {
88 return None;
89 }
90 let ch2 = bytes[pos] as u32;
91 pos += 1;
92 if (ch2 & 0xc0) != 0x80 {
93 return None;
94 }
95 let result: u32 = ((ch & 0x1f) << 6) | (ch2 & 0x3f);
96 if result <= 0x7f {
97 return None;
98 }
99 return Some((result, pos));
100 }
101 if (ch & 0xf0) == 0xe0 {
102 if bytes.len() - pos < 2 {
103 return None;
104 }
105 let ch2 = bytes[pos] as u32;
106 pos += 1;
107 let ch3 = bytes[pos] as u32;
108 pos += 1;
109 if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 {
110 return None;
111 }
112 let result = ((ch & 0x0f) << 12) | ((ch2 & 0x3f) << 6) | (ch3 & 0x3f);
113 if result <= 0x7ff || (0xd800 <= result && result <= 0xdfff) {
114 return None;
115 }
116 return Some((result, pos));
117 }
118 if (ch & 0xf8) == 0xf0 {
119 if bytes.len() - pos < 3 {
120 return None;
121 }
122 let ch2 = bytes[pos] as u32;
123 pos += 1;
124 let ch3 = bytes[pos] as u32;
125 pos += 1;
126 let ch4 = bytes[pos] as u32;
127 pos += 1;
128 if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 || (ch4 & 0xc0) != 0x80 {
129 return None;
130 }
131 let result =
132 ((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f);
133 if result <= 0xffff || 0x10ffff < result {
134 return None;
135 }
136 return Some((result, pos));
137 }
138 None
139}
140
141#[doc(hidden)]
142pub const fn utf16_len(bytes: &[u8]) -> usize {
143 let mut pos = 0;
144 let mut len = 0;
145 while let Some((code_point, new_pos)) = decode_utf8_char(bytes, pos) {
146 pos = new_pos;
147 len += if code_point <= 0xffff { 1 } else { 2 };
148 }
149 len
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test() {
158 assert_eq!(decode_utf8_char(b"123", 0), Some((0x31, 1)));
159 assert_eq!(decode_utf8_char(b"123", 1), Some((0x32, 2)));
160 assert_eq!(decode_utf8_char(b"123", 2), Some((0x33, 3)));
161 assert_eq!(decode_utf8_char(b"123", 3), None);
162 assert_eq!(utf16_len(b"123"), 3);
163 assert_eq!(utf16_len("α & ω".as_bytes()), 5);
164 }
165}