2002-06-21 13:16:28 +02:00
|
|
|
#ifndef ARABICA_CONVERT_ADAPTOR_H
|
|
|
|
#define ARABICA_CONVERT_ADAPTOR_H
|
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// $Id$
|
2003-08-28 14:36:33 +02:00
|
|
|
// Written by Jez Higgins <jez@jezuk.co.uk>
|
|
|
|
// Copyright 1999-2003 Jez UK Ltd, http://www.jezuk.co.uk/
|
|
|
|
//
|
|
|
|
// convert_adaptor is a stream that wraps around another stream. This
|
|
|
|
// may not seem like a big deal, but convert_adaptor applies codecvt
|
|
|
|
// facets along the way. This allows you to apply encryption or
|
|
|
|
// decryption (or any other transcoding) transparently. It can
|
|
|
|
// also adapt wchar_t streams to char streams, or vice versa, allowing
|
|
|
|
// you to write std::wstrings out as UTF-8 chars to a file, for instance.
|
2002-06-21 13:16:28 +02:00
|
|
|
//////////////////////////////////////////////////////
|
|
|
|
#include <locale>
|
|
|
|
#include <istream>
|
|
|
|
#include <ostream>
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2003-09-09 11:25:42 +02:00
|
|
|
|
2003-09-10 17:15:55 +02:00
|
|
|
#include <SAX/ArabicaConfig.h>
|
2003-09-10 10:48:08 +02:00
|
|
|
#ifdef ARABICA_VS6_WORKAROUND
|
2003-09-13 01:15:14 +02:00
|
|
|
#include <SAX/Utils/impl/VS6Workaround.h>
|
2002-06-21 13:16:28 +02:00
|
|
|
#endif
|
|
|
|
|
2003-09-11 16:05:18 +02:00
|
|
|
namespace Arabica
|
|
|
|
{
|
|
|
|
namespace convert
|
|
|
|
{
|
|
|
|
|
2002-06-21 13:16:28 +02:00
|
|
|
template<typename charT,
|
|
|
|
typename traitsT = std::char_traits<charT>,
|
|
|
|
typename externalCharT = charT,
|
|
|
|
typename externalTraitsT = std::char_traits<externalCharT> >
|
|
|
|
class convert_bufadaptor : public std::basic_streambuf<charT, traitsT>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef typename traitsT::int_type int_type;
|
|
|
|
typedef std::basic_streambuf<externalCharT, externalTraitsT> fromStreambufT;
|
|
|
|
|
2003-09-02 18:00:53 +02:00
|
|
|
explicit convert_bufadaptor(fromStreambufT& frombuf) : externalbuf_(frombuf) { }
|
2002-06-21 13:16:28 +02:00
|
|
|
virtual ~convert_bufadaptor() { }
|
2003-09-02 18:00:53 +02:00
|
|
|
|
|
|
|
void set_buffer(fromStreambufT& frombuf) { externalbuf_ = &frombuf; }
|
2002-06-21 13:16:28 +02:00
|
|
|
|
|
|
|
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<charT> outBuffer_;
|
|
|
|
state_t outState_;
|
|
|
|
std::vector<charT> inBuffer_;
|
|
|
|
state_t inState_;
|
|
|
|
|
|
|
|
void growOutBuffer();
|
|
|
|
bool flushOut();
|
|
|
|
void growInBuffer();
|
2003-08-28 22:52:47 +02:00
|
|
|
std::streamsize readIn();
|
2002-06-21 13:16:28 +02:00
|
|
|
|
2003-08-28 22:52:47 +02:00
|
|
|
static const std::streamsize bufferSize_;
|
|
|
|
static const std::streamsize pbSize_;
|
2002-06-21 13:16:28 +02:00
|
|
|
}; // convert_bufadaptor
|
|
|
|
|
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-08-28 22:52:47 +02:00
|
|
|
const std::streamsize convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::bufferSize_ = 1024;
|
2002-06-21 13:16:28 +02:00
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-08-28 22:52:47 +02:00
|
|
|
const std::streamsize convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::pbSize_ = 4;
|
2002-06-21 13:16:28 +02:00
|
|
|
// why 4? both Josuttis and Langer&Kreft use 4.
|
|
|
|
|
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-09-09 11:25:42 +02:00
|
|
|
typename convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::int_type convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::overflow(int_type c)
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
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<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
|
|
|
int convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::sync()
|
|
|
|
{
|
|
|
|
return flushOut() ? 0 : -1;
|
|
|
|
} // sync
|
|
|
|
|
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-09-09 11:25:42 +02:00
|
|
|
typename convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::int_type convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::underflow()
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
if(gptr() != 0 && gptr() < egptr())
|
|
|
|
return (traitsT::to_int_type(*gptr()));
|
|
|
|
|
2003-08-28 22:52:47 +02:00
|
|
|
if(!readIn())
|
2002-06-21 13:16:28 +02:00
|
|
|
return traitsT::eof();
|
|
|
|
|
|
|
|
return traitsT::to_int_type(*gptr());
|
|
|
|
} // underflow
|
|
|
|
|
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-09-09 11:25:42 +02:00
|
|
|
typename convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::int_type convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::pbackfail(int_type c)
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
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<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
|
|
|
void convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::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<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
|
|
|
void convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::growInBuffer()
|
|
|
|
{
|
|
|
|
size_t oldsize = inBuffer_.capacity();
|
|
|
|
size_t newsize = (oldsize ? oldsize*2 : bufferSize_) + pbSize_;
|
|
|
|
inBuffer_.resize(newsize);
|
|
|
|
} // growInBuffer
|
|
|
|
|
|
|
|
template<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
|
|
|
bool convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::flushOut()
|
|
|
|
{
|
|
|
|
size_t length = pptr() - &outBuffer_[0];
|
|
|
|
if(!length)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
bool ok(true);
|
|
|
|
const std::codecvt<charT, char, state_t>& cvt =
|
2003-09-09 15:09:48 +02:00
|
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
2003-09-10 17:15:55 +02:00
|
|
|
std::use_facet<std::codecvt<charT, char, std::mbstate_t> >(this->getloc());
|
2002-06-21 13:16:28 +02:00
|
|
|
#else
|
2003-09-10 17:15:55 +02:00
|
|
|
std::use_facet(this->getloc(), (std::codecvt<charT, char, std::mbstate_t>*)0, true);
|
2002-06-21 13:16:28 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if(cvt.always_noconv())
|
|
|
|
std::copy(&outBuffer_[0], &outBuffer_[0] + length, std::ostreambuf_iterator<externalCharT>(&externalbuf_));
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we must do code conversion
|
2003-09-01 13:28:37 +02:00
|
|
|
length += cvt.max_length(); // add a little
|
2002-06-21 13:16:28 +02:00
|
|
|
std::vector<externalCharT> to(length);
|
2003-08-28 22:52:47 +02:00
|
|
|
const charT* from_next = &(outBuffer_[0]);
|
2002-06-21 13:16:28 +02:00
|
|
|
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<externalCharT>(&externalbuf_));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
std::copy(&to[0], to_next, std::ostreambuf_iterator<externalCharT>(&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<class charT, class traitsT, class externalCharT, class externalTraitsT>
|
2003-08-28 22:52:47 +02:00
|
|
|
std::streamsize convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT>::readIn()
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
if(!inBuffer_.capacity())
|
|
|
|
growInBuffer();
|
|
|
|
|
2003-08-28 22:52:47 +02:00
|
|
|
size_t pbCount = std::min<size_t>(gptr() - eback(), pbSize_);
|
2002-06-21 13:16:28 +02:00
|
|
|
memcpy(&(inBuffer_[0]) + (pbSize_-pbCount)*sizeof(charT),
|
|
|
|
gptr() - pbCount*sizeof(charT),
|
|
|
|
pbCount*sizeof(charT));
|
|
|
|
|
|
|
|
const std::codecvt<charT, char, state_t>& cvt =
|
2003-09-09 15:09:48 +02:00
|
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
2003-09-10 17:15:55 +02:00
|
|
|
std::use_facet<std::codecvt<charT, char, std::mbstate_t> >(this->getloc());
|
2002-06-21 13:16:28 +02:00
|
|
|
#else
|
2003-09-10 17:15:55 +02:00
|
|
|
std::use_facet(this->getloc(), (std::codecvt<charT, char, std::mbstate_t>*)0, true);
|
2002-06-21 13:16:28 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
std::vector<externalCharT> from(inBuffer_.capacity());
|
2003-08-28 22:52:47 +02:00
|
|
|
std::streamsize res = externalbuf_.sgetn(&(from[0]), static_cast<std::streamsize>(from.capacity()));
|
2002-06-21 13:16:28 +02:00
|
|
|
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
|
2003-08-28 22:52:47 +02:00
|
|
|
res = static_cast<std::streamsize>(to_next - (&(inBuffer_[0])+pbSize_));
|
2002-06-21 13:16:28 +02:00
|
|
|
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);
|
|
|
|
|
2003-08-28 22:52:47 +02:00
|
|
|
return static_cast<int_type>(res);
|
2002-06-21 13:16:28 +02:00
|
|
|
} // readIn
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////
|
|
|
|
// iconvert_adaptor
|
2003-09-02 18:00:53 +02:00
|
|
|
template<typename charT, typename traitsT, typename externalCharT, typename externalTraitsT>
|
|
|
|
class convert_adaptor_buffer
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
typedef std::basic_streambuf<externalCharT, externalTraitsT> fromStreambufT;
|
|
|
|
|
|
|
|
explicit convert_adaptor_buffer(fromStreambufT& frombuf) : bufadaptor_(frombuf) { }
|
|
|
|
|
|
|
|
convert_bufadaptor<charT, traitsT, externalCharT, externalTraitsT> bufadaptor_;
|
|
|
|
}; // convert_adaptor_buffer
|
|
|
|
|
2002-06-21 13:16:28 +02:00
|
|
|
template<typename charT,
|
|
|
|
typename traitsT = std::char_traits<charT>,
|
|
|
|
typename fromCharT = charT,
|
|
|
|
typename fromTraitsT = std::char_traits<fromCharT> >
|
2003-09-02 18:00:53 +02:00
|
|
|
class iconvert_adaptor : private convert_adaptor_buffer<charT, traitsT, fromCharT, fromTraitsT>,
|
|
|
|
public std::basic_istream<charT, traitsT>
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
typedef std::basic_istream<fromCharT, fromTraitsT> fromStreamT;
|
|
|
|
public:
|
|
|
|
explicit iconvert_adaptor(fromStreamT& fromstream) :
|
2003-09-02 18:00:53 +02:00
|
|
|
convert_adaptor_buffer<charT, traitsT, fromCharT, fromTraitsT>(*(fromstream.rdbuf())),
|
|
|
|
std::basic_istream<charT, traitsT>(&bufadaptor_)
|
2002-06-21 13:16:28 +02:00
|
|
|
{
|
|
|
|
} // iconvert_adaptor
|
|
|
|
|
|
|
|
virtual ~iconvert_adaptor() { }
|
|
|
|
|
|
|
|
convert_bufadaptor<charT,traitsT>* rdbuf() const
|
|
|
|
{
|
|
|
|
return const_cast<convert_bufadaptor<charT, traitsT, fromCharT, fromTraitsT>*>(&bufadaptor_);
|
|
|
|
} // rdbuf
|
2003-08-28 00:11:54 +02:00
|
|
|
}; // class iconvert_adaptor
|
2002-06-21 13:16:28 +02:00
|
|
|
|
2003-09-01 13:28:37 +02:00
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
// oconvert_adaptor
|
|
|
|
template<typename charT,
|
|
|
|
typename traitsT = std::char_traits<charT>,
|
|
|
|
typename toCharT = charT,
|
|
|
|
typename toTraitsT = std::char_traits<toCharT> >
|
2003-09-02 18:00:53 +02:00
|
|
|
class oconvert_adaptor : private convert_adaptor_buffer<charT, traitsT, toCharT, toTraitsT>,
|
|
|
|
public std::basic_ostream<charT, traitsT>
|
2003-09-01 13:28:37 +02:00
|
|
|
{
|
|
|
|
typedef std::basic_ostream<toCharT, toTraitsT> toStreamT;
|
|
|
|
public:
|
|
|
|
explicit oconvert_adaptor(toStreamT &toStream) :
|
2003-09-02 18:00:53 +02:00
|
|
|
convert_adaptor_buffer<charT, traitsT, toCharT, toTraitsT>(*(toStream.rdbuf())),
|
|
|
|
std::basic_ostream<charT, traitsT>(&bufadaptor_)
|
2003-09-01 13:28:37 +02:00
|
|
|
{
|
|
|
|
} // oconvert_adaptor
|
|
|
|
|
|
|
|
virtual ~oconvert_adaptor() { }
|
|
|
|
|
|
|
|
convert_bufadaptor<charT, traitsT>* rdbuf() const
|
|
|
|
{
|
|
|
|
return const_cast<convert_bufadaptor<charT, traitsT, toCharT, toTraitsT>*>(&bufadaptor_);
|
|
|
|
} // rdbuf
|
|
|
|
}; // class oconvert_adaptor
|
|
|
|
|
2003-09-11 16:05:18 +02:00
|
|
|
} // namespace convert
|
|
|
|
} // namespace Arabica
|
2002-06-21 13:16:28 +02:00
|
|
|
#endif
|