我正在为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正常工作。
答案 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,我很难说出你想做什么。