从boost ::输入输出流::复制的例外() [英] exceptions from boost::iostreams::copy()

查看:851
本文介绍了从boost ::输入输出流::复制的例外()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在低于code,我有一个腐败的hello.bz2里面有流浪以外的字符EOF。

有没有一种方法,使升压::输入输出流::复制()调用抛出?

 的#include<&的fstream GT;
#包括LT&;&iostream的GT;
#包括LT&;升压/输入输出流/ filtering_streambuf.hpp>
#包括LT&;升压/输入输出流/ copy.hpp>
#包括LT&;升压/输入输出流/过滤/ bzip2.hpp>诠释的main()
{
    使用命名空间std;
    使用空间boost ::输入输出流;    ifstream的文件(hello.bz2的ios_bas​​e ::在|的ios_bas​​e ::二进制);
    filtering_streambuf<输入>在;
    in.push(bzip2_decom pressor());
    in.push(文件);
    提高::输入输出流::复制(在,COUT);
}

编辑:
请忽略这是迄今为止最受瞩目的行;在EOF。请承担与损坏的bzip2文件的工作。
我用EOF暗示我得到了错误,当我在文件上运行命令:bzcat

 命令:bzcat hello.bz2
你好,世界命令:bzcat:hello.bz2:尾随垃圾忽略EOF后


解决方案

研究

的std :: ::的ios_bas​​e失败是为类型作为异常抛出的所有对象的基类,由Iostreams库功能,报告在流缓冲操作检测到的错误。

在提升文档看

 类bzip2_error:公众的std :: ::的ios_bas​​e失败{
上市:
    bzip2_error(INT错误);
    INT错误()const的;
};

bzip2_error 是使用bzip2的过滤器时,抛出一个特定的异常,从的std :: ::的ios_bas​​e失败继承。正如你所看到的,它是通过传递重新presenting错误code整数构成。它也有一个方法错误() c将其与构建返回错误$ C $。结果
文档列表bzip2的错误codeS如下:


  • data_error - 指示COM pressed数据流已损坏。等于BZ_DATA_ERROR。

  • data_error_magic - 指示COM pressed数据流不与魔力序列'B''Z''H'开头。等于BZ_DATA_ERROR_MAGIC。

  • config_error - 表示libbzip2已经正确配置为当前平台。等于BZ_CONFIG_ERROR。

code

修改
我也想澄清的boost :: iostream的副本::()不会是一个在这里抛出异常,但bzip2的过滤器。只有iostream的或过滤器将抛出异常,只复制使用的是iostream /过滤器可能导致了iostream /过滤器抛出异常。

*的编辑2 *
它出现的问题是与bzip2_decom pressor_impl如你所预期。我已经复制了无尽的纺纱循环时,BZ2文件是空的。我花了一些时间来弄清楚如何打造提升和链路用bzip2,zlib的,和输入输出流库,看看我是否能复制你的结果。

  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 /升压/ bin.v2 /库/ -Iboost /有/升压1_42 -g

TEST.CPP:

 的#include<&的fstream GT;
#包括LT&;&iostream的GT;
#包括LT&;升压/输入输出流/ filtering_streambuf.hpp>
#包括LT&;升压/输入输出流/ copy.hpp>
#包括LT&;升压/输入输出流/过滤/ bzip2.hpp>诠释的main()
{
    使用命名空间std;
    使用空间boost ::输入输出流;    尝试{
        ifstream的文件(hello.bz2的ios_bas​​e ::在|的ios_bas​​e ::二进制);
        filtering_streambuf<输入>在;
        in.push(bzip2_decom pressor());
        in.push(文件);
        提高::输入输出流::复制(在,COUT);
    }
    抓(常量bzip2_error&安培;除外){
        INT错误= exception.error();        如果(错误==的boost ::输入输出流:: bzip2的:: data_error){
            // COM pressed数据流已损坏
            COUT<< COM pressed数据流被损坏;
        }
        否则,如果(错误==的boost ::输入输出流:: bzip2的:: data_error_magic)
        {
            // COM pressed数据流不与魔力序列'B''Z''H'开头
            COUT<< COM pressed数据流不与魔力序列'B''Z''H'开头;
        }
        否则,如果(::提高:: iostream的bzip2的:: config_error){
            // libbzip2已经正确配置为当前平台
            COUT<< libbzip2已经正确配置为当前平台;
        }
    }
}

调试:

  GDB的a.out
(GDB)b bzip2.hpp:344

有是驱动的bzip2的uncom pression在symmetric.hpp一个循环:109:

 ,而(真)
        {
            //调用滤波器,如果有在缓冲液,或者如果未消耗的字符
            //过滤器必须被刷新。
            布尔冲水=状态== f_eof;
            如果(buf.ptr()!= buf.eptr()||齐平){
                常量char_type *下一= buf.ptr();
                布尔做=
                    !过滤器()过滤器(NEXT,buf.eptr(),next_s,end_s,平齐);
                buf.ptr()= buf.data()+(下 - buf.data());
                如果(完成)
                    返回细节:: check_eof(
                               的static_cast<的std :: streamsize可>(next_s - S)
                           );
            }            //如果没有更多的字符是不加阻止,或
            //如果读取请求已经被满足,回报。
            如果((状态== f_would_block&放大器;&安培; buf.ptr()== buf.eptr())||
                 next_s == end_s)
            {
                返回的static_cast<的std :: streamsize可>(next_s - S);
            }            //填充缓冲区。
            如果(状态== f_good)
                状态=填充(SRC);
        }

