第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 に変換した場合に「似たような文字」として変換される文字は以下の通りです。次回はこれらの「似た文字の変換」によって引き起こされる問題について説明したいと思います。

UnicodeShift_JIS
¡U+00A1!0x21
¢U+00A2¢0x81 0x91
£U+00A3£0x81 0x92
¥U+00A5\0x5C
¦U+00A6|0x7C
©U+00A9c0x63
ªU+00AAa0x61
«U+00AB0x81 0xE1
¬U+00AC¬0x81 0xCA
­U+00AD-0x2D
®U+00AER0x52
¯U+00AF0x81 0x50
²U+00B220x32
³U+00B330x33
µU+00B5μ0x83 0xCA
·U+00B70x81 0x45
¸U+00B8 0x81
¹U+00B910x31
ºU+00BAo0x6F
»U+00BB0x81 0xE2
ÀU+00C0A0x41
ÁU+00C1A0x41
ÂU+00C2A0x41
ÃU+00C3A0x41
ÄU+00C4A0x41
ÅU+00C5A0x41
ÆU+00C6A0x41
ÇU+00C7C0x43
ÈU+00C8E0x45
ÉU+00C9E0x45
ÊU+00CAE0x45
ËU+00CBE0x45
ÌU+00CCI0x49
ÍU+00CDI0x49
ÎU+00CEI0x49
ÏU+00CFI0x49
ÐU+00D0D0x44
ÑU+00D1N0x4E
ÒU+00D2O0x4F
ÓU+00D3O0x4F
ÔU+00D4O0x4F
ÕU+00D5O0x4F
ÖU+00D6O0x4F
ØU+00D8O0x4F
ÙU+00D9U0x55
ÚU+00DAU0x55
ÛU+00DBU0x55
ÜU+00DCU0x55
ÝU+00DDY0x59
ÞU+00DET0x54
ßU+00DFs0x73
àU+00E0a0x61
áU+00E1a0x61
âU+00E2a0x61
ãU+00E3a0x61
äU+00E4a0x61
åU+00E5a0x61
æU+00E6a0x61
çU+00E7c0x63
èU+00E8e0x65
éU+00E9e0x65
êU+00EAe0x65
ëU+00EBe0x65
ìU+00ECi0x69
íU+00EDi0x69
îU+00EEi0x69
ïU+00EFi0x69
ðU+00F0d0x64
ñU+00F1n0x6E
òU+00F2o0x6F
óU+00F3o0x6F
ôU+00F4o0x6F
õU+00F5o0x6F
öU+00F6o0x6F
øU+00F8o0x6F
ùU+00F9u0x75
úU+00FAu0x75
ûU+00FBu0x75
üU+00FCu0x75
ýU+00FDy0x79
þU+00FEt0x74
ÿU+00FFy0x79
U+30940x83 0x94