#include <functional>
#include <ios>
#include <streambuf>

template <typename CharT, class Traits = std::char_traits<CharT>>
class encrypted_basic_streambuf : public std::basic_streambuf<CharT, Traits>
{
public:
    // Irgendwie notwendig. Bug?
    using char_type   = typename std::basic_streambuf<CharT, Traits>::char_type;
    using traits_type = typename std::basic_streambuf<CharT, Traits>::traits_type;
    using int_type    = typename std::basic_streambuf<CharT, Traits>::int_type;

    using encryption_function = std::function<char_type(char_type)>;

    encrypted_basic_streambuf(std::basic_ios<char_type, traits_type> &stream,
                              encryption_function function)
    : stream_(stream), streambuf_(stream.rdbuf()), function_(function)
    {
        stream_.rdbuf(this);
    }

    ~encrypted_basic_streambuf()
    {
        stream_.rdbuf(streambuf_);
    }

protected:
    int_type underflow() override
    {
        auto c = streambuf_->sgetc();
        return traits_type::eq_int_type(c, traits_type::eof()) ? c : function_(c);
    }

    int_type uflow() override
    {
        auto c = streambuf_->sbumpc();
        return traits_type::eq_int_type(c, traits_type::eof()) ? c : function_(c);
    }

    int_type overflow(int_type c) override
    {
        streambuf_->sputc(function_(c));
        return c;
    }

private:
    std::basic_ios<char_type, traits_type>       &stream_;
    std::basic_streambuf<char_type, traits_type> *streambuf_;
    encryption_function function_;
};

#include <iostream>

int main()
{
    {
        encrypted_basic_streambuf<char> encrypter(std::cout, [](char c){return c ^ 'a';});
        std::cout << "Hallo Welt";
    }
    std::cout << "\n Test 2: \n";
    {
        class xor_encrypter
        {
        public:
            xor_encrypter(char key)
            : key_(key) {}

            char operator() (char c)
            {
                return c ^ key_++;
            }

        private:
            char key_;
        };

        encrypted_basic_streambuf<char> encrypter(std::cout, xor_encrypter('a'));
        std::cout << "Hallo Welt";
    }
}
