使用自定义缓冲区增强iostream的使用率

时间:2016-03-11 02:56:50

标签: c++ boost iostream

我正在为Windows RTF流编写一个界面。我可以在没有boost::iostreams的情况下做到这一点,但这让我有机会学习图书馆。只要我留下注释行,下面的代码就会编译。

我也希望在Unicode中也可以这样做,因为我的一些RTF存储在一个访问数据库中,备忘录字段作为Unicode传递给我。

我开始认为我这样做比我需要的更复杂。马上,我不知道如何将传递的缓冲区连接到我的设备,所以我可以将它流式传输到Windows。 OTOH我可以在我的basic_stream中使用它,但这似乎不对。

当我尝试使用我的typedef file_wstream时,我得到了:

1>c:\cpp\reserveanalyst\stock_database\rtf.cpp(74): error C2614: 'rtf::basic_stream<_Elem,Dev>' : illegal member initialization: 'stream<boost::iostreams::basic_file_source<char>,rtf::wbuffer<wchar_t>,std::allocator<wchar_t> >' is not a base or member
1>          with
1>          [
1>              _Elem=rtf::wbuffer<wchar_t>,
1>              Dev=boost::iostreams::file_source
1>          ]

即使我正在使用basic_file_source< char >,也会达到io::wfile_source。使用wfile不应该提供RTF,但我想知道原因。

namespace io = boost::iostreams;
namespace rtf
{
    enum io_mode
    {
        sbad,
        read,
        write,
    };
// ........     wbuffer      ...........
    template< typename E >
    class wbuffer : public io::char_traits< E >
    {
    public:
        typedef E                       char_type;
        typedef std::streamsize         size_type;
        typedef size_t                  int_type;

        wbuffer( E* buf )
            :pointer( buf )
        { }
        size_type size( ) const { return 0; }
        E* begin( ) { return NULL; }
        static int_type eof( ) { return 0; }
    private:
        E* pointer;
    };

// ........       my_dev     ........
    class my_dev
    {
    public:
        typedef wchar_t        char_type;
        typedef io::bidirectional_device_tag  category;

        //my_dev( Container& container)
        //  :container_(container)
        //{ }
        std::streamsize read( char_type* s, std::streamsize n)
        {
            return 0;
        }
       std::streamsize write( const char_type* s, std::streamsize n)
       {
           return 0;
       }
    };

// ........     basic_stream     ..........
    template< typename _Elem, typename Dev= my_dev >
    class basic_stream : public boost::iostreams::stream< Dev, _Elem >
    {
    public:
        typedef typename boost::iostreams::char_type_of< _Elem >::type  char_type;
        typedef typename io::char_traits< _Elem >                traits_type;
        basic_stream( char_type* buf, io_mode mode= sbad )
            :mode( mode )
        { }
        //
        basic_stream( io::wfile_source& stream, io_mode mode= sbad )
            :mode( mode )
            ,boost::iostreams::stream< Dev, _Elem, std::allocator< _Elem::char_type > >( stream )
        { }

        std::streamsize write( char_type* s, std::streamsize n )
        {
            //io::write( s, io::stream< Dev >, &io::char_type_of< _Elem >::type, n ); 
            return 0;
        }
        std::streamsize read( char_type* s, std::streamsize n )
        {
//          std::basic_iostream< _Elem, _Traits >::read( s, n ); 
            return 0;
        }

        io_mode get_mode( ) const { return mode; }
        std::streamsize count( ) const { return 0; }

    private:
        io_mode mode;
    };

// ........ 
    typedef rtf::basic_stream< wbuffer< wchar_t > > read_wstream;
    typedef rtf::basic_stream< wbuffer< wchar_t >, io::file_source > file_wstream;

};//namespace rtf

/*
DWORD CALLBACK EditStreamCallback(
  _In_ DWORD_PTR dwCookie,  whatever we please as an object pointer
  _In_ LPBYTE    pbBuff,    the RTF buffer
  _In_ LONG      cb,        number of bytes to transfer
  _In_ LONG      *pcb       number of bytes that were transfered
);
*/

