Использование форсированных фильтров iostreams (закрытых и не копируемых) - PullRequest
2 голосов
/ 12 января 2011

Задав вопрос о crypto ++ Я попытался реализовать его с помощью boost 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 не подлежащим копированию, несмотря на документацию, в которой указано ", если T - стандартный поток или тип буфера потока, с использованием шаблонной перегрузки push с неконстантной ссылкой." если я раскомментирую строку:

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

1 Ответ

5 голосов
/ 12 января 2011

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

test.cpp: В функции 'T boost :: iostreams :: detail :: wrap (const T &, повышение имени типа :: disable_if > :: type *) [с T = sha_output_filter , повышение имени типа :: disable_if > :: type = void] ':

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


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

Эту проблему можно решить, заменив typedef для category на

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