[Iostreams] code_converter from boost::iostreams fails with bidirection device

Hello, I would like to wrap an input/output stream buffer (std::streambuf) with boost::iostreams::code_converter to be able to use it both raw and with ont-the-fly encoding by the boost::iostreams::default_facet. namespace io = boost::iostreams; xxxstream stream; stream << "raw "; io::stream<io::code_converter<xxxiodevice> > wrapper(*stream.rdbuf()); wrapper << L"and converted"; I created a device wrapping std::streambuf. Pure input device (using io::source_tag) and pure output device (using io::sink_tag) were working. Combined device (using io::bidirectional_device_tag) failed with access violation in destructor (flushing and closing) of the io::code_converter in code_converter.hpp: template<typename Device, typename Codevt, typename Alloc> std::streamsize code_converter<Device, Codevt, Alloc>::write (const char_type* s, std::streamsize n) { buffer_type& buf = out(); ... std::codecvt_base::result result = // buf.eptr() was null here cvt().out( buf.state(), s + total, s + n, nint, buf.eptr(), buf.end(), next ); ... } I wondered how it is possible that the output buffer was not initialized. I learnt that the buffer was intentionally skipped in code_converter.hpp: template<typename Device, typename Codecvt, typename Alloc> struct code_converter_impl { ... void open(const Device& dev, int buffer_size) { ... // following condition is false for bidirectional if (can_write::value && !is_double::value) { buf_.second().resize(buffer_size); buf_.second().set(0, 0); } ... } ... }; The reason is the definition of a bidirectional device in categories.hpp: struct bidirectional : virtual input, virtual output, detail::two_sequence {}; It is detected in the io::code_converter turning off the initialization: typedef is_convertible<device_category, two_sequence> is_double; It means that I cannot use io::code_converter with io::bidirectional combining both io::input and io::output tags. Unfortunately I was not able to use these both explicitely: // original: typedef io::bidirectional_device_tag category; struct category : io::device_tag, io::input, io::output {}; The compiler complained about it with a message I was not able to fix: error C2784: 'std::basic_ostream<_Elem,_Traits> &boost::operator <<( std::basic_ostream<_Elem,_Traits> &,const boost::shared_ptr<Y> &)' : could not deduce template argument for 'std::basic_ostream< _Elem,_Traits> &' from 'boost::iostreams::stream<Device>' So far, I found just one working solution without changing boost sources - using two objects; one for reading, another one for writing: xxxstream stream; stream << "raw "; io::stream<io::code_converter<xxxidevice> > inwrapper(*stream.rdbuf()); io::stream<io::code_converter<xxxodevice> > outwrapper(*stream.rdbuf()); outwrapper << L"and converted"; However, I would like to use one object if it was possible. In my case, all writing is always finished before reading and vice versa. Encoding states in std::codecvt would not overlap. What would you suggest as a solution for input/output devices in io::code_converter? 1. Stick with the two objects - one for input, one for output. 2. Fix io::code_converter to accept devices with io::bidirectional tag. Either initialize both buffers or reuse the input one. 3. Use different tag than io::bidirectional. Which one? 4. Maybe I am wrapping std::streambuf in a wrong way. Is there another? I am attaching a simple example of a stripped source demonstrating the issue on std::stringstream. Thank you, Ferda
participants (1)
-
Ferdinand Prantl