Thread: Trying to override streambuf to use with cout

  1. #1
    Registered User
    Join Date
    Jan 2009
    Posts
    3

    Question Trying to override streambuf to use with cout

    Hi,

    I'm trying to grab all the input sent to cout to modify and redirect it. I used the example from http://www.dreamincode.net/code/snippet2499.htm, which works fine using the following code:

    Code:
        std::ofstream file_sink("encrypted.bin", std::ios_base::binary | std::ios_base::out);
        basic_xor_filter<char> filter(*(file_sink.rdbuf()), 0x7F);
        std::ostream output_stream(&filter);
        output_stream << "Hello World" << std::endl;
        output_stream.flush();
    The basic_xor_filter class overrides streambuf and simply XORs the input characters before sending them to the provided streambuf (in this case, a file). My problem occurs when I try setting cout's rdbuf() to filter:

    Code:
        streambuf* s = &filter;
        cout.rdbuf( s );
        cout << "Hello World\n";
    This code causes a glibc "double free or corruption (!prev)" error. Could anyone tell me where I am going wrong? Perhaps I just don't understand the concepts properly?

    Thanks very much.

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Be sure to reset cout's streambuffer to the old one.
    Code:
    streambuf* old = cout.rdbuf(s);
    ...
    cout.rdbuf(old);
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Jan 2009
    Posts
    3
    Thanks for the reply CornedBeef, unfortunatley this hasn't solved the problem. I have managed to stop the glibc error by using std::endl instead of \n, but it is simply replaced with a seg fault. My code now looks like this:

    Code:
            streambuf* s = &filter;
            streambuf* old = cout.rdbuf(s);
            cout << "Hello World\n" << std::endl;
            cout.flush();
            cout.rdbuf(old);
    Can anyone shed any light on what causes this?

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Use a debugger to track the segfault down. There's something wrong deeper down in the code.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Code:
    int main()
    {
        basic_xor_filter<char> filter(*(std::cout.rdbuf()), 0x00);
        std::streambuf* old = std::cout.rdbuf(&filter);
        std::cout << "Hello world\n";
        std::cout.flush();
        std::cout.rdbuf(old);
        return 0;
    }
    This works normally for me. Without restoring the original streambuf debugger indicated a segfault in the global destructors - possibly the destructor of cout is trying to delete the streambuf (filter) which already went out of scope.
    Last edited by anon; 01-11-2009 at 03:32 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #6
    Registered User
    Join Date
    Jan 2009
    Posts
    3
    Thanks for the replies everyone, i think the issues I was having were caused by the example code, I stripped out everything I didn't need and now it works.

    For anyone interested here is an example that works fine for me. It it basically designed to grab anything sent to cout and lets you do whatever you want with it at the line marked "//Do something with the string".

    mystreambuf.h
    Code:
    #ifndef __MYSTREAMBUF_H
    #define __MYSTREAMBUF_H
    
    
    
    template <typename charT, typename traits = std::char_traits<charT> >
    class mystreambuf : public std::basic_streambuf<charT, traits>
    {
    public:
        // The size of the input and output buffers.
        static const size_t BUFF_SIZE = 1024;
        typedef traits traits_type;
        typedef typename traits_type::int_type int_type;
        typedef typename traits_type::pos_type pos_type;
        typedef typename traits_type::off_type off_type;
    
        // You can use any method that you want, but here, we'll just take in a raw streambuf as a
        // slave I/O object.  xor_char is what each character is xored with before output.
        explicit mystreambuf()
            : out_buf_(new charT[BUFF_SIZE])
        {
            // Initialize the put pointer.  Overflow won't get called until this buffer is filled up,
            // so we need to use valid pointers.
            this->setp(out_buf_, out_buf_ + BUFF_SIZE - 1);
        }
    
        // It's a good idea to release any resources when done using them.
        ~mystreambuf() {
            delete [] out_buf_;
        }
    
    protected:
        // This is called when there are too many characters in the buffer (thus, a write needs to be performed).
        virtual int_type overflow(int_type c);
        // This is called when the buffer needs to be flushed.
        virtual int_type sync();
    
    
    private:
        // Output buffer
        charT* out_buf_;
    };
    
    #endif
    mystreambuf.cpp
    Code:
    // Based on class by perfectly.insane from http://www.dreamincode.net/code/snippet2499.htm
    
    #include <fstream>
    #include <iostream>
    #include <streambuf>
    
    #include "mystreambuf.h"
    
    // This function is called when the output buffer is filled.
    // In this function, the buffer should be written to wherever it should
    // be written to (in this case, the streambuf object that this is controlling).
    template <typename charT, typename traits>
    typename mystreambuf<charT, traits>::int_type
    mystreambuf<charT, traits>::overflow(mystreambuf<charT, traits>::int_type c)
    {
        charT* ibegin = this->out_buf_;
        charT* iend = this->pptr();
    
        // Reset the put pointers to indicate that the buffer is free
        // (at least it will be at the end of this function).
        setp(out_buf_, out_buf_ + BUFF_SIZE + 1);
    
        // If this is the end, add an eof character to the buffer.
        // This is why the pointers passed to setp are off by 1
        // (to reserve room for this).
        if(!traits_type::eq_int_type(c, traits_type::eof())) {
            *iend++ = traits_type::to_char_type(c);
        }
    
        // Compute the write length.
        int_type ilen = iend - ibegin;
    
        //Do something with the string
        printf("String: %.*s\n", ilen, out_buf_);
    
        return traits_type::not_eof(c);
    }
    
    // This is called to flush the buffer.
    // This is called when we're done with the file stream (or when .flush() is called).
    template <typename charT, typename traits>
    typename mystreambuf<charT, traits>::int_type
    mystreambuf<charT, traits>::sync()
    {
        return traits_type::eq_int_type(this->overflow(traits_type::eof()),
                                        traits_type::eof()) ? -1 : 0;
    }
    
    int main() {
     
        mystreambuf<char> filter;
        /*
        std::ostream output_stream(&filter);
        output_stream << "hello world";
        output_stream.flush();
        */
        
        std::streambuf* s = std::cout.rdbuf();
        std::cout.rdbuf( &filter );
        std::cout << "Hello World";
        std::cout.flush();
        std::cout.rdbuf(s);
        
    }
    cheers.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    For all iostream complicated stuff I'd much rather use the Boost.Iostreams library.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. class methods to cout stream
    By shintaro in forum C++ Programming
    Replies: 5
    Last Post: 11-11-2008, 07:27 PM
  2. How Does cout Work
    By jrahhali in forum C++ Programming
    Replies: 8
    Last Post: 08-25-2004, 03:19 PM
  3. Stupid compiler errors
    By ChrisEacrett in forum C++ Programming
    Replies: 9
    Last Post: 11-30-2003, 05:44 PM
  4. c++ string input
    By R.Stiltskin in forum C++ Programming
    Replies: 4
    Last Post: 02-22-2003, 04:25 PM
  5. FAQ cout
    By evilmonkey in forum FAQ Board
    Replies: 1
    Last Post: 10-07-2001, 11:32 AM