[LDAP] LDAP v2 ではデータを Shift-JIS で扱うためサーバからの UTF-16 日本語データが文字化けする(Ver2.0)

皆さんごきげんよう。ういこうです。今日は先日作成したコンテンツを上げようと思ったときに公開ボタンを押すのを忘れていたコンテンツを発見しましたので、今日は豪華二本立てです。本当は九月分だったのに…。さて、今日はダブルバイトを使う民族がコンピュータ史上ずっと血涙を流し続ける問題…そう、「文字化け」についてお送りします。

【今日のお題】
LDAP サーバにアクセスしてダブルバイト文字を取ってこようとしたらなぜか文字化けが発生するときとしないときがある。
接続先も接続元もサーバから帰ってくるパケットデータも毎回バイナリレベルで同じなのになぜ故?

【詳細】
LDAP v3 ではなく、何らかの問題により、LDAP v2 で接続がなされた場合、クライアントサイドでは、クライアント端末内部でサーバから受け取ったデータを取り扱う際 ANSI (日本の場合は一般的に SHIFT-JIS) で文字を扱うことになります。しかしながら、実際にサーバから来る値は、UTF-16 となるため、ANSI:Shift-JIS – Unicode:UTF-16 の文字コード変換が発生し、結果的に文字化けが発生します。この際にネットワーク パケットのデータを見ても、文字化け発生時と正常時でサーバからのデータはバイナリ レベルで一切違いがありません。あくまでも問題は接続時に LDAP v2 としてバインドされることによって、クライアントがサーバから受け取ったデータを扱う際に余計な文字コード変換が発生することとなります。

こうした場合は、ネットワーク パケットでバインド状況を確認し、LDAP バージョンが v2 になっていないかを確かめてみてください。

現象発生時 : “Version : 2” となっている

image

正常時 : “Version : 3” となっている

image

【まとめ】
・サーバからのデータはネットワークパケットのバイナリレベルで正常時、異常時も変わらない
・LDAP v2 で接続されている
・LDAP v3 で接続されている場合は発生しない

なかなか不思議な事象ですね。サーバからのデータ自体は変わりが無いのに、接続 LDAP プロトコルのバージョンが違うだけで文字化けするなんて…。ちなみに現象発生時は、正常時と比較して MultiByteToWideChar() がデータを扱うたびに呼ばれまくっていました。ANSI:Shift-JIS - Unicode:UTF-16 変換でデータ破壊が起きるのは、この関数の呼ばれるタイミングです。

【おまけ : ANSI:Shift-JIS - Unicode:UTF-16 変換でなぜデータが壊れて文字化けするか】
日本語 OS 上で ANSI としてデータを扱う際は、Shift_JIS で動作します。ところが、Shift_JIS の規格外の文字コードが指定された場合など、このコードを不正な文字コードと認識してしまい、Shift_JIS 文字テーブル内に割り当てられているいずれかの任意の文字にコード自体を変更しようとする試みが OS 内部で実行されます。また、文字コード上指定されたコードに Unicode の場合と異なる文字が Shift-JIS では割り当てられている場合も別の文字に変換されてしまいます。

もちろん、Unicode であっても、「あ」「い」などのひらがなのような Shift_JIS 文字テーブルに同じ文字が割り当てられている文字の場合は問題ありませんが、これは実際は内部で Shift_JIS の文字コードとして認識されているためであり、Unicode:UTF-16 として正しく処理されているわけではありません。そのため、文字によって化けたり化けなかったり、途中から化けたりという動作となって現れます。

この動作(Unicode:UTF-16 -> ANSI 変換)が起こることによって、文字コード自体が全く異なるコードに変換され、破壊されてしまうことになります。なお、前後の文字コードの配列の関係によっては、結果として制御記号などと誤認され、予期せぬ動作を行なう可能性もあります。前後の文字の関係によって、動作が異なることもあります。

 

ういこう@超常現象と思いきや…。

(2010/10/05 Update : 本件ヘルプ下さった C 様より UTF-16 である旨のご指摘を受けて変更しました。C さんありがとうございます!)