aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/convert.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/convert.cpp')
-rw-r--r--src/convert.cpp101
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()};
+}
+
+}