QC#119758 の関連です。
Report No: 119758 Status: Open
[MacOS] ParamStr(0) returns wrong string on MacOS (UTF-8 problem)
http://qc.embarcadero.com/wc/qcmain.aspx?d=119758
QCWIN:Defect_No=119758
この QC の Workaround には
UTF8ToString(RawByteString(ParamStr(0)))
とありますが、実はこれだけでは問題は解決しません。
OS X のコマンドライン引数は UTF-8 になっています…なので、System.ParamStr() の
function ParamStr(Index: Integer): string; {$IFDEF MSWINDOWS}
...
{$ENDIF MSWINDOWS} {$IF defined(LINUX) or defined(MACOS)} begin if Index < ArgCount then Result := string(PAnsiCharArray(ArgValues^)[Index]) else Result := ''; {$ENDIF LINUX or MACOS} end;
これではマズい事が解ります。
OS X で 現行の ParamStr() が返すのは、UTF-8 を ANSI (日本なら SHIFT_JIS) へ変換したものを UnicodeString へ変換したものです。Workaround は このヘンテコな UnicodeString を ANSI (日本なら SHIFT_JIS) へ変換したものを UTF-8 へ変換しますが、ANSI が噛んでいる時点で、ANSI に存在しない文字…例えば結合文字等は失われてしまいます。つまり、ParamStr() が返した値をどんなにいじっても正しい文字列は取得できない事になります。
解決方法は、ParamStr() の QC が修正されるまでは以下の関数を使う事です。
function ParamStr_OSX(Index: Integer): string; type PAnsiCharArray = array [0..0] of PAnsiChar; begin if Index < ArgCount then Result := string(UTF8String(PAnsiCharArray(ArgValues^)[Index])) else Result := ''; end;
このコードでは、コマンドライン引数 (UTF-8) を UTF8String へ格納し、それを UnicodeString へ変換して返しています。すべて Unicode で処理していますのでロスレス変換となり、文字化けは発生しません。
Workaround の方法はラウンドトリップ変換でしかないので、すべての問題を解決するには至りません。OS X のファイル名は "オレオレ NFD" で正規化されているため、ラウンドトリップだと濁点等は失われてしまいます。Unicode のみを使ったロスレス変換であれば、正規化はそのままに UnicodeString で取得できます。
See also:
Macで実行ファイルのフォルダの取得方法 (Delphi Q&A)
http://hpcgi1.nifty.com/MADIA/DelphiBBS/wwwlng.cgi?print+201311/13110006.txt
[MacOS] ParamStr(0) returns wrong string on MacOS (UTF-8 problem)
http://qc.embarcadero.com/wc/qcmain.aspx?d=119758
|