#ifndef ARABICA_CONVERT_STREAM_H #define ARABICA_CONVERT_STREAM_H ////////////////////////////////////////////////////// // // $Id$ // ////////////////////////////////////////////////////// // // basic_iconvertstream, basic_oconvertstream // // Written by Jez Higgins // Copyright 1999-2005 Jez UK Ltd, http://www.jezuk.co.uk/ // // Normal basic_stringstream do not apply the codecvt facet // of their locale. These two streams act exactly like // basic_stringstream except that they do apply the imbued codecvt // facet to their input (in the case of basic_iconvertstream) // or output (int the case of basic_oconvertstream). // // This means you can to cool things like this // // std::locale loc(std::_Addfac(std::locale(), new base64_codecvt)); // converting_ostringstream os; // os.imbue(loc); // // os << "stuff"; // ... lots more stuff streamed into os // // std::cout << os.str() << std::endl; // os.str() contains the Base64 encoded byte sequence // // Decoding is just as simple. // // std::locale loc(std::_Addfac(std::locale(), new base64_codecvt)); // // converting_istringstream is; // is.imbue(loc); // is.str(a_base64_byte_stream); // std::cout << is.str(); // ... is.str() is the decode byte stream, which can also be extracted // ... using >> operators (is >> byte; etc) // //////////////////////////////////////////////////////////// #include #include #include #include #include namespace Arabica { namespace io { template class convertstreambuf_init { public: typedef std::basic_stringbuf stringbufT; convertstreambuf_init(std::ios_base::openmode mode) : buf_(mode) { } // convertstreambuf_init stringbufT const* buf() const { return &buf_; } // buf() stringbufT* buf() { return &buf_; } // buf() private: stringbufT buf_; }; // class convertstreambuf_init template, typename fromCharT = charT, typename fromTraitsT = std::char_traits > class basic_iconvertstream : private virtual convertstreambuf_init, public std::basic_istream { typedef convertstreambuf_init convertstreambuf_initT; public: typedef std::basic_istream istreamT; typedef typename convertstreambuf_initT::stringbufT stringbufT; typedef std::basic_string stringT; typedef std::basic_string fromStringT; explicit basic_iconvertstream(std::ios_base::openmode mode = std::ios_base::in) : convertstreambuf_initT(mode | std::ios_base::in), std::basic_istream(convertstreambuf_initT::buf()) { std::fill_n(to_, toSize_, 0); } // basic_iconvertstream explicit basic_iconvertstream(const stringT& str, std::ios_base::openmode mode = std::ios_base::in) : convertstreambuf_initT(mode | std::ios_base::in), std::basic_istream(convertstreambuf_initT::buf()) { str(str); } // basic_iconvertstream virtual ~basic_iconvertstream() {} stringbufT* rdbuf() const { return const_cast(convertstreambuf_initT::buf()); } // rdbuf stringT str() const { return convertstreambuf_initT::buf()->str(); } // str void str(const fromStringT& str) { // do conversion const std::codecvt& cvt = std::use_facet >(this->getloc()); if(cvt.always_noconv()) { convertstreambuf_initT::buf()->str(no_conversion(str)); return; } // we must do code conversion stringT converted; const fromCharT* from_next = str.data(); typename std::codecvt_base::result r; typename traitsT::state_type state; do { charT* to_next; r = cvt.in(state, from_next, str.data() + str.length(), from_next, to_, to_ + toSize_, to_next); if(r == std::codecvt_base::noconv) { converted.append(no_conversion(str)); break; } converted.append(to_, (to_next - to_)); } while(r == std::codecvt_base::partial); // naughty! ignore (r == std::codecvt_base::error) convertstreambuf_initT::buf()->str(converted); } // str private: stringT no_conversion(const fromStringT& str) { stringT dest; std::back_insert_iterator id(dest); for(typename fromStringT::const_iterator i = str.begin(); i != str.end(); ++i, ++id) *id = static_cast(*i); return dest; } // no_conversion static const int toSize_ = 4096; charT to_[toSize_]; }; // basic_iconvertstream template, typename toCharT = charT, typename toTraitsT = std::char_traits > class basic_oconvertstream : private virtual convertstreambuf_init, public std::basic_ostream { typedef convertstreambuf_init convertstreambuf_initT; public: typedef std::basic_ostream ostreamT; typedef typename convertstreambuf_initT::stringbufT stringbufT; typedef std::basic_string stringT; typedef std::basic_string toStringT; explicit basic_oconvertstream(std::ios_base::openmode mode = std::ios_base::out) : convertstreambuf_initT(mode | std::ios_base::out), std::basic_ostream(convertstreambuf_initT::buf()) { std::fill_n(to_, toSize_, 0); } // basic_oconvertstream explicit basic_oconvertstream(const stringT& str, std::ios_base::openmode mode = std::ios_base::out) : convertstreambuf_initT(mode | std::ios_base::out), std::basic_ostream(convertstreambuf_initT::buf()) { convertstreambuf_initT::buf()->str(str); } // basic_oconvertstream virtual ~basic_oconvertstream() {} stringbufT* rdbuf() const { return const_cast(convertstreambuf_initT::buf()); } // rdbuf toStringT str() { toStringT out; stringT newstuff(convertstreambuf_initT::buf()->str()); if(newstuff.length() == 0) return out; // convert it here const std::codecvt& cvt = std::use_facet >(this->getloc()); if(cvt.always_noconv()) out.append(no_conversion(newstuff)); else { // we must do code conversion const charT* from_next = newstuff.data(); typename std::codecvt_base::result r; typename traitsT::state_type state; do { toCharT* to_next; r = cvt.out(state, from_next, newstuff.data() + newstuff.length(), from_next, to_, to_ + toSize_, to_next); if(r == std::codecvt_base::noconv) { out.append(no_conversion(newstuff)); break; } out.append(to_, (to_next - to_)); } while(r == std::codecvt_base::partial); // naughty! ignore (r == std::codecvt_base::error) } // if(cvt.always_noconv()) convertstreambuf_initT::buf()->str(stringT()); return out; } // str void str(const stringT& str) { convertstreambuf_initT::buf()->str(str); } // str private: toStringT no_conversion(const stringT& str) { toStringT dest; std::back_insert_iterator id(dest); for(typename stringT::const_iterator i = str.begin(); i != str.end(); ++i, ++id) *id = static_cast(*i); return dest; } // no_conversion static const int toSize_ = 4096; toCharT to_[toSize_]; }; // basic_oconvertstream typedef basic_iconvertstream converting_istringstream; typedef basic_oconvertstream converting_ostringstream; #ifndef ARABICA_NO_WSTRING_T typedef basic_iconvertstream converting_iwstringstream; typedef basic_oconvertstream converting_owstringstream; #endif } // namespace io } // namespace Arabica #endif