6

私は 10 年前は C++ の専門家でしたが、ここ 10 年間は Java をプログラミングしてきました。小さなサードパーティの XML パーサーを使用する C++ プロジェクトを開始しました。XML パーサーは、STL istream を受け入れます。私の XML データは Windows COM IStream から来ています。私は、Right Thing を実行して、IStream データを取得し、istream を介して XML パーサーに提示するアダプターを作成すると考えました。

http://www.mr-edd.co.uk/blog/beginners_guide_streambufの優れたチュートリアルに従い、基になる COM IStream からデータを取得する COMStreambuf を作成し、それをカスタム COMIstream のバッファーとして使用しました。すべて問題ないように見えますが、パーサーから読み取りエラーが発生します。

パーサーは、istream で seekg() を使用してファイル全体をメモリに読み込み、そのサイズを調べてから、seekg() で最初に戻って一度に読み込みます。当然のことながら、前述のチュートリアルでは、明らかに書かれたことのない「[シークの実装に関する指示] を別の投稿のために保存する」ことにしました。

カスタム istream/streambuf で seekg() を実装するために何をする必要があるか教えてもらえますか? 私は自分でそれをやってみようと思います (私の最初の傾向は、istream で何かをオーバーライドすることです) が、STL の深部での経験が浅く、Java のメンタリティがあるため、何か不完全なことをして脆弱な解決策になるのではないかと心配しています。(たとえば、チュートリアルを読まなければ、たとえば、新しい streambuf を記述してカスタム istream を作成したり、デフォルトのロケールで imbue() を呼び出す必要があるなどとは思いもしませんでした。)

助けてくれてありがとう。私はこのサイトに非常に感銘を受けました.---参加者の知識と、誰が最良の答えを持っているかを認める友好的で正直な性格の両方に. :)

4

1 に答える 1

3

「シーク」とは、およびを意味するseekoffと思いますseekpos

メンバーを実装する簡単なseekoff方法seekposは、インターフェイスのメソッドCOMStreambufをラップすることです。たとえば、次のようなものが機能するはずです。SeekIStream

// COMStreambuf.cpp
COMStreambuf::pos_type COMStreambuf::seekoff(COMStreambuf::off_type off_, std::ios_base::seekdir way_, std::ios_base::openmode which_)
{
    union {
        LARGE_INTEGER liMove;
        ULARGE_INTEGER uliMove;
    };
    liMove.QuadPart = off_;

    DWORD dwOrigin = STREAM_SEEK_SET;
    if (way_ == std::ios_base::cur) {
        dwOrigin = STREAM_SEEK_CUR;
    } else if (way_ == std::ios_base::end) {
        dwOrigin = STREAM_SEEK_END;
    } else {
        assert(way_ == std::ios_base::beg);
        dwOrigin = STREAM_SEEK_SET;
        uliMove.QuadPart = off_; 
    }

    ULARGE_INTEGER uliNewPosition;
    if (which_ & std::ios_base::in) {
        if (which_ & std::ios_base::out)
            return pos_type(off_type(-1));
        HRESULT hres = streamIn->Seek(liMove, dwOrigin, &uliNewPosition);
        if (hres != S_OK)
            return pos_type(off_type(-1));

        setg(eback(), egptr(), egptr());
    } else if (which_ & std::ios_base::out) {
        HRESULT hres = streamOut->Seek(liMove, dwOrigin, &uliNewPosition);
        if (hres != S_OK)
            return pos_type(off_type(-1));

        setp(pbase(), epptr(), epptr());
    } else {
        return pos_type(off_type(-1));
    }

    return pos_type(uliNewPosition.QuadPart);
}

COMStreambuf::pos_type COMStreambuf::seekpos(COMStreambuf::pos_type sp_, std::ios_base::openmode which_)
{
    return seekoff(off_type(sp_), std::ios_base::beg, which_);
}

このリストでは、streamInI call の位置を設定した後:

setg(eback(), egptr(), egptr());

シーク後、sputbackcまたはsungetc古いデータを操作します。これがアプリケーションにとって意味があるかどうかを検討し、別のことを行うことができます。

于 2010-12-05T22:57:53.197 に答える