| // 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 "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 |