2011-01-12 3 views
2

После запроса question about crypto++ Я попытался реализовать его с помощью boost iostreams. Я произвел следующий код:Использование импульсных фильтров iostreams (закрыть и не копировать)

#include <iostream> 
#include <cryptopp/sha.h> 
#include <algorithm> 
#include <boost/array.hpp> 
#include <boost/iostreams/concepts.hpp> 
#include <boost/iostreams/operations.hpp> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <boost/iostreams/device/file.hpp> 

template<typename hash> 
class sha_output_filter : public boost::iostreams::output_filter 
{ 
    hash _hash; 
    char _digest[hash::DIGESTSIZE]; 
public: 
    typedef char         char_type; 
    typedef boost::iostreams::output_filter_tag category; 

    sha_output_filter() {} 
    //sha_output_filter(const sha_output_filter &) = delete; 
    sha_output_filter &operator=(const sha_output_filter &) = delete; 

    template<typename Sink> 
    bool put (Sink &dest, int c) 
    { 
    std::cout << "put" << std::endl; 
    char _c = c; 
    _hash.Update ((const byte *)&_c, 1); 
    boost::iostreams::put (dest, c); 
    } 

    template<typename Source> 
    void close (Source &src) 
    { 
    std::cout << "close" << std::endl; 
    _hash.Final(_digest); 
    } 

    boost::array<char, hash::DIGESTSIZE> digest() { 
    boost::array<char, hash::DIGESTSIZE> tmp; 
    std::copy(_digest, _digest + hash::DIGESTSIZE, tmp.begin()); 
    return tmp; 
    } 
}; 

int main() 
{ 
    sha_output_filter<CryptoPP::SHA1> outf; 
    boost::iostreams::filtering_ostream out; 
    out.set_auto_close (true); 
    out.push(outf); 
    out.push(boost::iostreams::file_sink("my_file.txt")); 
    std::cout << "write" << std::endl; 
    out.write("123\n", 4); 
    out.pop(); 
    out.pop(); 
    boost::iostreams::file_sink hash_out("hash.txt"); 
    boost::array<char, CryptoPP::SHA1::DIGESTSIZE> digest = outf.digest(); 
    hash_out.write(digest.begin(), CryptoPP::SHA1::DIGESTSIZE); 
} 

Проблема нет. 1: Это не работает, если я делаю sha_output_filter без копируемого несмотря документации с указанием "if T is a standard stream or stream buffer type, by using the templated overload of push taking a non-const reference.", но если я раскомментируйте строки:

In file included from /usr/include/boost/iostreams/traits.hpp:31:0, 
       from /usr/include/boost/iostreams/detail/dispatch.hpp:17, 
       from /usr/include/boost/iostreams/flush.hpp:17, 
       from /usr/include/boost/iostreams/close.hpp:18, 
       from /usr/include/boost/iostreams/operations.hpp:16, 
       from test.cpp:6: 
