そろそろWindowsでUTF-16とShift-JISの変換方法をC++erらしくまとめようか

Win32APIには御存知の通り``WideCharToMultiByte``関数と``MultiByteToWideChar``関数があるが、わりと使うのは面倒くさい。

そもそも当たり前だけど``std::basic_string<char_type>``使えないし。

というわけでメモ代わりにまとめておく。locale周りはガバのプーさんだけどそこは勘弁して下さい。

# 結論

これでいいかと。なんとなく``shrink_to_fit``呼んでるけどこれ必要なのかねぇ

```cpp
#include <string>
#include <windows.h>
#include <cstring>
std::wstring shift_jis_to_utf_16(const std::string& str)
{
	static_assert(sizeof(wchar_t) == 2, "this function is windows only");
	const int len = ::MultiByteToWideChar(932/*CP_ACP*/, 0, str.c_str(), -1, nullptr, 0);
	std::wstring re(len * 2 + 2, L'\0');
	if (!::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &re[0], len)) {
		const auto ec = ::GetLastError();
		switch (ec)
		{
		case ERROR_INSUFFICIENT_BUFFER:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INSUFFICIENT_BUFFER"); break;
		case ERROR_INVALID_FLAGS:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_FLAGS"); break;
		case ERROR_INVALID_PARAMETER:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_PARAMETER"); break;
		case ERROR_NO_UNICODE_TRANSLATION:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_NO_UNICODE_TRANSLATION"); break;
		default:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: unknown(" + std::to_string(ec) + ')'); break;
		}
	}
	const std::size_t real_len = std::wcslen(re.c_str());
	re.resize(real_len);
	re.shrink_to_fit();
	return re;
}
std::string utf_16_to_shift_jis(const std::wstring& str) {
	static_assert(sizeof(wchar_t) == 2, "this function is windows only");
	const int len = ::WideCharToMultiByte(932/*CP_ACP*/, 0, str.c_str(), -1, nullptr, 0, nullptr, nullptr);
	std::string re(len * 2, '\0');
	if (!::WideCharToMultiByte(CP_ACP, 0, str.c_str(), -1, &re[0], len, nullptr, nullptr)) {
		const auto ec = ::GetLastError();
		switch (ec)
		{
		case ERROR_INSUFFICIENT_BUFFER:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INSUFFICIENT_BUFFER"); break;
		case ERROR_INVALID_FLAGS:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_FLAGS"); break;
		case ERROR_INVALID_PARAMETER:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: ERROR_INVALID_PARAMETER"); break;
		default:
			throw std::runtime_error("in function utf_16_to_shift_jis, WideCharToMultiByte fail. cause: unknown(" + std::to_string(ec) + ')'); break;
		}
	}
	const std::size_t real_len = std::strlen(re.c_str());
	re.resize(real_len);
	re.shrink_to_fit();
	return re;
}

```

# 雑記
``CP_ACP``ってところを変えればいろいろ出来たりする。例えば``ISO_8859_1``なら西ヨーロッパ言語  - iso-8859-1からutf-16への変換ができる。
cf.)

- https://channel9.msdn.com/Forums/TechOff/184894-WIN32-Text-Encoding-APIs/ebf597d0472b441e819e9dea013dba85
- https://msdn.microsoft.com/ja-jp/library/aa288104%28v=vs.71%29.aspx

あと、WideCharToMultiByte関数は第二引数に``WC_NO_BEST_FIT_CHARS``を指定せずに呼ぶと似た文字への変換が発生するらしい。
cf.)

- http://d.hatena.ne.jp/hasegawayosuke/20060209#1139475064
- https://msdn.microsoft.com/ja-jp/library/windows/desktop/dd374130%28v=vs.85%29.aspx

# 参考サイト

- [文字列取得バッファとしてのstd::string - yohhoyの日記](http://d.hatena.ne.jp/yohhoy/20130413/p1)
- [Visual C++でShift-JISをUTF-8に変換するコード - 今日もスミマセン。](http://d.hatena.ne.jp/snaka72/20090429/1241027781)
- [備忘録: C++で文字コード変換](http://bebolog.blogspot.jp/2014/11/c.html)

# 追記

ちょっと違うけど
http://qiita.com/AsladaGSX/items/af50066dbbfd59991af9
なんかすごい頑張っている記事を見つけました、