diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2020-10-04 10:50:19 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2020-10-04 10:50:19 +0300 |
commit | e3fc06afd790b0fab3d31e6a81d75ccc0d7bb1e9 (patch) | |
tree | 4189a9241f7463a2bd51c16071a878f5319a18e3 /src/convert.cpp | |
parent | initial commit (diff) | |
download | winapi-utf8-e3fc06afd790b0fab3d31e6a81d75ccc0d7bb1e9.tar.gz winapi-utf8-e3fc06afd790b0fab3d31e6a81d75ccc0d7bb1e9.zip |
add string conversion functions + some tests
Diffstat (limited to 'src/convert.cpp')
-rw-r--r-- | src/convert.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
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 <Egor.Tensin@gmail.com> +// 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 <winapi/utf8.hpp> + +#include <windows.h> + +#include <cstddef> +#include <sstream> +#include <stdexcept> +#include <string> +#include <vector> + +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<unsigned char>& 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<const char*>(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<wchar_t> 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<unsigned char>& 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<const wchar_t*>(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<char> 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()}; +} + +} |