Skip to main content

winwrap/string/
mod.rs

1use crate::*;
2use crate::um::stringapiset::{wide_char_to_multi_byte, CodePage, WCFlags, multi_byte_to_wide_char, MBFlags};
3use std::cmp::Ordering;
4use std::ops;
5use std::string::FromUtf16Error;
6use winapi::ctypes::wchar_t;
7
8#[cfg(not(feature = "ansi"))]
9pub type TString = WString;
10
11#[cfg(not(feature = "ansi"))]
12pub type TStr = WStr;
13
14#[cfg(feature = "ansi")]
15pub type TString = AString;
16
17#[cfg(feature = "ansi")]
18pub type TStr = AString;
19
20#[allow(non_snake_case)]
21extern "C" {
22    pub fn wcslen(s: *const wchar_t) -> usize;
23
24    pub fn strlen(s: *const u8) -> usize;
25
26    pub fn wcsnlen(s: *const wchar_t, len: usize) -> usize;
27
28    pub fn strnlen(s: *const u8, len: usize) -> usize;
29}
30
31fn wide_char_to_multi_byte_wrap(
32    code_page: CodePage,
33    wc_flags: WCFlags,
34    x: &[u16],
35) -> OsResult<Vec<u8>> {
36    // get the required buffer size.
37    let l = wide_char_to_multi_byte(
38        code_page,
39        wc_flags,
40        x,
41        &mut [],
42        None,
43        None,
44    )?;
45    let mut ret: Vec<u8> = Vec::with_capacity(l);
46    unsafe {
47        ret.set_len(l);
48
49        let l2 = wide_char_to_multi_byte(
50            code_page,
51            wc_flags,
52            x,
53            ret.as_mut_slice(),
54            None,
55            None,
56        )?;
57        assert_eq!(l, l2);
58    }
59    Ok(ret)
60}
61
62fn multi_byte_to_wide_char_wrap(
63    code_page: CodePage,
64    mb_flags: MBFlags,
65    x: &[u8],
66) -> OsResult<Vec<u16>> {
67    let l = multi_byte_to_wide_char(
68        code_page,
69        mb_flags,
70        x,
71        &mut [],
72    )?;
73    let mut ret: Vec<u16> = Vec::with_capacity(l);
74    unsafe {
75        ret.set_len(l);
76
77        let l2 = multi_byte_to_wide_char(
78            code_page,
79            mb_flags,
80            x,
81            ret.as_mut_slice(),
82        )?;
83        assert_eq!(l, l2);
84    }
85    Ok(ret)
86}
87
88#[repr(C)]
89#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)]
90pub struct WString {
91    inner: Box<[wchar_t]>,
92}
93
94impl WString {
95    #[inline]
96    pub fn as_bytes_with_nul(&self) -> &[u16] { &self.inner }
97
98    #[inline]
99    pub fn as_bytes(&self) -> &[u16] { &self.as_bytes_with_nul()[..self.inner.len() - 1] }
100
101    #[inline]
102    pub fn as_u8_bytes_with_nul(&self) -> &[u8] {
103        unsafe { std::slice::from_raw_parts(self.inner.as_ptr() as *const u8, self.inner.len() * 2) }
104    }
105
106    #[inline]
107    pub fn as_u8_bytes(&self) -> &[u8] { &self.as_u8_bytes_with_nul()[..self.inner.len() - 2] }
108
109    #[inline]
110    pub fn as_c_str(&self) -> &WStr { &*self }
111
112    #[inline]
113    pub fn as_ptr(&self) -> *const u16 { self.inner.as_ptr() }
114
115    #[inline]
116    pub fn len(&self) -> usize { self.inner.len() }
117
118    pub fn to_string(&self) -> Result<String, FromUtf16Error> {
119        String::from_utf16(self.as_bytes())
120    }
121
122    pub fn to_string_lossy(&self) -> String { String::from_utf16_lossy(self.as_bytes()) }
123
124    #[inline]
125    pub fn new<T: Into<Vec<u16>>>(v: T) -> Self { Self::_new(v.into()) }
126
127    #[inline]
128    pub fn new_c<T: Into<Vec<u8>>>(v: T) -> Self { Self::_new2(v.into()) }
129
130    #[inline]
131    fn _new(mut v: Vec<u16>) -> Self {
132        unsafe {
133            let len = wcsnlen(v.as_ptr(), v.len());
134            if len == v.len() {
135                // append NULL.
136                v.reserve_exact(1);
137                v.push(0);
138            }
139            v.set_len(len + 1);
140            Self::new_nul_unchecked(v)
141        }
142    }
143
144    fn from_astr(x: &AStr) -> OsResult<Self> {
145        let wc = multi_byte_to_wide_char_wrap(
146            CodePage::ACP,
147            MBFlags::PRECOMPOSED | MBFlags::ERR_INVALID_CHARS,
148            x.to_bytes_with_nul(),
149        )?;
150        Ok(Self::_new(wc))
151    }
152
153    fn from_astr_lossy(x: &AStr) -> Self {
154        let wc = multi_byte_to_wide_char_wrap(
155            CodePage::ACP,
156            MBFlags::PRECOMPOSED,
157            x.to_bytes_with_nul(),
158        ).unwrap();
159        Self::_new(wc)
160    }
161
162    #[inline]
163    fn _new2(mut v: Vec<u8>) -> Self {
164        if v.len() & 1 == 1 { v.push(0); } // Make the length even.
165        unsafe {
166            let v = v.leak();
167            let x = Vec::from_raw_parts(v.as_ptr() as *mut u16, v.len() / 2, v.len() / 2);
168            Self::_new(x)
169        }
170    }
171
172    /// # Safety
173    /// `v` must be a null-terminated UNICODE string.
174    pub unsafe fn new_nul_unchecked(v: Vec<u16>) -> Self {
175        Self { inner: v.into_boxed_slice() }
176    }
177
178    /// # Safety
179    /// `ptr` must be a null-terminated UNICODE string.
180    pub unsafe fn from_raw(ptr: *mut wchar_t) -> Self {
181        let len = wcslen(ptr);
182        let slice = std::slice::from_raw_parts_mut(ptr, len as usize + 1);
183        Self { inner: Box::from_raw(slice) }
184    }
185
186    pub unsafe fn from_raw_s(ptr: *mut u16, len: usize) -> Self {
187        let v = Vec::from_raw_parts(ptr, len, len);
188        Self::_new(v)
189    }
190}
191
192impl ops::Deref for WString {
193    type Target = WStr;
194
195    fn deref(&self) -> &Self::Target {
196        unsafe { WStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
197    }
198}
199
200impl ops::Index<ops::RangeFull> for WString {
201    type Output = WStr;
202
203    #[inline]
204    fn index(&self, _: ops::RangeFull) -> &Self::Output {
205        self
206    }
207}
208
209impl From<&AStr> for WString {
210    /// Converts &AStr to WString. Panic if an input cannot be converted to WCHAR.
211    fn from(x: &AStr) -> Self {
212        let wc = multi_byte_to_wide_char_wrap(
213            CodePage::ACP,
214            MBFlags::PRECOMPOSED | MBFlags::ERR_INVALID_CHARS,
215            x.to_bytes_with_nul(),
216        ).unwrap();
217        Self::_new(wc)
218    }
219}
220
221impl From<AString> for WString {
222    /// Converts AString to WString. Panic if an input cannot be converted to WCHAR.
223    #[inline]
224    fn from(x: AString) -> Self { Self::from(x.as_c_str()) }
225}
226
227impl From<Vec<u16>> for WString {
228    fn from(x: Vec<u16>) -> Self { Self::_new(x) }
229}
230
231impl From<&str> for WString {
232    fn from(x: &str) -> Self { Self::_new(x.encode_utf16().collect()) }
233}
234
235impl Drop for WString {
236    fn drop(&mut self) {
237        unsafe {
238            *self.inner.as_mut_ptr() = 0;
239            std::mem::forget(self)
240        }
241    }
242}
243
244#[repr(C)]
245#[derive(Debug)]
246pub struct WStr {
247    inner: [wchar_t],
248}
249
250impl WStr {
251    #[inline]
252    pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u16]) -> &Self {
253        &*(bytes as *const [u16] as *const Self)
254    }
255
256    #[inline]
257    pub fn as_ptr(&self) -> *const wchar_t { self.inner.as_ptr() }
258
259    #[inline]
260    pub fn as_mut_ptr(&mut self) -> *mut wchar_t { self.inner.as_mut_ptr() }
261
262    #[inline]
263    pub fn len(&self) -> usize { self.inner.len() }
264
265    #[inline]
266    pub fn to_bytes_with_nul(&self) -> &[u16] { &self.inner }
267
268    pub fn to_bytes(&self) -> &[u16] {
269        let bytes = self.to_bytes_with_nul();
270        &bytes[..bytes.len() - 1]
271    }
272
273    #[inline]
274    pub fn to_u8_bytes_with_nul(&self) -> &[u8] {
275        unsafe { std::slice::from_raw_parts(self.inner.as_ptr() as *const u8, self.inner.len() * 2) }
276    }
277
278    pub fn to_u8_bytes(&self) -> &[u8] {
279        let bytes = self.to_u8_bytes_with_nul();
280        &bytes[..bytes.len() - 2]
281    }
282}
283
284impl PartialEq for WStr {
285    fn eq(&self, other: &Self) -> bool { self.to_bytes().eq(other.to_bytes()) }
286}
287
288impl Eq for WStr {}
289
290impl PartialOrd for WStr {
291    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
292        self.to_bytes().partial_cmp(&other.to_bytes())
293    }
294}
295
296impl Ord for WStr {
297    fn cmp(&self, other: &Self) -> Ordering {
298        self.to_bytes().cmp(&other.to_bytes())
299    }
300}
301
302/// ANSI string
303#[repr(C)]
304#[derive(Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)]
305pub struct AString {
306    inner: Box<[u8]>,
307}
308
309impl From<&str> for AString {
310    fn from(x: &str) -> Self {
311        // UTF8 -> UNICODE -> ANSI
312        let ws = WString::from(x);
313        AString::from(ws)
314    }
315}
316
317impl From<&WStr> for AString {
318    fn from(x: &WStr) -> Self {
319        let mb = wide_char_to_multi_byte_wrap(
320            CodePage::ACP,
321            WCFlags::empty(),
322            x.to_bytes_with_nul(),
323        ).unwrap();
324        Self::_new(mb)
325    }
326}
327
328impl From<WString> for AString {
329    /// Converts WString to AString. Panic if an input cannot be converted to CHAR.
330    fn from(x: WString) -> Self {
331        Self::from(x.as_c_str())
332    }
333}
334
335impl AString {
336    #[inline]
337    pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner }
338
339    #[inline]
340    pub fn as_bytes(&self) -> &[u8] { &self.as_bytes_with_nul()[..self.inner.len() - 1] }
341
342    #[inline]
343    pub fn as_c_str(&self) -> &AStr { &*self }
344
345    #[inline]
346    pub fn as_mut_c_str(&mut self) -> &mut AStr { &mut *self }
347
348    #[inline]
349    pub fn as_ptr(&self) -> *const u8 { self.inner.as_ptr() }
350
351    #[inline]
352    pub fn len(&self) -> usize { self.inner.len() }
353
354    pub fn to_string(&self) -> OsResult<String> {
355        // ANSI -> UNICODE -> UTF8
356        let x = WString::from_astr(self.as_c_str())?;
357        unsafe {
358            let mut mb = wide_char_to_multi_byte_wrap(
359                CodePage::UTF8,
360                WCFlags::ERR_INVALID_CHARS,
361                x.as_bytes_with_nul(),
362            )?;
363            mb.set_len(mb.len() - 1); // remove NULL
364            Ok(String::from_utf8_unchecked(mb))
365        }
366    }
367
368    pub fn to_string_lossy(&self) -> String {
369        // ANSI -> UNICODE -> UTF8
370        let x = WString::from_astr_lossy(self.as_c_str());
371        unsafe {
372            let mut mb = wide_char_to_multi_byte_wrap(
373                CodePage::UTF8,
374                WCFlags::empty(),
375                x.as_bytes_with_nul(),
376            ).unwrap();
377            mb.set_len(mb.len() - 1); // remove NULL
378            String::from_utf8_unchecked(mb)
379        }
380    }
381
382    #[inline]
383    pub fn new(v: Vec<u8>) -> Self { Self::_new(v.into()) }
384
385    /// Converts &str to AString without an encoding check.
386    ///
387    /// # Example
388    ///
389    /// ```no_run
390    /// use winapi::shared::minwindef::FARPROC;
391    /// use winwrap::OsResult;
392    /// use winwrap::string::*;
393    /// use winwrap::um::libloaderapi::{get_proc_address, load_library_w, ProcAddress};
394    ///
395    /// /// It is assumed that a function name does not contains any multi-byte character.
396    /// pub unsafe fn load_and_get_proc_address(dll_name: &str, func_name: &str) -> OsResult<FARPROC> {
397    ///    let m = load_library_w(&WString::from(dll_name))?;
398    ///    get_proc_address(&m, ProcAddress::ByName(&AString::from_str_unchecked(func_name)))
399    /// }
400    /// ```
401    pub unsafe fn from_str_unchecked(s: &str) -> Self {
402        Self::new(s.as_bytes().to_vec())
403    }
404
405    fn _new(mut v: Vec<u8>) -> Self {
406        unsafe {
407            let len = strnlen(v.as_ptr(), v.len());
408            if len == v.len() {
409                v.reserve_exact(1);
410                v.push(0);
411            }
412            v.set_len(len + 1);
413            Self::new_nul_unchecked(v)
414        }
415    }
416
417    /// # Safety
418    /// `v` must be a null-terminated ANSI string.
419    #[inline]
420    pub fn new_nul_unchecked(v: Vec<u8>) -> Self {
421        Self { inner: v.into_boxed_slice() }
422    }
423
424    /// # Safety
425    /// `ptr` must be a null-terminated ANSI string.
426    pub unsafe fn from_raw(ptr: *mut u8) -> Self {
427        let len = strlen(ptr);
428        let slice = std::slice::from_raw_parts_mut(ptr, len as usize + 1);
429        Self { inner: Box::from_raw(slice) }
430    }
431
432    pub unsafe fn from_raw_s(ptr: *mut u8, len: usize) -> Self {
433        let v = Vec::from_raw_parts(ptr, len, len);
434        Self::_new(v)
435    }
436}
437
438impl ops::Deref for AString {
439    type Target = AStr;
440
441    fn deref(&self) -> &Self::Target {
442        unsafe { AStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
443    }
444}
445
446impl ops::DerefMut for AString {
447    fn deref_mut(&mut self) -> &mut Self::Target {
448        unsafe { AStr::from_bytes_with_nul_unchecked_mut(self.as_bytes_with_nul()) }
449    }
450}
451
452impl ops::Index<ops::RangeFull> for AString {
453    type Output = AStr;
454
455    #[inline]
456    fn index(&self, _: ops::RangeFull) -> &Self::Output {
457        self
458    }
459}
460
461impl From<Vec<u8>> for AString {
462    #[inline]
463    fn from(x: Vec<u8>) -> Self { Self::new(x) }
464}
465
466impl Drop for AString {
467    fn drop(&mut self) {
468        unsafe {
469            *self.inner.as_mut_ptr() = 0;
470            std::mem::forget(self)
471        }
472    }
473}
474
475#[repr(C)]
476#[derive(Debug)]
477pub struct AStr {
478    inner: [u8],
479}
480
481impl AStr {
482    #[inline]
483    pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self {
484        &*(bytes as *const [u8] as *const Self)
485    }
486
487    #[inline]
488    pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &[u8]) -> &mut Self {
489        &mut *(bytes as *const [u8] as *mut Self)
490    }
491
492    #[inline]
493    pub fn as_ptr(&self) -> *const i8 { self.inner.as_ptr() as *const i8 }
494
495    #[inline]
496    pub fn as_mut_ptr(&mut self) -> *mut i8 { self.inner.as_mut_ptr() as *mut i8 }
497
498    #[inline]
499    pub fn as_u8_ptr(&self) -> *const u8 { self.inner.as_ptr() }
500
501    #[inline]
502    pub fn as_mut_u8_ptr(&mut self) -> *mut u8 { self.inner.as_mut_ptr() }
503
504    #[inline]
505    pub fn len(&self) -> usize { self.inner.len() }
506
507    #[inline]
508    pub fn to_bytes_with_nul(&self) -> &[u8] { &self.inner }
509
510    #[inline]
511    pub fn to_bytes(&self) -> &[u8] {
512        let bytes = self.to_bytes_with_nul();
513        &bytes[..bytes.len() - 1]
514    }
515}
516
517impl PartialEq for AStr {
518    fn eq(&self, other: &Self) -> bool {
519        self.to_bytes().eq(other.to_bytes())
520    }
521}
522
523impl Eq for AStr {}
524
525impl PartialOrd for AStr {
526    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
527        self.to_bytes().partial_cmp(&other.to_bytes())
528    }
529}
530
531impl Ord for AStr {
532    fn cmp(&self, other: &Self) -> Ordering {
533        self.to_bytes().cmp(&other.to_bytes())
534    }
535}