Question

After asking question about crypto++ I tried to implement it using boost iostreams. I produced following code:

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

Problem no. 1: It does not work if I make sha_output_filter non-copyable despite documentation stating "if T is a standard stream or stream buffer type, by using the templated overload of push taking a non-const reference." but if I uncomment line:

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

The boost::ref works however.


Problem no. 2. How to close the stream? The debug output is:

write
put
put
put
put
Was it helpful?

Solution

The first problem is that your sha_output_filter does not meet the requirements for using the non-const overload of push, because it is not derived from std::istream, std::ostream or std::streambuf, so it is not classified as a standard stream or stream buffer type.
This can be deduced from one of the first messages from the compiler

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]’:

where it indicates that it can successfully resolve the boost::disable_if<...>::type, so it does not disable this overload. If you look at the source code, you will probably find a enable_if test on the non-const overload.


Regarding the second problem, your filter is not marked as being closable, so the Boost library does not know it can call close on the filter.

This can be resolved by replacing the typedef for category with

struct category : boost::iostreams::output_filter_tag, boost::iostreams::closable_tag {};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top