Programming Tips #033:UTF-8 => Shift-JIS 変換
概要
きのうテキストビュワーのテストしてたら、文字化けするテキストファイルがあったので調べたら文字コードが UTF-8 だった。
そこで変換方法をググって見たが、なかなかそのものずばりのサイトが見つからなかった。
仕方がないから UTF-8 の仕様を調べて自分で作ってみた。
ファイルんの頭にシグネチャが無いタイプもあるらしいが、調べるのも大変なのでとりあえずシグネチャ付きのみ対応。
ソースコード
#include <windows.h> BOOL ConvUTF8( LPCTSTR path, LPCTSTR path2 ) { static const BYTE BOM[ 3 ] = { 0xEF, 0xBB, 0xBF }; BOOL result = FALSE; HANDLE hFile = CreateFile( path, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); HANDLE hFile2; DWORD dwRead, dwWrite; char buffer [ 3 + 1 ]; wchar_t buffer2[ 3 + 1 ]; INT n; if ( hFile != INVALID_HANDLE_VALUE ) { if ( ReadFile( hFile, buffer, sizeof BOM, & dwRead, NULL ) && dwRead == sizeof BOM && memcmp( buffer, BOM, sizeof BOM ) == 0 ) { hFile2 = CreateFile( path2, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile2 != INVALID_HANDLE_VALUE ) { for ( ;; ) { if ( ! ReadFile( hFile, buffer, 1, & dwRead, NULL ) || dwRead == 0 ) { break; } else if ( ( buffer[ 0 ] & 0xF0 ) == 0xE0 ) { n = 3; ReadFile( hFile, & buffer[ 1 ], 2, & dwRead, NULL ); } else if ( ( buffer[ 0 ] & 0xE0 ) == 0xC0 ) { n = 2; ReadFile( hFile, & buffer[ 1 ], 1, & dwRead, NULL ); } else { n = 1; } n = MultiByteToWideChar( CP_UTF8, 0, buffer, n, buffer2, sizeof ( wchar_t ) * ( n + 1 ) ); if ( n > 0 ) { n = WideCharToMultiByte( CP_ACP, 0, buffer2, n, buffer, sizeof buffer, NULL, NULL ); if ( n > 0 ) { buffer[ n ] = '\0'; WriteFile( hFile2, buffer, n, & dwWrite, NULL ); } } } SetEndOfFile( hFile2 ); CloseHandle( hFile2 ); result = TRUE; } } CloseHandle( hFile ); } return result; }
解説
UTF-8 は1文字が1~3バイトになるらしい。
1バイト目で1文字が何バイトか調べたら MultiByteToWideChar() 関数でいったんワイド文字に変換する。
変換後のワイド文字を WideCharToMultiByte() 関数でマルチバイト文字に変換する。
これだけ。