MASATOの開発日記


前の開発日記 次の開発日記 一覧

2002/05/04

最近はDirectX8のDirectGraphicsで遊んでいます。 DirectGraphicsは、DirectX7以前のDirect3Dが改良されたものみたいです。 (Direct3Dは扱ったことが無いので良く分かりません)
発端は、2Dのゲームを3Dライブラリを使って作ってみようと思い立ったことです。 2Dでしたら基本的には2D用のライブラリであるDirectDrawで良く、 DirectGraphicsのような3Dを扱うライブラリを使う必要は無いのですが、 絵の回転や半透明等を扱うようになると、DirectDrawでは少し荷が重たいのです。 DirectGraphicsならそこらへんはいとも簡単にこなせますので、 ここはDirectGraphicsを使ってみようと思いました。
まだライブラリの色々な機能を試している段階なので、これで実際にゲームを作るのは 当分先の話となるでしょう。

マルチバイト文字とワイド文字

MSDNのC標準関数を見ていますと、マルチバイト文字やらワイド文字といった表現が出てきます。 昔は、何が違うのかさっぱり分かりませんでしたが、最近ようやく何のことだか分かるようになりました。

マルチバイト文字とは、1文字が1バイト以上nバイト以下で構成されている文字です。 基本的には可変長です。例えば、Shift_JISは、1文字が1バイト以上2バイト以下です。よってマルチバイト文字です。 UTF-8は、1文字が1バイト以上6バイト以下です。よってこれもマルチバイト文字です。

それに対してワイド文字とは、1文字が1バイト以上の固定長で構成されている文字です。 例えば、Unicodeは、1文字が2バイトですので、ワイド文字です。 UTF-32も、1文字が4バイトですので、ワイド文字です。

ASCIIは1文字が1バイト以上1バイト以下であり、かつ1文字が1バイト固定長であるので、 これはマルチバイト文字かつワイド文字であるかどうかと言った細かい所までは分かりませんが、 VC++でマルチバイト文字と言ったら、Shift_JISやUTF-8のことであり、ワイド文字と言ったらUnicodeを指すと考えて それほど困りはしないと思います。

なお、UTF-8、UTF-16、UTF-32等を全てひっくるめてUnicodeという場合と、 サロゲートペアの無いリトルエンディアンのUTF-16を指してUnicodeと言う場合があるようです。 (UTF-16がUnicodeにサロゲートペアを追加した文字コードであるという方が正しいようです。) WindowsでUnicodeと言ったら一般には後者を指します。今回も後者の意味で使用しています。 今後、前者の意味で使用するときはUNICODEと大文字で記述することにします。分かり難いですが・・・

UTF-8からShift_JISへの変換

環境Visual C++ 6.0

マルチバイト文字からマルチバイト文字への変換方法です。 MultiByteToMultiByteという便利そうな関数は無いので、一旦Unicodeを経由して変換します。

変換関数UTF8ToShiftJISのコードは次のようになります。

BOOL UTF8ToShiftJIS(const CString& src, CString* dest)
{
  // ●UTF8からUnicodeに変換した場合の長さを求める。●
  int iWideLength = ::MultiByteToWideChar(CP_UTF8, 0, src, src.GetLength(), NULL, 0);
  if (iWideLength == 0)return FALSE;
  LPWSTR lpWideString = new WCHAR[iWideLength];
  int iLength;
  if (
    // ●UTF8からUnicodeに変換する。●
    (::MultiByteToWideChar(CP_UTF8, 0, src, src.GetLength(), lpWideString, iWideLength) == 0)
    // ●UnicodeからShift_JISに変換した場合の長さを求める。●
    || ((iLength = ::WideCharToMultiByte(CP_ACP, 0, lpWideString, iWideLength, NULL, 0, NULL, NULL)) == 0)
    // ●UnicodeからShift_JISに変換する。●
    || (::WideCharToMultiByte(CP_ACP, 0, lpWideString, iWideLength, dest->GetBuffer(iLength), iLength, NULL, NULL) == 0)){
    // ●変換に失敗●
    delete lpWideString;
    return FALSE;
  }
  // ●変換に成功●
  delete lpWideString;
  dest->ReleaseBuffer();
  return TRUE;
}

MultiByteToWideCharとWideCharToMultiByteの第一引数に注目して下さい。 CP_UTF8を用いてUnicodeに変換し、CP_ACPを用いてShiftJISに変換しています。

使い方の例を示します。utf8.txtは、UTF-8で書かれたテキストファイルだとします。

CFile file;
if (file.Open("utf8.txt", CFile::modeRead)){
  DWORD iLength = file.GetLength();
  CString src;
  file.Read(src.GetBuffer(iLength), iLength);
  file.Close();
  src.ReleaseBuffer(iLength);
  CString dest;
  UTF8ToShiftJIS(src, &dest);
  // ●この時点で、destにShift_JISに変換された文字列が格納されている。●
}

こちらは特に工夫はしていません。ファイルから読み込んだ文字列をUTF8ToShiftJISに渡しているだけです。

今回はMFCを使用しましたが、今回使用したものはWindowsAPIの MultiByteToWideCharとWideCharToMultiByteだけなので、MFCを使わないで UTF8ToShiftJISを実装しても大した違いは無いかと思われます。

前の開発日記 次の開発日記 一覧