2012年7月18日水曜日

GDAL shape driver を深追いしてみた…

どうにも、GDAL(1.9.1)/OGR shape driver が日本語のファイル名を受け付けないので、コードを追ってみました。
VSIFilesystemHandler *VSIFileManager::GetHandler( const char *pszPath )

{
    VSIFileManager *poThis = Get();
    std::map<std::string,VSIFilesystemHandler*>::const_iterator iter;
    int nPathLen = strlen(pszPath);

    for( iter = poThis->oHandlers.begin();
         iter != poThis->oHandlers.end();
         ++iter )
    {
        const char* pszIterKey = iter->first.c_str();
        int nIterKeyLen = iter->first.size();
        if( strncmp(pszPath,pszIterKey,nIterKeyLen) == 0 )
            return iter->second;

        /* "/vsimem\foo" should be handled as "/vsimem/foo" */
        if (nIterKeyLen && nPathLen > nIterKeyLen &&
            pszIterKey[nIterKeyLen-1] == '/' &&
            pszPath[nIterKeyLen-1] == '\\' &&
            strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
            return iter->second;

        /* /vsimem should be treated as a match for /vsimem/ */
        if( nPathLen == nIterKeyLen - 1
            && strncmp(pszPath,pszIterKey,nIterKeyLen-1) == 0 )
            return iter->second;
    }
    
    return poThis->poDefaultHandler;
}
  "\" 記号文字を "/" 記号文字で置き換えしようとしているのか?これ、SJIS だと典型的にハマるパターンですね。 "表" という SJIS コードは、16進数で表すと 0x955C になります。一方 "\" という ASCII コードは、16進数で表すと 0x5C になります。日本語SJISの取り扱いでは、それぞれの char コードの範囲が SJIS の第1バイトかどうかを調べて、第一バイトに該当した時には、第2バイトもSJISコードなので、ASCII コードとしては処理をしないという条件分岐が必要になります。  SJISが出来た当初は、ASCII と被らないで、なるべく2バイト内に納めて漢字の表現をしないといけなかった事情があるので、この設計は仕方ない事ではありますが、特殊すぎます。  とにかく、こういう罠があるので、内部では UNICODE(UCS2)か、UTF8にすべきなんですが、まじうざい。いっその事、標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 標準で ufopen とか、UTF8 のパスを受け付ける関数とかが、めっちゃ欲しいです。 2012/07/19 追記: ここのコードをトレースしてみたが、何をやりたいのか、ちょっとピンと来ない…。
pszIterKey:/vsigzip/
pszIterKey:/vsimem/
pszIterKey:/vsisparse/
pszIterKey:/vsistdin/
pszIterKey:/vsistdout/
pszIterKey:/vsistdout_redirect/
pszIterKey:/vsisubfile/
pszIterKey:/vsitar/
pszIterKey:/vsizip/
ソースファイル名を渡して、そいつが、これらのデバイスにマッチするかどうかを見ているようである。日本語だと、何故、こんなところで失敗するのか?もっと他の部分をあたってみるか… 同日 追記: VSIFilesystemHandler というクラスで、ファイルシステムの文字コードによる違いを吸収しているようだ。なんとも壮大で、頭がクラクラする。 iConv を使っている場合もあるようだが、 ifdef で iConv を使うか、WinAPIを使うか、切り替えてるので、バイナリ配布物の状況がよくわからない。QGis で配布されているやつは、iConv を使うコードでコンパイルされているのだろう。ところが、FOSS4GJP の情報によると Windows版 iConv のコンパイルは、いろいろと文字コードセットに対する対応が足りないらしく、正しく動作していないらしい。  Windows では、環境変数 GDAL_FILENAME_IS_UTF8 = YES が設定されていた場合には、ファイル名を UTF8 から UNICODE に変換して、UNICODE(UCS2)のファイル名を _wstat にかけている。  どうも、この _wstat に渡すパスあたりで、こけている感じだ。一生懸命、wchar_t にしているが、内部で利用されているパスは、生のMBCSなので、_wstat にかけたいがためだけのコードに留まってしまっている。複雑になった割には報われていないという印象だ。 同日 さらに追記:  stat のコードで失敗してるのかなぁと思ったが、そういう訳でもないらしい。いろんなバージョンで、試行錯誤してたので、DLL HELL に陥ってたのかも…。

0 件のコメント: