如何为自定义 istream/streambuf 实现eekg()?

发布于 2024-09-14 14:01:06 字数 872 浏览 8 评论 0原文

十年前我曾经是一名 C++ 专家,但过去 10 年我一直在进行 Java 编程。我刚刚启动了一个使用小型第三方 XML 解析器的 C++ 项目。 XML 解析器接受 STL istream。我的 XML 数据来自 Windows COM IStream。我认为我应该做正确的事情并创建一个适配器来获取 IStream 数据并通过 istream 将其呈现给 XML 解析器。

我遵循了 http://www.mr-edd.co.uk/ 上的精彩教程blog/beginners_guide_streambuf 并创建了一个 COMStreambuf,它从底层 COM IStream 获取数据,并将其用作自定义 COMIstream 的缓冲区。一切看起来都不错,但我从解析器收到读取错误。

结果解析器通过在istream上使用seekg()将整个文件读取到内存中以找出其大小,然后使用seekg()返回到开头一次性读取它。毫不奇怪,上述教程决定“将[有关实现搜索的说明]保存到另一篇文章中”,而这显然从未被编写过。

有人可以告诉我需要做什么才能使用自定义 istream/streambuf 实现eekg() 吗?我会冒险自己去做(我的第一个倾向是覆盖 istream 中的内容),但由于我在 STL 方面缺乏经验,而且我的 Java 心态,我担心我会做一些不完整的事情,并得到一个脆弱的解决方案。 (例如,如果不阅读教程,我永远不会猜到有人会通过编写新的streambuf来创建自定义istream,或者我需要使用默认语言环境调用imbue()等。)

感谢您的任何帮助。这个网站给我留下了深刻的印象——参与者的知识,以及他们在承认谁拥有最佳答案方面的友好、诚实的本性。 :)

I used to be a C++ expert a decade ago, but for the past 10 years I've been programming Java. I just started a C++ project that uses a small third-party XML parser. The XML parser accepts an STL istream. My XML data is coming from a Windows COM IStream. I thought I'd do the Right Thing and create an adapter to take the IStream data and present it to the XML parser through an istream.

I followed the excellent tutorial at http://www.mr-edd.co.uk/blog/beginners_guide_streambuf and created a COMStreambuf that takes data from the underlying COM IStream, and used it as a buffer for a custom COMIstream. Everything looks good, but I get a read error from the parser.

Turns out the parser reads the whole file into memory by using seekg() on the istream to find out its size and then goes back to the beginning with seekg() to read it in one go. Unsurprisingly, the aforementioned tutorial decided to "save [instructions on implementing seeking] for another post" which was apparently never written.

Can someone tell me what I need to do to implement seekg() with my custom istream/streambuf? I would venture out doing it myself (my first inclination would be to override stuff in istream), but with my inexperience this deep in the STL and with my Java mentality I fear I would do something incomplete and have a brittle solution. (Without reading tutorials, for example, I never would have guessed that one makes a custom istream by writing a new streambuf, for example, or that I would need to call imbue() with a default locale, etc.)

Thanks for any help. I've been very impressed with this site---both with the knowledge of the participants and their friendly, honest nature in conceding who has the best answer. :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

極樂鬼 2024-09-21 14:01:06

我认为“seekg”是指seekoffseekpos

实现 COMStreambuf 的成员 seekoffseekpos 的直接方法是包装 IStream 接口的Seek 方法。例如,类似这样的东西应该可以工作:

// 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_);
}

在此清单中,在设置 streamIn 的位置后,我调用:

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

在查找之后,sputbackcsungetc将在旧数据上运行。您可能需要考虑这对您的应用程序是否有意义并做一些不同的事情。

I assume that by "seekg" you mean seekoff and seekpos.

The straightforward way to implement members seekoff and seekpos of your COMStreambuf is to wrap the Seek method of the IStream interface. For example, something like this should work:

// 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_);
}

In this listing, after setting the position of streamIn I call:

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

After a seek, sputbackc or sungetc will operate on old data. You may want to consider whether this makes sense for your application and do something different.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文