繁体   English   中英

boost :: iostreams :: copy()产生的异常

[英]exceptions from boost::iostreams::copy()

在下面的代码中,我有一个损坏的“ hello.bz2”,该字符具有超出EOF的杂散字符。

有没有办法使boost :: iostreams :: copy()调用抛出?

#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/bzip2.hpp>

int main() 
{
    using namespace std;
    using namespace boost::iostreams;

    ifstream file("hello.bz2", ios_base::in | ios_base::binary);
    filtering_streambuf<input> in;
    in.push(bzip2_decompressor());
    in.push(file);
    boost::iostreams::copy(in, cout);
}

编辑:请忽略到目前为止吸引最多关注的那一行; EOF。 请假定使用损坏的bzip2文件。 我使用“ EOF”提示在文件上运行bzcat时遇到的错误

bzcat hello.bz2
hello world

bzcat: hello.bz2: trailing garbage after EOF ignored

研究

std :: ios_base :: failure是“ Iostreams库中的函数抛出异常以报告在流缓冲区操作期间检测到的错误的所有对象的类型的基类。”

查看增强文档:

class bzip2_error : public std::ios_base::failure {
public:
    bzip2_error(int error);
    int error() const;
};

bzip2_error是使用bzip2过滤器时抛出的特定异常,该过滤器继承自std :: ios_base :: failure 如您所见,它是通过传入代表错误代码的整数来构造的。 它还有一个error()方法,该方法返回构造它的错误代码。
该文档列出了bzip2错误代码,如下所示:

  • data_error-表示压缩数据流已损坏。 等于BZ_DATA_ERROR。
  • data_error_magic-指示压缩数据流不是以“魔术”序列“ B”,“ Z”,“ h”开头。 等于BZ_DATA_ERROR_MAGIC。
  • config_error-表示当前平台的libbzip2配置不正确。 等于BZ_CONFIG_ERROR。

编辑我也想澄清一下,boost :: iostreams :: copy()不会是在这里抛出异常的那个,而是bzip2过滤器。 仅iostream或过滤器会引发异常,复制仅使用 iostream / filter可能会导致iostream /过滤器引发异常。

**编辑2 **看来问题出在您预期的bzip2_decompressor_impl。 当bz2文件为空时,我已经复制了无限旋转的循环。 我花了一些时间弄清楚如何构建boost并与bzip2,zlib和iostreams库链接,以查看是否可以复制您的结果。

g++ test.cpp -lz -lbz2 boostinstall/boost/bin.v2/libs/iostreams/build/darwin-4.2.1/release/link-static/threading-multi/libboost_iostreams.a -Lboostinstall/boost/bin.v2/libs/ -Iboost/include/boost-1_42 -g

test.cpp:

#include <fstream>
#include <iostream>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/bzip2.hpp>

int main()
{
    using namespace std;
    using namespace boost::iostreams;

    try {
        ifstream file("hello.bz2", ios_base::in | ios_base::binary);
        filtering_streambuf<input> in;
        in.push(bzip2_decompressor());
        in.push(file);
        boost::iostreams::copy(in, cout);
    }
    catch(const bzip2_error& exception) {
        int error = exception.error();

        if(error == boost::iostreams::bzip2::data_error) {
            // compressed data stream is corrupted
            cout << "compressed data stream is corrupted";
        }
        else if(error == boost::iostreams::bzip2::data_error_magic)
        {
            // compressed data stream does not begin with the 'magic' sequence 'B' 'Z' 'h'
            cout << "compressed data stream does not begin with the 'magic' sequence 'B' 'Z' 'h'";
        }
        else if(boost::iostreams::bzip2::config_error) {
            // libbzip2 has been improperly configured for the current platform
            cout << "libbzip2 has been improperly configured for the current platform";
        }
    }
}

调试:

gdb a.out
(gdb) b bzip2.hpp:344

在symmetric.hpp:109中有一个循环驱动bzip2的解压缩:

        while (true)
        {
            // Invoke filter if there are unconsumed characters in buffer or if
            // filter must be flushed.
            bool flush = status == f_eof;
            if (buf.ptr() != buf.eptr() || flush) {
                const char_type* next = buf.ptr();
                bool done =
                    !filter().filter(next, buf.eptr(), next_s, end_s, flush);
                buf.ptr() = buf.data() + (next - buf.data());
                if (done)
                    return detail::check_eof(
                               static_cast<std::streamsize>(next_s - s)
                           );
            }

            // If no more characters are available without blocking, or
            // if read request has been satisfied, return.
            if ( (status == f_would_block && buf.ptr() == buf.eptr()) ||
                 next_s == end_s )
            {
                return static_cast<std::streamsize>(next_s - s);
            }

            // Fill buffer.
            if (status == f_good)
                status = fill(src);
        }

在symmetric.hpp:117上调用bzip2_decompressor_impl的过滤方法bzip2.hpp:344:

template<typename Alloc>
bool bzip2_decompressor_impl<Alloc>::filter
    ( const char*& src_begin, const char* src_end,
      char*& dest_begin, char* dest_end, bool /* flush */ )
{
    if (!ready())
        init();
    if (eof_)
        return false;
    before(src_begin, src_end, dest_begin, dest_end);
    int result = decompress();
    after(src_begin, dest_begin);
    bzip2_error::check BOOST_PREVENT_MACRO_SUBSTITUTION(result);
    return !(eof_ = result == bzip2::stream_end);
}

我认为问题很简单,永远不会设置bzip2_decompressor_impl的eof_标志。 除非它以某种我不理解的魔术方式发生,否则它归bzip2_decompressor_impl类所有,并且永远只能设置为false。 因此,当我们这样做时:

cat /dev/null > hello.bz2

我们得到了一个永无止境的旋转循环,当遇到EOF时我们不会中断。 这肯定是一个错误,因为其他程序(如vim)打开以类似方式创建的文本文件不会有问题。 但是,当bz2文件“损坏”时,我能够使过滤器抛出:

echo "other corrupt" > hello.bz2
./a.out
compressed data stream does not begin with the 'magic' sequence 'B' 'Z' 'h'

有时,您必须花些精力来学习开源代码。 您的bz2更有可能被损坏并正确抛出。 但是,/ dev / null情况是一个严重的错误。 我们应该将其提交给boost开发人员,以便他们可以对其进行修复。

在文件末尾,您怎么会有流浪字符?

如果您的意思是文件中包含垃圾数据,那么解压缩算法将如何判断该数据是否为垃圾数据,从而能够决定是否throw该数据?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM