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