// Copyright (c) 2020 Egor Tensin // This file is part of the "winapi-utf8" project. // For details, see https://github.com/egor-tensin/winapi-utf8. // Distributed under the MIT License. #include #include #include #include #include #include #include namespace winapi { namespace { std::runtime_error error(const char* function, DWORD code) { std::ostringstream oss; oss << function << " failed with error code " << code; return std::runtime_error{oss.str()}; } } std::wstring widen(const std::string& src) { return widen(src.c_str(), src.size()); } std::wstring widen(const std::vector& src) { return widen(src.data(), src.size()); } std::wstring widen(const void* src, std::size_t in_nb) { const DWORD flags = MB_ERR_INVALID_CHARS | MB_PRECOMPOSED; const char* in_data = reinterpret_cast(src); auto out_nch = ::MultiByteToWideChar(CP_UTF8, flags, in_data, in_nb, NULL, 0); if (out_nch == 0) { throw error("MultiByteToWideChar", GetLastError()); } static_assert(sizeof(wchar_t) == sizeof(WCHAR), "wchar_t != WCHAR"); std::vector out; out.resize(out_nch); out_nch = ::MultiByteToWideChar(CP_UTF8, flags, in_data, in_nb, out.data(), out.size()); if (out_nch == 0) { throw error("MultiByteToWideChar", GetLastError()); } return {out.data(), out.size()}; } std::string narrow(const std::wstring& src) { static_assert(sizeof(std::wstring::value_type) == sizeof(WCHAR), "wchar_t != WCHAR"); return narrow(src.c_str(), src.size() * sizeof(std::wstring::value_type)); } std::string narrow(const std::vector& src) { return narrow(src.data(), src.size()); } std::string narrow(const void* src, std::size_t in_nb) { if (in_nb % sizeof(WCHAR) != 0) { std::ostringstream err_msg; err_msg << "narrow: invalid buffer size: " << in_nb; throw std::runtime_error{err_msg.str()}; } const std::size_t in_nch = in_nb / sizeof(WCHAR); const DWORD flags = WC_ERR_INVALID_CHARS | WC_NO_BEST_FIT_CHARS; const wchar_t* in_data = reinterpret_cast(src); auto out_nb = ::WideCharToMultiByte(CP_UTF8, flags, in_data, in_nch, NULL, 0, NULL, NULL); if (out_nb == 0) { throw error("WideCharToMultiByte", GetLastError()); } std::vector out; out.resize(out_nb); out_nb = ::WideCharToMultiByte(CP_UTF8, flags, in_data, in_nch, out.data(), out.size(), NULL, NULL); if (out_nb == 0) { throw error("WideCharToMultiByte", GetLastError()); } return {out.data(), out.size()}; } }