test.cpp: In function ‘T boost::iostreams::detail::wrap(const T&, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’: 
/usr/include/boost/iostreams/stream_buffer.hpp:94:5: instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:257:60: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:216:1: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
/usr/include/boost/iostreams/chain.hpp:496:7: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:484:1: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
test.cpp:51:16: instantiated from here 
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’ 
/usr/include/boost/iostreams/detail/wrap_unwrap.hpp:53:14: error: used here 
In file included from /usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:23:0, 
       from /usr/include/boost/iostreams/stream_buffer.hpp:22, 
       from /usr/include/boost/iostreams/chain.hpp:35, 
       from /usr/include/boost/iostreams/filtering_streambuf.hpp:17, 
       from /usr/include/boost/iostreams/filtering_stream.hpp:22, 
       from test.cpp:7: 
test.cpp: In constructor ‘boost::iostreams::detail::concept_adapter<T>::concept_adapter(const T&) [with T = sha_output_filter<CryptoPP::SHA1>]’: 
/usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:187:5: instantiated from ‘void boost::iostreams::detail::indirect_streambuf<T, Tr, Alloc, Mode>::open(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/stream_buffer.hpp:106:13: instantiated from ‘void boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::open_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/stream_buffer.hpp:94:5: instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:257:60: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:216:1: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
/usr/include/boost/iostreams/chain.hpp:496:7: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:484:1: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
test.cpp:51:16: instantiated from here 
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’ 
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:67:48: error: used here 
test.cpp: In copy constructor ‘boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >::concept_adapter(const boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >&)’: 
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:38:23: instantiated from ‘void boost::iostreams::detail::optional<T>::reset(const T&) [with T = boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >]’ 
/usr/include/boost/iostreams/detail/streambuf/indirect_streambuf.hpp:187:5: instantiated from ‘void boost::iostreams::detail::indirect_streambuf<T, Tr, Alloc, Mode>::open(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/stream_buffer.hpp:106:13: instantiated from ‘void boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::open_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/stream_buffer.hpp:94:5: instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:257:60: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:216:1: instantiated from ‘void boost::iostreams::detail::chain_base<Self, Ch, Tr, Alloc, Mode>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Self = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, Ch = char, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::output, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
/usr/include/boost/iostreams/chain.hpp:496:7: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push_impl(const T&, std::streamsize, std::streamsize) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int]’ 
/usr/include/boost/iostreams/chain.hpp:484:1: instantiated from ‘void boost::iostreams::detail::chain_client<Chain>::push(const T&, std::streamsize, std::streamsize, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type*) [with T = sha_output_filter<CryptoPP::SHA1>, Chain = boost::iostreams::chain<boost::iostreams::output, char, std::char_traits<char>, std::allocator<char> >, std::streamsize = long int, typename boost::disable_if<boost::iostreams::is_std_io<T> >::type = void]’ 
test.cpp:51:16: instantiated from here 
test.cpp:20:3: error: deleted function ‘sha_output_filter<hash>::sha_output_filter(const sha_output_filter<hash>&) [with hash = CryptoPP::SHA1, sha_output_filter<hash> = sha_output_filter<CryptoPP::SHA1>]’ 
/usr/include/boost/iostreams/detail/adapter/concept_adapter.hpp:38:23: error: used here 
In file included from /usr/include/boost/iostreams/detail/streambuf/direct_streambuf.hpp:26:0, 
       from /usr/include/boost/iostreams/stream_buffer.hpp:21, 
       from /usr/include/boost/iostreams/chain.hpp:35, 
       from /usr/include/boost/iostreams/filtering_streambuf.hpp:17, 
       from /usr/include/boost/iostreams/filtering_stream.hpp:22, 
       from test.cpp:7: 
/usr/include/boost/iostreams/detail/optional.hpp: In member function ‘void boost::iostreams::detail::optional<T>::reset(const T&) [with T = boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >]’: 
/usr/include/boost/iostreams/detail/optional.hpp:100:9: note: synthesized method ‘boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >::concept_adapter(const boost::iostreams::detail::concept_adapter<sha_output_filter<CryptoPP::SHA1> >&)’ first required here 

В boost::ref работает однако.


Проблема №. 2. Как закрыть поток? Выход отладки:

write 
put 
put 
put 
put 

ответ

5

Первая проблема заключается в том, что ваш sha_output_filter не отвечает требованиям для использования в неконстантную перегрузки push, потому что он не является производным от std::istream, std::ostream или std::streambuf, так что это не классифицируется как стандартный поток или тип буфера потока.
Это можно вывести из одного из первых сообщений от компилятора

test.cpp: В функции «T повышение :: iostreams :: подробнее :: обертка (Const T &, имяТипа повышение :: disable_if < повышение :: iostreams :: is_std_io < Т > > :: тип *) [с Т = sha_output_filter < CryptoPP :: SHA1 >, Ьурепате повышение :: disable_if < импульс :: iostreams :: is_std_io < Т > > :: = типа недействительными ] ':

, где он указывает, что он может успешно разрешить boost::disable_if<...>::type, поэтому он не отключает эту перегрузку. Если вы посмотрите на исходный код, вы, вероятно, найдете тест enable_if на непостоянную перегрузку.


Что касается второй проблемы, то ваш фильтр не помечен как замыкаем, так что библиотека подталкивания не знает, она может вызывать close на фильтре.

Эту проблему можно решить путем замены ЬурейеЕ для category с

struct category : boost::iostreams::output_filter_tag, boost::iostreams::closable_tag {};