template< typename _Char >
DWORD CALLBACK rtf_stream_callback(
        DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb )
{
    rtf::basic_stream< rtf::wbuffer< _Char > >& cookie= *(rtf::basic_stream< rtf::wbuffer< _Char > >*)dwCookie;
    try
    {
        if( cookie.get_mode( ) == rtf::read )
        {
            *pcb= (LONG)cookie.read( (_Char*)pbBuff, cb );
        }
        else if( cookie.get_mode( ) == rtf::write )
        {
            //*pcb= (LONG)cookie.write( (_Char*)pbBuff, cb );
            cookie.write( (_Char*)pbBuff, cb );
        }
        else
            ;//error!

    }
    catch( std::exception e )
    {
    }
    return 0;
    }

//The actual public calls
    BOOL SetRichText( CRichEditCtrl& re, LPCTSTR buf, int format )//| SFF_SELECTION
    {
        rtf::read_wstream ios( const_cast< wchar_t* >( buf ), rtf::write );
        EDITSTREAM es= { (DWORD_PTR)&ios, 0, rtf_stream_callback< wchar_t > };
        long r= (long)::SendMessage( re, EM_STREAMIN, format, (LPARAM)&es );
        return true;
    }

    bool SetRichText( CRichEditCtrl& r, std::ifstream& istr, int format )
    {
        std::wstringstream str;
        io::wfile_source f( "test.rtf" );
    //  rtf::file_wstream ws( f, rtf::write );
        return false;
    }

这就是我最终的结果。这可能是错误的做法,但我学到了很多东西。

namespace io = boost::iostreams;

namespace rtf
{
    enum io_mode
    {
        e_bad,
        e_read,
        e_write,
    };
    // ........       rtf_buffer     ........
    template< typename Char >
    class rtf_buffer
    {
    public:
        typedef Char                            char_type;
        typedef io::bidirectional_device_tag    category;
        typedef io::char_traits< Char >         char_traits;
        typedef std::streamsize                 buf_count;

        rtf_buffer( char_type** buf, io_mode mode )
            :buf_( *buf )
            ,cur_( *buf )
            ,user_( buf )
            ,mode( mode )
        {
            if( mode == e_write )
                if( std::is_same< Char, wchar_t >::value )
                    end_= (Char*)( *buf + _tcslen( (wchar_t*)*buf ) );
                else
                    end_= (Char*)( *buf + strlen( (char*)*buf ) );
            else
                end_= *buf;
        }

        buf_count read( char_type* s, buf_count n )
        {
            std::streamsize left= end_ - cur_;
            if( ! left )
                return -1;

            if( left < n )
            {
                if( std::is_same< Char, wchar_t >::value )
                {
                    size_t c;
                    char* buffer= new char[ (size_t)n ]; //TODO not big enough for asian chars
                    errno_t err= wcstombs_s( &c, buffer, (int)left, (wchar_t*)cur_, _TRUNCATE ); //TODO errno
                    memcpy( s, buffer, c );
                    delete [ ] buffer;
                }
                else
                    memcpy( s, cur_, (size_t)left );

                cur_= end_;
                return left;
            }
            //else
            {
                if( std::is_same< Char, wchar_t >::value )
                {
                    size_t c;
                    char* buffer= new char[ (size_t)n ]; //TODO not big enough for asian chars ?
                    errno_t err= wcstombs_s( &c, buffer, (int)n, (wchar_t*)cur_, _TRUNCATE ); //TODO errno
                    memcpy( s, buffer, c );
                    delete [ ] buffer;
                }
                else
                    memcpy( s, cur_, (size_t)n );
                cur_+= n;
                return n;
            }
        }
        buf_count write( char_type* s, buf_count n )
        {
            buf_count old_size= buffer.size( );
            if( std::is_same< Char, wchar_t >::value )
            {
                mbstate_t state;
                memset(&state, 0, sizeof state);
                size_t d_size;
                // mbsrtowcs_s(_Out_opt_ size_t* _Retval, _Out_opt_z_cap_(_Size) wchar_t * _Dst, _In_ size_t _Size, _Inout_ _Deref_prepost_opt_valid_ const char ** _PSrc, _In_ size_t _N, _Out_opt_ mbstate_t * _State);
                //'(size_t *, wchar_t [1], wchar_t **, int, mbstate_t *)'
                errno_t err= mbsrtowcs_s( &d_size, NULL, 0, (const char**)&s, (size_t)n, &state );
                buf_count size= d_size + old_size;
                buffer.resize( (size_t)size + 1, 0 );
                err= mbsrtowcs_s( &d_size, (wchar_t*)&buffer[ (size_t)old_size ], (size_t)size, (const char**)&s, (size_t)n, &state );
            }
            else
            {
                buffer.resize( (size_t)( n + buffer.size( ) ) );
                memcpy( s, cur_, (size_t)n );
                return n;
            }
            *user_= &buffer.front( );
            cur_+= n;
            return n;
        }
        char_type* buf_;
        char_type* end_;
        char_type* cur_;
        char_type** user_;
        io_mode mode;
        std::vector< Char > buffer;
    };

