1 | module builtin |
2 | |
3 | import strings |
4 | |
5 | const cp_utf8 = 65001 |
6 | |
7 | // to_wide returns a pointer to an UTF-16 version of the string receiver. |
8 | // In V, strings are encoded using UTF-8 internally, but on windows most APIs, |
9 | // that accept strings, need them to be in UTF-16 encoding. |
10 | // The returned pointer of .to_wide(), has a type of &u16, and is suitable |
11 | // for passing to Windows APIs that expect LPWSTR or wchar_t* parameters. |
12 | // See also MultiByteToWideChar ( https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar ) |
13 | // See also builtin.wchar.from_string/1, for a version, that produces a |
14 | // platform dependant L"" C style wchar_t* wide string. |
15 | pub fn (_str string) to_wide() &u16 { |
16 | $if windows { |
17 | unsafe { |
18 | num_chars := (C.MultiByteToWideChar(cp_utf8, 0, &char(_str.str), _str.len, |
19 | 0, 0)) |
20 | mut wstr := &u16(malloc_noscan((num_chars + 1) * 2)) // sizeof(wchar_t) |
21 | if wstr != 0 { |
22 | C.MultiByteToWideChar(cp_utf8, 0, &char(_str.str), _str.len, wstr, num_chars) |
23 | C.memset(&u8(wstr) + num_chars * 2, 0, 2) |
24 | } |
25 | return wstr |
26 | } |
27 | } $else { |
28 | srunes := _str.runes() |
29 | unsafe { |
30 | mut result := &u16(vcalloc_noscan((srunes.len + 1) * 2)) |
31 | for i, r in srunes { |
32 | result[i] = u16(r) |
33 | } |
34 | result[srunes.len] = 0 |
35 | return result |
36 | } |
37 | } |
38 | } |
39 | |
40 | // string_from_wide creates a V string, encoded in UTF-8, given a windows |
41 | // style string encoded in UTF-16. Note that this function first searches |
42 | // for the string terminator 0 character, and is thus slower, while more |
43 | // convenient compared to string_from_wide2/2 (you have to know the length |
44 | // in advance to use string_from_wide2/2). |
45 | // See also builtin.wchar.to_string/1, for a version that eases working with |
46 | // the platform dependent &wchar_t L"" strings. |
47 | [manualfree; unsafe] |
48 | pub fn string_from_wide(_wstr &u16) string { |
49 | $if windows { |
50 | unsafe { |
51 | wstr_len := C.wcslen(_wstr) |
52 | return string_from_wide2(_wstr, int(wstr_len)) |
53 | } |
54 | } $else { |
55 | mut i := 0 |
56 | for unsafe { _wstr[i] } != 0 { |
57 | i++ |
58 | } |
59 | return unsafe { string_from_wide2(_wstr, i) } |
60 | } |
61 | } |
62 | |
63 | // string_from_wide2 creates a V string, encoded in UTF-8, given a windows |
64 | // style string, encoded in UTF-16. It is more efficient, compared to |
65 | // string_from_wide, but it requires you to know the input string length, |
66 | // and to pass it as the second argument. |
67 | // See also builtin.wchar.to_string2/2, for a version that eases working |
68 | // with the platform dependent &wchar_t L"" strings. |
69 | [manualfree; unsafe] |
70 | pub fn string_from_wide2(_wstr &u16, len int) string { |
71 | $if windows { |
72 | unsafe { |
73 | num_chars := C.WideCharToMultiByte(cp_utf8, 0, _wstr, len, 0, 0, 0, 0) |
74 | mut str_to := malloc_noscan(num_chars + 1) |
75 | if str_to != 0 { |
76 | C.WideCharToMultiByte(cp_utf8, 0, _wstr, len, &char(str_to), num_chars, |
77 | 0, 0) |
78 | C.memset(str_to + num_chars, 0, 1) |
79 | } |
80 | return tos2(str_to) |
81 | } |
82 | } $else { |
83 | mut sb := strings.new_builder(len) |
84 | defer { |
85 | unsafe { sb.free() } |
86 | } |
87 | for i := 0; i < len; i++ { |
88 | u := unsafe { rune(_wstr[i]) } |
89 | sb.write_rune(u) |
90 | } |
91 | res := sb.str() |
92 | return res |
93 | } |
94 | } |