bzip2_decom pressor_impl的滤波方法bzip2.hpp:344被称为上symmetric.hpp:117:

 模板<类型名的Alloc>
布尔bzip2_decom pressor_impl<&的Alloc GT; ::过滤器
    (为const char *放大器; src_begin,为const char * src_end,
      字符*&安培; dest_begin,字符* dest_end,布尔/ * *平齐/)
{
    如果(!准备好())
        在里面();
    如果(eof_)
        返回false;
    前(src_begin,src_end,dest_begin,dest_end);
    INT结果= DECOM preSS();
    后(src_begin,dest_begin);
    bzip2_error ::检查BOOST_ preVENT_MACRO_SUBSTITUTION(结果);
    !返回(eof_ =结果== bzip2的:: stream_end);
}

我认为这个问题很简单,bzip2_decom pressor_impl的eof_标志永远不会被设置。除非它想以某种神奇的方法我不明白发生的,它是由bzip2_decom pressor_impl类拥有和它永远只能被设置为false。所以,当我们做到这一点:

 猫的/ dev / null的> hello.bz2

我们得到一个旋转环,永远不会结束,当EOF被击中我们不打破。这当然是一个错误,因为其他程序(如vim)也没问题打开以类似的方式创建一个文本文件。但是我能够得到过滤器扔在BZ2文件是损坏:

 回声等腐败> hello.bz2
./a.out
COM pressed数据流不与魔力序列'B''Z''H'开头

有时你必须采取开源$ C ​​$ C与一粒盐。这将是更有可能的是你的BZ2的将被破坏,并妥善抛出。然而,在/ dev / null的情况下是一个严重的错误。我们应该将其提交给升压开发,使他们能够解决这个问题。

In the below code, I have a corrupt "hello.bz2" which has stray characters beyond the EOF.

Is there a way to make the boost::iostreams::copy() call to throw ?

#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);
}

EDIT: Please ignore the line that is so far attracted most attention; the EOF. Please assume working with a corrupted bzip2 file. I used "EOF" suggesting the error I got when I run bzcat on the file

bzcat hello.bz2
hello world

bzcat: hello.bz2: trailing garbage after EOF ignored

解决方案

Research

std::ios_base::failure is the "the base class for the types of all objects thrown as exceptions, by functions in the Iostreams library, to report errors detected during stream buffer operations."

Looking at the boost docs:

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

bzip2_error is a specific exception thrown when using the bzip2 filter, which inherits from std::ios_base::failure. As you can see, it is constructed by passing in an integer representing the error code. It also has a method error() which returns the error code it was constructed with.
The docs list bzip2 error codes as the following:

  • data_error - Indicates that the compressed data stream is corrupted. Equal to BZ_DATA_ERROR.
  • data_error_magic - Indicates that the compressed data stream does not begin with the 'magic' sequence 'B' 'Z' 'h'. Equal to BZ_DATA_ERROR_MAGIC.
  • config_error - Indicates that libbzip2 has been improperly configured for the current platform. Equal to BZ_CONFIG_ERROR.

Code

EDIT I also want to clarify that boost::iostreams::copy() will not be the one throwing the exception here, but the bzip2 filter. Only the iostream or filters will throw exceptions, copy just uses the iostream/filter which may cause the iostream/filter to throw an exception.

*EDIT 2 * It appears the problem is with bzip2_decompressor_impl as you have expected. I have replicated the endless spinning loop when the bz2 file is empty. It took me a little while to figure out how to build boost and link with bzip2, zlib, and iostreams library to see if I could replicate your results.

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";
        }
    }
}

debugging:

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

There is a loop that drives the bzip2's uncompression in symmetric.hpp:109 :

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

bzip2_decompressor_impl's filter method bzip2.hpp:344 gets called on symmetric.hpp:117 :

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

I think the problem is simple, the bzip2_decompressor_impl's eof_ flag never gets set. Unless it's suppose to happen in some magic way I don't understand, it's owned by the bzip2_decompressor_impl class and it's only ever being set to false. So when we do this:

cat /dev/null > hello.bz2

We get a spinning loop that never ends, we don't break when an EOF is hit. This is certainly a bug, because other programs (like vim) would have no problem opening a text file created in a similar manner. However I am able to get the filter to throw when the bz2 file is "corrupted":

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

Sometimes you have to take open source code with a grain of salt. It will be more likely that your bz2's will be corrupted and properly throw. However, the /dev/null case is a serious bug. We should submit it to the boost dev so they can fix it.

这篇关于从boost ::输入输出流::复制的例外()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