    // ........     basic_stream     ..........
    template< typename Char, typename Dev >
    class stream
        :public Dev
    {
    public:
        typedef Char                                            char_type;
        typedef typename io::char_traits< Char >                traits_type;
        typedef std::is_same< std::ifstream, Dev >              is_ifstream;
        typedef std::streamsize                                 buf_count;

// rtf_buffer constructor
        stream( char_type** buf, io_mode mode= e_bad )
            :mode( mode )
            ,Dev( buf, mode )
        {
        }
// std::ifstream construtor
        stream( std::ifstream& is, io_mode mode= e_bad )
            :mode( mode )
            ,Dev( )
        {
            set_rdbuf( is.rdbuf( ) );
        }
// std::ofstream construtor
        stream( std::ofstream& os, io_mode mode= e_bad )
            :mode( mode )
            ,Dev( )
        {
            set_rdbuf( os.rdbuf( ) );
        }
//write buf
    template <class U >
        typename std::enable_if<
            std::is_base_of< rtf_buffer< Char >, U >::value, buf_count >
        ::type
        write_rtf( char_type* s, buf_count n )
        {
            return Dev::read( s, n );
        }
//write istream
    template <class U >
        typename std::enable_if<
            std::is_base_of< std::ifstream, U >::value, buf_count >
        ::type
        write_rtf( char_type* s, buf_count n )
        {
            std::ifstream::read( (char*)s, n );
            return std::ifstream::gcount( );
            return 0;
        }
//write ostream
    template <class U >
        typename std::enable_if<
            std::is_base_of< std::ofstream, U >::value, buf_count >
        ::type
        write_rtf( char_type* s, buf_count n )
        {
            return 0;
        }
//read buf
    template <class U >
        typename std::enable_if<
            std::is_base_of< rtf_buffer< Char >, U >::value, buf_count >
        ::type
//      buf_count
        read_rtf( char_type* s, buf_count n )
        {
//          return 0;
            return Dev::write( s, n );
        }
//read istream
    template <class U >
        typename std::enable_if<
            std::is_base_of< std::ifstream, U >::value, buf_count >
        ::type
        read_rtf( char_type* s, buf_count n )
        {
            //return Dev::write( s, n );
            return 0;
        }

//read ostream
    template <class U >
        typename std::enable_if<
            std::is_base_of< std::ofstream, U >::value, buf_count >
        ::type
        read_rtf( char_type* s, buf_count n )
        {
            std::ofstream::write( s, n );
            return 0;
        }

        io_mode get_mode( ) const { return mode; }
    private:
        io_mode mode;
    };
};//namespace rtf

/*
DWORD CALLBACK EditStreamCallback(
  _In_ DWORD_PTR dwCookie,  whatever we please as an object pointer
  _In_ LPBYTE    pbBuff,    accual io buffer
  _In_ LONG      cb,        number of bytes to transfer
  _In_ LONG      *pcb       number of bytes that were transfered
);
*/

