デベハトップの謎

画像を表示するアプリケーションは星の数ほどありますが、手軽に画像ファイルのαチャンネルを確認できるものが見当たらなかったので、必要に迫られて自作したものを使っています。
以前作った libneet のサンプルに画像の拡大・縮小・パン移動・矢印キーで同じディレクトリにある他の画像を次々と表示…などの機能を付けた程度ではありますが、そこそこ重宝しています。

ところが、このアプリには Windows のデスクトップに置いた画像を開けることができない、というバグがありました。
うちは普段、半角英数字以外の文字の入ったフォルダにファイルを置く習慣がなかったので特に気にしていませんでしたが、必要に迫られたので今回調べてみました。
デバッガで追いかけてみると、ファイルのパス名に含まれる「デスクトップ」の文字が化けていることに気付きました。

  • 化ける前
  • 化けた後

「デベハトップ」…?

なんやそれ? と検索(google:デベハトップ)してみたら、同じ現象に悩んでるユーザーの声は見受けられますが、開発関係の情報は出てきません。(2005/7/6現在)
ShiftJIS の「ス」「ク」が文字列処理的にマズい文字とは聞いたことはありませんし、文字コード的にも化け方の規則性が無さ気に思えたので少し考えてしまいましたが、文字化けのタイミングが「英字の大文字→小文字変換」をしている時とわかってようやく理解しました。

ShiftJIS で両者の文字コードを並べてみるとこのようになります。

  • デ(0x83 0x66) ス(0x83 0x58) ク(0x83 0x4e) ト(0x83 0x67) ッ(0x83 0x62) プ(0x83 0x76)
  • デ(0x83 0x66) ベ(0x83 0x78) ハ(0x83 0x6e) ト(0x83 0x67) ッ(0x83 0x62) プ(0x83 0x76)

各文字の 2 バイト目だけを取り出すと、ASCII の英字に該当します。

  • "f"(0x66) "X"(0x58) "N"(0x4e) "g"(0x67) "b"(0x62) "v"(0x76)
  • "f"(0x66) "x"(0x78) "n"(0x6e) "g"(0x67) "b"(0x62) "v"(0x76)

これでもう一目瞭然ですね。原因は大文字→小文字変換の処理を行う際、ShiftJIS の 2 バイト目だと気付かず進めてしまっていたことです。マルチバイトに対応しない文字列処理ライブラリを使ったりするとこうなりますね…。

うちの場合はこのコードが原因でした。

std::string fileNameFullPath(rNameFile.c_str());
std::transform(fileNameFullPath.begin(), fileNameFullPath.end(), fileNameFullPath.begin(), std::tolower);

あぁぁ中途半端な STL 厨であることがバレてしもうた…。_| ̄|○
というか、これまでマルチバイトや wchar 関係に無知であり続けたので、真面目に勉強して出直してきます…。

検索で開発関係の情報が出てこなかったのは、きっと書くのが恥ずかしいくらいの常識すぎる情報なのでしょう…。まあいいや、せっかくだから盛大に恥をかこう(^^;)。