#ifndef ARABICA_CONVERT_ADAPTOR_H #define ARABICA_CONVERT_ADAPTOR_H ////////////////////////////////////////////////////// // // $Id$ // ////////////////////////////////////////////////////// #include #include #include #include #include #ifdef _MSC_VER #include #endif template, typename externalCharT = charT, typename externalTraitsT = std::char_traits > class convert_bufadaptor : public std::basic_streambuf { public: typedef typename traitsT::int_type int_type; typedef std::basic_streambuf fromStreambufT; convert_bufadaptor(fromStreambufT& frombuf) : externalbuf_(frombuf) { } virtual ~convert_bufadaptor() { } protected: virtual int_type overflow(int_type c = traitsT::eof()); virtual int sync(); virtual int_type underflow(); virtual int_type pbackfail(int_type c); private: typedef typename traitsT::state_type state_t; fromStreambufT& externalbuf_; std::vector outBuffer_; state_t outState_; std::vector inBuffer_; state_t inState_; void growOutBuffer(); bool flushOut(); void growInBuffer(); int_type readIn(); static const size_t bufferSize_; static const size_t pbSize_; }; // convert_bufadaptor template const size_t convert_bufadaptor::bufferSize_ = 1024; template const size_t convert_bufadaptor::pbSize_ = 4; // why 4? both Josuttis and Langer&Kreft use 4. template convert_bufadaptor::int_type convert_bufadaptor::overflow(convert_bufadaptor::int_type c) { if(traitsT::eq_int_type(traitsT::eof(), c)) return traitsT::not_eof(c); growOutBuffer(); sputc(traitsT::to_char_type(c)); return traitsT::not_eof(c); } // overflow template int convert_bufadaptor::sync() { return flushOut() ? 0 : -1; } // sync template convert_bufadaptor::int_type convert_bufadaptor::underflow() { if(gptr() != 0 && gptr() < egptr()) return (traitsT::to_int_type(*gptr())); size_t length = readIn(); if(!length) return traitsT::eof(); return traitsT::to_int_type(*gptr()); } // underflow template convert_bufadaptor::int_type convert_bufadaptor::pbackfail(int_type c) { if(gptr() == eback()) return traitsT::eof(); gbump(-1); if(!traitsT::eq_int_type(c, traitsT::eof())) *(gptr()) = traitsT::to_char_type(c); return traitsT::not_eof(c); } // pbackfail template void convert_bufadaptor::growOutBuffer() { size_t oldsize = outBuffer_.capacity(); size_t newsize = (oldsize ? oldsize*2 : bufferSize_); outBuffer_.resize(newsize); setp(&outBuffer_[0] + oldsize, &outBuffer_[0] + outBuffer_.capacity()); } // growOutBuffer template void convert_bufadaptor::growInBuffer() { size_t oldsize = inBuffer_.capacity(); size_t newsize = (oldsize ? oldsize*2 : bufferSize_) + pbSize_; inBuffer_.resize(newsize); } // growInBuffer template bool convert_bufadaptor::flushOut() { size_t length = pptr() - &outBuffer_[0]; if(!length) return true; bool ok(true); const std::codecvt& cvt = #ifndef _MSC_VER std::use_facet >(this->getloc()); #else std::use_facet(this->getloc(), (std::codecvt*)0, true); #endif if(cvt.always_noconv()) std::copy(&outBuffer_[0], &outBuffer_[0] + length, std::ostreambuf_iterator(&externalbuf_)); else { // we must do code conversion std::vector to(length); const charT* from_next = outBuffer_.begin(); std::codecvt_base::result r; do { externalCharT* to_next; r = cvt.out(outState_, from_next, pptr(), from_next, &to[0], &to[0]+length, to_next); if(r == std::codecvt_base::noconv) { std::copy(&outBuffer_[0], &outBuffer_[0] + length, std::ostreambuf_iterator(&externalbuf_)); break; } std::copy(&to[0], to_next, std::ostreambuf_iterator(&externalbuf_)); } while(r == std::codecvt_base::partial); ok = ok ? (r != std::codecvt_base::error) : false; } // if(cvt.always_noconv()) if(ok) setp(&outBuffer_[0], &outBuffer_[0] + outBuffer_.capacity()); return ok; } // flushOut template convert_bufadaptor::int_type convert_bufadaptor::readIn() { if(!inBuffer_.capacity()) growInBuffer(); #ifndef _MSC_VER size_t pbCount = std::min(gptr() - eback(), pbSize_); #else size_t pbCount = min(gptr() - eback(), pbSize_); #endif memcpy(&(inBuffer_[0]) + (pbSize_-pbCount)*sizeof(charT), gptr() - pbCount*sizeof(charT), pbCount*sizeof(charT)); const std::codecvt& cvt = #ifndef _MSC_VER std::use_facet >(this->getloc()); #else std::use_facet(this->getloc(), (std::codecvt*)0, true); #endif std::vector from(inBuffer_.capacity()); int res = externalbuf_.sgetn(&(from[0]), from.capacity()); if(res > 0) { std::codecvt_base::result r; do { const externalCharT* from_next; charT* to_next; r = cvt.in(inState_, &(from[0]), &(from[0]) + res, from_next, &(inBuffer_[0])+pbSize_, &(inBuffer_[0]) + inBuffer_.capacity() - pbSize_, to_next); if(r == std::codecvt_base::noconv) memcpy(&(inBuffer_[0])+pbSize_, &from[0], res); else res = to_next - (&(inBuffer_[0])+pbSize_); if(r == std::codecvt_base::partial) growInBuffer(); } while(r == std::codecvt_base::partial); if(r == std::codecvt_base::error) { // couldn't convert - let's bail return 0; } // if(r == std::codecvt_base::error) } setg(&(inBuffer_[0]) + (pbSize_-pbCount), &(inBuffer_[0])+pbSize_, &(inBuffer_[0])+pbSize_+res); return res; } // readIn //////////////////////////////////////////////////// // iconvert_adaptor template, typename fromCharT = charT, typename fromTraitsT = std::char_traits > class iconvert_adaptor : public std::basic_istream { typedef std::basic_istream fromStreamT; public: explicit iconvert_adaptor(fromStreamT& fromstream) : std::basic_istream(&bufadaptor_), bufadaptor_(*(fromstream.rdbuf())) { } // iconvert_adaptor virtual ~iconvert_adaptor() { } convert_bufadaptor* rdbuf() const { return const_cast*>(&bufadaptor_); } // rdbuf private: convert_bufadaptor bufadaptor_; }; // class basic_socketstream #endif