blob: 62a118f569fea4c9f7aa0625507e1b4324f852e8 [file] [log] [blame]
Elliott Hughesc1fd4922015-11-11 18:02:29 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <windows.h>
18
19#include "base/utf8.h"
20
21#include <fcntl.h>
22
23#include <string>
24
25#include "base/logging.h"
26
27namespace android {
28namespace base {
29
30bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
31 utf8->clear();
32
33 if (size == 0) {
34 return true;
35 }
36
37 // TODO: Consider using std::wstring_convert once libcxx is supported on
38 // Windows.
39
40 // Only Vista or later has this flag that causes WideCharToMultiByte() to
41 // return an error on invalid characters.
42 const DWORD flags =
43#if (WINVER >= 0x0600)
44 WC_ERR_INVALID_CHARS;
45#else
46 0;
47#endif
48
49 const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
50 NULL, 0, NULL, NULL);
51 if (chars_required <= 0) {
52 return false;
53 }
54
55 // This could potentially throw a std::bad_alloc exception.
56 utf8->resize(chars_required);
57
58 const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
59 &(*utf8)[0], chars_required, NULL,
60 NULL);
61 if (result != chars_required) {
62 CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
63 << " chars to buffer of " << chars_required << " chars";
64 utf8->clear();
65 return false;
66 }
67
68 return true;
69}
70
71bool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
72 // Compute string length of NULL-terminated string with wcslen().
73 return WideToUTF8(utf16, wcslen(utf16), utf8);
74}
75
76bool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
77 // Use the stored length of the string which allows embedded NULL characters
78 // to be converted.
79 return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
80}
81
82// Internal helper function that takes MultiByteToWideChar() flags.
83static bool _UTF8ToWideWithFlags(const char* utf8, const size_t size,
84 std::wstring* utf16, const DWORD flags) {
85 utf16->clear();
86
87 if (size == 0) {
88 return true;
89 }
90
91 // TODO: Consider using std::wstring_convert once libcxx is supported on
92 // Windows.
93 const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
94 NULL, 0);
95 if (chars_required <= 0) {
96 return false;
97 }
98
99 // This could potentially throw a std::bad_alloc exception.
100 utf16->resize(chars_required);
101
102 const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
103 &(*utf16)[0], chars_required);
104 if (result != chars_required) {
105 CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
106 << " chars to buffer of " << chars_required << " chars";
107 utf16->clear();
108 return false;
109 }
110
111 return true;
112}
113
114bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
115 // If strictly interpreting as UTF-8 succeeds, return success.
116 if (_UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
117 return true;
118 }
119
120 // Fallback to non-strict interpretation, allowing invalid characters and
121 // converting as best as possible, and return false to signify a problem.
122 (void)_UTF8ToWideWithFlags(utf8, size, utf16, 0);
123 return false;
124}
125
126bool UTF8ToWide(const char* utf8, std::wstring* utf16) {
127 // Compute string length of NULL-terminated string with strlen().
128 return UTF8ToWide(utf8, strlen(utf8), utf16);
129}
130
131bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
132 // Use the stored length of the string which allows embedded NULL characters
133 // to be converted.
134 return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
135}
136
137// Versions of standard library APIs that support UTF-8 strings.
138namespace utf8 {
139
140int open(const char* name, int flags, ...) {
141 std::wstring name_utf16;
142 if (!UTF8ToWide(name, &name_utf16)) {
143 errno = EINVAL;
144 return -1;
145 }
146
147 int mode = 0;
148 if ((flags & O_CREAT) != 0) {
149 va_list args;
150 va_start(args, flags);
151 mode = va_arg(args, int);
152 va_end(args);
153 }
154
155 return _wopen(name_utf16.c_str(), flags, mode);
156}
157
158int unlink(const char* name) {
159 std::wstring name_utf16;
160 if (!UTF8ToWide(name, &name_utf16)) {
161 errno = EINVAL;
162 return -1;
163 }
164
165 return _wunlink(name_utf16.c_str());
166}
167
168} // namespace utf8
169} // namespace base
170} // namespace android