Исследовательская работа
std::ios_base::failure — это «базовый класс для типов всех объектов, выбрасываемых в качестве исключений функциями в библиотеке Iostreams, для сообщения об ошибках, обнаруженных во время операций буфера потока».
Глядя на документы boost:
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() будет вызывать здесь исключение не boost::iostreams::copy(), а фильтр bzip2. Только iostream или фильтры будут генерировать исключения, копировать только использует iostream/filter, что может привести к тому, что iostream/filter выдаст исключение.
**EDIT 2 ** Похоже, проблема связана с bzip2_decompressor_impl, как вы и ожидали. Я воспроизвел бесконечный цикл вращения, когда файл bz2 пуст. Мне потребовалось некоторое время, чтобы понять, как создать ускорение и связь с библиотекой 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
Существует цикл, который запускает распаковку bzip2 в 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 bzip2.hpp:344 вызывается для симметричного.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);
}
Я думаю, что проблема проста, флаг eof_ в bzip2_decompressor_impl никогда не устанавливается. Если это не произойдет каким-то волшебным образом, которого я не понимаю, он принадлежит классу 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, чтобы они могли это исправить.
person
manifest
schedule
02.07.2010