第1回: Unicode から Shift_JIS への変換(その1)

Windows 上で Unicode を扱う場合に発生するセキュリティ上の問題点などについて不定期に書いていくことにします。以前の内容と重なる部分も多いですし、時間的にもどこまで書けるかわかりませんけれど…。

さて第1回目は、 Windows 上で Unicode を扱う際のもっとも基本とも言える WideCharToMultiByte を使用した Unicode から Shift_JIS (コードページ932)への変換についてです。

WideCharToMultiByte を使用する際に発生しやすい問題点は以下の2点です。

バッファサイズの指定ミスによるバッファオーバーフロー

変換前の Unicode の文字列は「文字数」で指定するのに対し(cchWideChar)、変換結果を受け取るバッファのサイズ(cbMultiByte)は「バイト単位」で指定しなければいけません。cchWideChar、cbMultiByte のどちらも終端のヌル文字を含めたサイズを指定します。
cbMultiByte にゼロを指定した場合には、関数の戻り値としてバッファに必要な大きさが返されますので、それを利用して動的にメモリを確保するのもよいでしょう。

Unicode から Shift_JIS への変換における多対一のマッピング

WideCharToMultiByte の呼び出しにて、フラグ(dwFlags) に WC_NO_BEST_FIT_CHARS を指定していない場合、Unicode から Shift_JIS に変換する場合に複数の Unicode 文字が同じ文字に変換されることがあります。WC_NO_BEST_FIT_CHARS フラグは Windows 2000 および Windows 98 以降で有効となりますが、残念なことに WideCharToMultiByte に関する世の中の例題の多くではあまり指定されていないようです。
このフラグを指定した場合には、Unicode 文字に直接対応する Shift_JIS の文字がない場合には、既定の文字(デフォルトでは '?' )に変換されます。このフラグを指定している場合、UnicodeShift_JIS は一対一に対応しますので、Shift_JIS をもう一度 Unicode に直した場合には(対応する文字がなく '?' に変換された場合を除き)同じ文字に戻すことができます。
フラグが指定されていない場合には、「よく似た文字」に変換されてしまい、そのような Shift_JIS の文字を再び Unicode に変換した場合には元の文字とは異なった文字に変換されてしまいます。例えば、U+00C0(À)は、Shift_JIS に変換すると 0x41(A) に置き換わります。もちろん、U+0041(A)も Shift_JIS への変換で 0x41(A) になります。逆に、Shift_JIS の 0x41 を Unicode に変換した場合には、U+0041(A) になります。このように、WC_NO_BEST_FIT_CHARS を設定しない変換においては、UnicodeShift_JIS の間では多対一の変換が行われてしまいます。

具体的に、Shift_JIS に変換した場合に「似たような文字」として変換される文字は以下の通りです。次回はこれらの「似た文字の変換」によって引き起こされる問題について説明したいと思います。

続きを読む