mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-30 22:23:40 +01:00
302 lines
8.7 KiB
C++
302 lines
8.7 KiB
C++
#ifndef ARABICA_CONVERT_STREAM_H
|
|
#define ARABICA_CONVERT_STREAM_H
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// $Id$
|
|
//
|
|
//////////////////////////////////////////////////////
|
|
//
|
|
// basic_iconvertstream, basic_oconvertstream
|
|
//
|
|
// Written by Jez Higgins <jez@jezuk.co.uk>
|
|
// 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 <SAX/ArabicaConfig.hpp>
|
|
#include <locale>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace convert
|
|
{
|
|
|
|
template<typename charT, typename traitsT>
|
|
class convertstreambuf_init
|
|
{
|
|
public:
|
|
typedef std::basic_stringbuf<charT, traitsT> 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 charT,
|
|
typename traitsT = std::char_traits<charT>,
|
|
typename fromCharT = charT,
|
|
typename fromTraitsT = std::char_traits<fromCharT> >
|
|
class basic_iconvertstream :
|
|
private virtual convertstreambuf_init<charT, traitsT>,
|
|
public std::basic_istream<charT, traitsT>
|
|
{
|
|
typedef convertstreambuf_init<charT, traitsT> convertstreambuf_initT;
|
|
public:
|
|
typedef std::basic_istream<charT, traitsT> istreamT;
|
|
typedef typename convertstreambuf_initT::stringbufT stringbufT;
|
|
typedef std::basic_string<charT, traitsT> stringT;
|
|
typedef std::basic_string<fromCharT, fromTraitsT> fromStringT;
|
|
|
|
explicit basic_iconvertstream(std::ios_base::openmode mode = std::ios_base::in) :
|
|
convertstreambuf_initT(mode | std::ios_base::in),
|
|
std::basic_istream<charT, traitsT>(convertstreambuf_initT::buf())
|
|
{
|
|
} // 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<charT, traitsT>(convertstreambuf_initT::buf())
|
|
{
|
|
str(str);
|
|
} // basic_iconvertstream
|
|
|
|
virtual ~basic_iconvertstream()
|
|
{}
|
|
|
|
stringbufT* rdbuf() const
|
|
{
|
|
return const_cast<stringbufT*>(convertstreambuf_initT::buf());
|
|
} // rdbuf
|
|
|
|
stringT str() const
|
|
{
|
|
return convertstreambuf_initT::buf()->str();
|
|
} // str
|
|
|
|
void str(const fromStringT& str)
|
|
{
|
|
// do conversion
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
|
const std::codecvt<charT, fromCharT, typename traitsT::state_type>& cvt =
|
|
std::use_facet<std::codecvt<charT, fromCharT, typename traitsT::state_type> >(this->getloc());
|
|
#else
|
|
const std::codecvt<charT, fromCharT, traitsT::state_type>& cvt =
|
|
std::use_facet(convertstreambuf_initT::buf()->getloc(), (std::codecvt<charT, fromCharT, traitsT::state_type>*)0, true);
|
|
#endif
|
|
|
|
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;
|
|
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
|
std::back_insert_iterator<stringT> id(dest);
|
|
for(typename fromStringT::const_iterator i = str.begin(); i != str.end(); ++i, ++id)
|
|
*id = static_cast<charT>(*i);
|
|
#else
|
|
for(typename fromStringT::const_iterator i = str.begin(); i != str.end(); ++i)
|
|
dest += static_cast<charT>(*i);
|
|
#endif
|
|
|
|
return dest;
|
|
} // no_conversion
|
|
|
|
static const int toSize_ = 4096;
|
|
charT to_[toSize_];
|
|
}; // basic_iconvertstream
|
|
|
|
template<typename charT,
|
|
typename traitsT = std::char_traits<charT>,
|
|
typename toCharT = charT,
|
|
typename toTraitsT = std::char_traits<toCharT> >
|
|
class basic_oconvertstream :
|
|
private virtual convertstreambuf_init<charT, traitsT>,
|
|
public std::basic_ostream<charT, traitsT>
|
|
{
|
|
typedef convertstreambuf_init<charT, traitsT> convertstreambuf_initT;
|
|
public:
|
|
typedef std::basic_ostream<charT, traitsT> ostreamT;
|
|
typedef typename convertstreambuf_initT::stringbufT stringbufT;
|
|
typedef std::basic_string<charT, traitsT> stringT;
|
|
typedef std::basic_string<toCharT, toTraitsT> toStringT;
|
|
|
|
explicit basic_oconvertstream(std::ios_base::openmode mode = std::ios_base::out) :
|
|
convertstreambuf_initT(mode | std::ios_base::out),
|
|
std::basic_ostream<charT, traitsT>(convertstreambuf_initT::buf())
|
|
{
|
|
} // 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<charT, traitsT>(convertstreambuf_initT::buf())
|
|
{
|
|
convertstreambuf_initT::buf()->str(str);
|
|
} // basic_oconvertstream
|
|
|
|
virtual ~basic_oconvertstream()
|
|
{}
|
|
|
|
stringbufT* rdbuf() const
|
|
{
|
|
return const_cast<stringbufT*>(convertstreambuf_initT::buf());
|
|
} // rdbuf
|
|
|
|
toStringT str()
|
|
{
|
|
toStringT out;
|
|
stringT newstuff(convertstreambuf_initT::buf()->str());
|
|
|
|
if(newstuff.length() == 0)
|
|
return out;
|
|
|
|
// convert it here
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
|
const std::codecvt<charT, toCharT, typename traitsT::state_type>& cvt =
|
|
std::use_facet<std::codecvt<charT, toCharT, typename traitsT::state_type> >(this->getloc());
|
|
#else
|
|
const std::codecvt<charT, toCharT, traitsT::state_type>& cvt =
|
|
std::use_facet(getloc(), (std::codecvt<charT, toCharT, traitsT::state_type>*)0, true);
|
|
#endif
|
|
|
|
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;
|
|
|
|
#ifndef ARABICA_VS6_WORKAROUND
|
|
std::back_insert_iterator<toStringT> id(dest);
|
|
for(typename stringT::const_iterator i = str.begin(); i != str.end(); ++i, ++id)
|
|
*id = static_cast<toCharT>(*i);
|
|
#else
|
|
for(typename stringT::const_iterator i = str.begin(); i != str.end(); ++i)
|
|
dest += static_cast<toCharT>(*i);
|
|
#endif
|
|
|
|
return dest;
|
|
} // no_conversion
|
|
|
|
static const int toSize_ = 4096;
|
|
toCharT to_[toSize_];
|
|
}; // basic_oconvertstream
|
|
|
|
typedef basic_iconvertstream<char> converting_istringstream;
|
|
typedef basic_oconvertstream<char> converting_ostringstream;
|
|
#ifndef ARABICA_NO_WSTRING_T
|
|
typedef basic_iconvertstream<wchar_t> converting_iwstringstream;
|
|
typedef basic_oconvertstream<wchar_t> converting_owstringstream;
|
|
#endif
|
|
|
|
} // namespace convert
|
|
} // namespace Arabica
|
|
#endif
|