|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/strings/sys_string_conversions.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  | #include <wchar.h> | 
|  |  | 
|  | #include "base/strings/string_piece.h" | 
|  | #include "base/strings/utf_string_conversions.h" | 
|  | #include "util/build_config.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | std::string SysWideToUTF8(const std::wstring& wide) { | 
|  | // In theory this should be using the system-provided conversion rather | 
|  | // than our ICU, but this will do for now. | 
|  | return WideToUTF8(wide); | 
|  | } | 
|  | std::wstring SysUTF8ToWide(StringPiece utf8) { | 
|  | // In theory this should be using the system-provided conversion rather | 
|  | // than our ICU, but this will do for now. | 
|  | std::wstring out; | 
|  | UTF8ToWide(utf8.data(), utf8.size(), &out); | 
|  | return out; | 
|  | } | 
|  |  | 
|  | #if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID) | 
|  | // TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb() | 
|  | // support and a better understanding of what calls these routines. | 
|  |  | 
|  | std::string SysWideToNativeMB(const std::wstring& wide) { | 
|  | return WideToUTF8(wide); | 
|  | } | 
|  |  | 
|  | std::wstring SysNativeMBToWide(StringPiece native_mb) { | 
|  | return SysUTF8ToWide(native_mb); | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | std::string SysWideToNativeMB(const std::wstring& wide) { | 
|  | mbstate_t ps; | 
|  |  | 
|  | // Calculate the number of multi-byte characters.  We walk through the string | 
|  | // without writing the output, counting the number of multi-byte characters. | 
|  | size_t num_out_chars = 0; | 
|  | memset(&ps, 0, sizeof(ps)); | 
|  | for (size_t i = 0; i < wide.size(); ++i) { | 
|  | const wchar_t src = wide[i]; | 
|  | // Use a temp buffer since calling wcrtomb with an output of NULL does not | 
|  | // calculate the output length. | 
|  | char buf[16]; | 
|  | // Skip NULLs to avoid wcrtomb's special handling of them. | 
|  | size_t res = src ? wcrtomb(buf, src, &ps) : 0; | 
|  | switch (res) { | 
|  | // Handle any errors and return an empty string. | 
|  | case static_cast<size_t>(-1): | 
|  | return std::string(); | 
|  | break; | 
|  | case 0: | 
|  | // We hit an embedded null byte, keep going. | 
|  | ++num_out_chars; | 
|  | break; | 
|  | default: | 
|  | num_out_chars += res; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (num_out_chars == 0) | 
|  | return std::string(); | 
|  |  | 
|  | std::string out; | 
|  | out.resize(num_out_chars); | 
|  |  | 
|  | // We walk the input string again, with |i| tracking the index of the | 
|  | // wide input, and |j| tracking the multi-byte output. | 
|  | memset(&ps, 0, sizeof(ps)); | 
|  | for (size_t i = 0, j = 0; i < wide.size(); ++i) { | 
|  | const wchar_t src = wide[i]; | 
|  | // We don't want wcrtomb to do its funkiness for embedded NULLs. | 
|  | size_t res = src ? wcrtomb(&out[j], src, &ps) : 0; | 
|  | switch (res) { | 
|  | // Handle any errors and return an empty string. | 
|  | case static_cast<size_t>(-1): | 
|  | return std::string(); | 
|  | break; | 
|  | case 0: | 
|  | // We hit an embedded null byte, keep going. | 
|  | ++j;  // Output is already zeroed. | 
|  | break; | 
|  | default: | 
|  | j += res; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return out; | 
|  | } | 
|  |  | 
|  | std::wstring SysNativeMBToWide(StringPiece native_mb) { | 
|  | mbstate_t ps; | 
|  |  | 
|  | // Calculate the number of wide characters.  We walk through the string | 
|  | // without writing the output, counting the number of wide characters. | 
|  | size_t num_out_chars = 0; | 
|  | memset(&ps, 0, sizeof(ps)); | 
|  | for (size_t i = 0; i < native_mb.size();) { | 
|  | const char* src = native_mb.data() + i; | 
|  | size_t res = mbrtowc(nullptr, src, native_mb.size() - i, &ps); | 
|  | switch (res) { | 
|  | // Handle any errors and return an empty string. | 
|  | case static_cast<size_t>(-2): | 
|  | case static_cast<size_t>(-1): | 
|  | return std::wstring(); | 
|  | break; | 
|  | case 0: | 
|  | // We hit an embedded null byte, keep going. | 
|  | i += 1; | 
|  | FALLTHROUGH; | 
|  | default: | 
|  | i += res; | 
|  | ++num_out_chars; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (num_out_chars == 0) | 
|  | return std::wstring(); | 
|  |  | 
|  | std::wstring out; | 
|  | out.resize(num_out_chars); | 
|  |  | 
|  | memset(&ps, 0, sizeof(ps));  // Clear the shift state. | 
|  | // We walk the input string again, with |i| tracking the index of the | 
|  | // multi-byte input, and |j| tracking the wide output. | 
|  | for (size_t i = 0, j = 0; i < native_mb.size(); ++j) { | 
|  | const char* src = native_mb.data() + i; | 
|  | wchar_t* dst = &out[j]; | 
|  | size_t res = mbrtowc(dst, src, native_mb.size() - i, &ps); | 
|  | switch (res) { | 
|  | // Handle any errors and return an empty string. | 
|  | case static_cast<size_t>(-2): | 
|  | case static_cast<size_t>(-1): | 
|  | return std::wstring(); | 
|  | break; | 
|  | case 0: | 
|  | i += 1;  // Skip null byte. | 
|  | break; | 
|  | default: | 
|  | i += res; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return out; | 
|  | } | 
|  |  | 
|  | #endif  // defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID) | 
|  |  | 
|  | }  // namespace base |