template< typename IO >
DWORD CALLBACK rtf_stream_callback(
        DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb )
{
    auto& cookie= *(IO*)dwCookie;
    try
    {
        if( cookie.get_mode( ) == rtf::e_read )
            *pcb= (LONG)cookie.read_rtf< IO >( (IO::char_type*)pbBuff, cb );

        else if( cookie.get_mode( ) == rtf::e_write )
            *pcb= (LONG)cookie.write_rtf< IO >( (IO::char_type*)pbBuff, cb );

        else
            ;//error!
    }
    catch( std::exception e )
    {
    }
    return 0;
}

//......
class rtf_fstream
{
};

typedef rtf::stream< wchar_t, rtf::rtf_buffer< wchar_t > > rtf_wbuf;
typedef rtf::stream< char, std::ifstream > rtf_istream;
typedef rtf::stream< char, std::ofstream > rtf_ostream;

//format |= SFF_SELECTION
BOOL SetRichText( CRichEditCtrl& re, LPCTSTR buf, int format )
{
    rtf_wbuf  ios( const_cast< wchar_t** >( &buf ), rtf::e_write );
    EDITSTREAM es= { (DWORD_PTR)&ios, 0, rtf_stream_callback< rtf_wbuf > };
    long r= (long)::SendMessage( re, EM_STREAMIN, format, (LPARAM)&es );
    return FALSE;
}

bool SetRichText( CRichEditCtrl& re, bfs::path& path, int format )
{
    std::ifstream is( path.string( ) );
    rtf_istream  ios( is, rtf::e_write );
    EDITSTREAM es= { (DWORD_PTR)&ios, 0, rtf_stream_callback< rtf_istream > };
    long r= (long)::SendMessage( re, EM_STREAMIN, format, (LPARAM)&es );
    return true;
}

LPTSTR GetRichText( CRichEditCtrl& re, int format ) //| SFF_SELECTION
{
    wchar_t* p_buf;
    rtf_wbuf os( &p_buf, rtf::e_read );
    EDITSTREAM es= { (DWORD_PTR)&os, 0, rtf_stream_callback< rtf_wbuf > };
    long r= (long)::SendMessage( re, EM_STREAMOUT, format, (LPARAM)&es );

    return NULL;
}

bool GetRichText( CRichEditCtrl& re, CString& str, int format ) //| SFF_SELECTION
{
    wchar_t* p_buf;
    rtf_wbuf os( &p_buf, rtf::e_read );
    EDITSTREAM es= { (DWORD_PTR)&os, 0, rtf_stream_callback< rtf_wbuf > };
    long r= (long)::SendMessage( re, EM_STREAMOUT, format, (LPARAM)&es );
    wchar_t* sb= str.GetBufferSetLength( r );
    memcpy( sb, p_buf, r * sizeof( wchar_t ) );
    str.ReleaseBuffer( );
//  str= *p_buf;
    return true;
}

bool GetRichText( CRichEditCtrl& re, bfs::path& path, int format )
{
    std::ofstream os( path.string( ) );
    rtf_ostream ios( os, rtf::e_read );
    EDITSTREAM es= { (DWORD_PTR)&ios, 0, rtf_stream_callback< rtf_ostream > };
    //long r= (long)::SendMessage( re, EM_STREAMIN, format, (LPARAM)&es );
    return false;
}

我唯一没做过的就是测试ofstream write正常工作。

1 个答案:

答案 0 :(得分:0)

您尝试在成员(模式)之后初始化基类。

另外,在初始化基类时指定了分配器(也许是错误的),但是在第一次声明基类时却没有。

初步修复:

basic_stream(io::wfile_source &stream, io_mode mode = sbad)
    : boost::iostreams::stream<Dev, _Elem>(stream), mode(mode)  {}

现在看起来你正在将io::wfile_source填充到该基类的wbuffer<>构造函数参数中。这看起来不错,但如果没有SSCCE,我很难说出你想做什么。

相关问题