FSSpec vs. FSRef Part 3 Unicode file names

Unicode ファイル名に関する覚え書き

アプリケーションを作っていると、ファイル名やフォルダ名を表示する場面がよくあります。Mac OS X が Unicode のロングファイル名をサポートして以来、このリスト (*1) でもそれに関する話題が度々出てきたし、そのうちのいくつかには私もコメントしてきました。けれど、ここでいったんこれまでの知識を覚え書きにしておきます。もし Unicode についてあまり詳しくないのなら、その扱いには少々クセがあることを知っておきましょう。では、Unicode ファイル名を扱う場合の基本を示します。

Unicode 文字列は(Mac OS X においては)UniChar の文字列で、CFString と相互変換が可能です。Unicode 文字は複数の UniChar で構成されるかもしれない為、任意のオフセット値と範囲を指定して単純に削除/挿入操作をしてはいけません。そのような処理をすると、予想外かつ正しくない文字列になってしまう可能性があるだけでなく、Unicode 文字列として無効なものとなることさえあります。

描画の為にファイル名を切りつめる場合には、CFMutableStringRef に変換してから TruncateThemeText() を使います。長さによってファイル名を切りつめる場合には、UniChar 文字列に変換してから UCFFindTextBreak() を kUCTextBreakClusterMask フラグとともに呼び出します。これにより、クラスタの途中で文字を分断しないことを保証できます。クラスタとは複数の UniChar によって構成される、意味上の最小の単位です。クラスタから 1文字以上を削除してしまった場合、意味が変わってしまうのは良い方で、最悪の場合 Unicode として不正なものとなってしまいます。

Unicode ファイル名を別の形式に変換したい場合、ドキュメント化されていない仮定に基づいて処理してはいけません。CFStringRef を UniChar 配列に変換するには、CFStringGetCharacters() を使用します。この場合、バッファサイズは

CFStringGetLength( cfStr) * sizeof( UniChar )

により求めます。この他の変換処理では、もうちょっと話が込み入ってきます。

例えば CFString を UTF-8 形式の C 文字列に変換したい場合、CFStringGetCString() を使用しますが、バッファサイズの算出方法は以下のようになります。

bufferSize = 1 + CFStringGetMaximumSizeForEncoding( CFStringGetLength( cfStr), kCFStringEncodingUTF8 );
(*1)
訳注: Carbon-Development メーリングリストのこと

訳文に対してのフィードバックは amn@mugiwara.jp まで

[index] [Part 1] [Part 2] [Part 3]