From e3fc06afd790b0fab3d31e6a81d75ccc0d7bb1e9 Mon Sep 17 00:00:00 2001 From: Egor Tensin Date: Sun, 4 Oct 2020 10:50:19 +0300 Subject: add string conversion functions + some tests --- src/convert.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/convert.cpp (limited to 'src') diff --git a/src/convert.cpp b/src/convert.cpp new file mode 100644 index 0000000..6f4f400 --- /dev/null +++ b/src/convert.cpp @@ -0,0 +1,101 @@ +// 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()}; +} + +} -- cgit v1.2.3