1 /* 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 "android-base/utf8.h" 20 21 #include <fcntl.h> 22 23 #include <string> 24 25 #include "android-base/logging.h" 26 27 namespace android { 28 namespace base { 29 30 // Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar(). 31 static void SetErrnoFromLastError() { 32 switch (GetLastError()) { 33 case ERROR_NO_UNICODE_TRANSLATION: 34 errno = EILSEQ; 35 break; 36 default: 37 errno = EINVAL; 38 break; 39 } 40 } 41 42 bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) { 43 utf8->clear(); 44 45 if (size == 0) { 46 return true; 47 } 48 49 // TODO: Consider using std::wstring_convert once libcxx is supported on 50 // Windows. 51 52 // Only Vista or later has this flag that causes WideCharToMultiByte() to 53 // return an error on invalid characters. 54 const DWORD flags = 55 #if (WINVER >= 0x0600) 56 WC_ERR_INVALID_CHARS; 57 #else 58 0; 59 #endif 60 61 const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size, 62 NULL, 0, NULL, NULL); 63 if (chars_required <= 0) { 64 SetErrnoFromLastError(); 65 return false; 66 } 67 68 // This could potentially throw a std::bad_alloc exception. 69 utf8->resize(chars_required); 70 71 const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size, 72 &(*utf8)[0], chars_required, NULL, 73 NULL); 74 if (result != chars_required) { 75 SetErrnoFromLastError(); 76 CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result 77 << " chars to buffer of " << chars_required << " chars"; 78 utf8->clear(); 79 return false; 80 } 81 82 return true; 83 } 84 85 bool WideToUTF8(const wchar_t* utf16, std::string* utf8) { 86 // Compute string length of NULL-terminated string with wcslen(). 87 return WideToUTF8(utf16, wcslen(utf16), utf8); 88 } 89 90 bool WideToUTF8(const std::wstring& utf16, std::string* utf8) { 91 // Use the stored length of the string which allows embedded NULL characters 92 // to be converted. 93 return WideToUTF8(utf16.c_str(), utf16.length(), utf8); 94 } 95 96 // Internal helper function that takes MultiByteToWideChar() flags. 97 static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16, 98 const DWORD flags) { 99 utf16->clear(); 100 101 if (size == 0) { 102 return true; 103 } 104 105 // TODO: Consider using std::wstring_convert once libcxx is supported on 106 // Windows. 107 const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size, 108 NULL, 0); 109 if (chars_required <= 0) { 110 SetErrnoFromLastError(); 111 return false; 112 } 113 114 // This could potentially throw a std::bad_alloc exception. 115 utf16->resize(chars_required); 116 117 const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size, 118 &(*utf16)[0], chars_required); 119 if (result != chars_required) { 120 SetErrnoFromLastError(); 121 CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result 122 << " chars to buffer of " << chars_required << " chars"; 123 utf16->clear(); 124 return false; 125 } 126 127 return true; 128 } 129 130 bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) { 131 // If strictly interpreting as UTF-8 succeeds, return success. 132 if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) { 133 return true; 134 } 135 136 const int saved_errno = errno; 137 138 // Fallback to non-strict interpretation, allowing invalid characters and 139 // converting as best as possible, and return false to signify a problem. 140 (void)UTF8ToWideWithFlags(utf8, size, utf16, 0); 141 errno = saved_errno; 142 return false; 143 } 144 145 bool UTF8ToWide(const char* utf8, std::wstring* utf16) { 146 // Compute string length of NULL-terminated string with strlen(). 147 return UTF8ToWide(utf8, strlen(utf8), utf16); 148 } 149 150 bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) { 151 // Use the stored length of the string which allows embedded NULL characters 152 // to be converted. 153 return UTF8ToWide(utf8.c_str(), utf8.length(), utf16); 154 } 155 156 // Versions of standard library APIs that support UTF-8 strings. 157 namespace utf8 { 158 159 int open(const char* name, int flags, ...) { 160 std::wstring name_utf16; 161 if (!UTF8ToWide(name, &name_utf16)) { 162 return -1; 163 } 164 165 int mode = 0; 166 if ((flags & O_CREAT) != 0) { 167 va_list args; 168 va_start(args, flags); 169 mode = va_arg(args, int); 170 va_end(args); 171 } 172 173 return _wopen(name_utf16.c_str(), flags, mode); 174 } 175 176 int unlink(const char* name) { 177 std::wstring name_utf16; 178 if (!UTF8ToWide(name, &name_utf16)) { 179 return -1; 180 } 181 182 return _wunlink(name_utf16.c_str()); 183 } 184 185 } // namespace utf8 186 } // namespace base 187 } // namespace android 188