// wstring -- convert wide strings using codecvt facet
 #pragma once
#ifndef _CVT_WSTRING_
#define _CVT_WSTRING_
#ifndef RC_INVOKED
#include <cstring>
#include <locale>
#include <stdexcept>
#include <string>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,3)

namespace stdext {
	namespace cvt {

		// TEMPLATE CLASS wstring_convert
template<class _Codecvt,
	class _Elem = wchar_t>
	class wstring_convert
	{	// converts between _Elem (wide) and char (byte) strings
	enum {_BUF_INC = 8, _BUF_MAX = 16};

	void _Init(_Codecvt *_Pcvt_arg = new _Codecvt)
		{	// initialize the object
		_Pcvt = _Pcvt_arg;
		_Loc = _STD _ADDFAC(_Loc, _Pcvt);
		_Nconv = 0;
		}

public:
	typedef _STD basic_string<char> byte_string;
	typedef _STD basic_string<_Elem> wide_string;
	typedef typename _Codecvt::state_type state_type;
	typedef typename wide_string::traits_type::int_type int_type;

	wstring_convert()
		: _Has_berr(false), _Has_werr(false), _Has_state(false)
		{	// construct with no error strings
		_Init();
		}

	wstring_convert(_Codecvt *_Pcvt_arg)
		: _Has_berr(false), _Has_werr(false), _Has_state(false)
		{	// construct with no error strings and codecvt
		_Init(_Pcvt_arg);
		}

	wstring_convert(_Codecvt *_Pcvt_arg, state_type _State_arg)
		: _Has_berr(false), _Has_werr(false), _Has_state(true)
		{	// construct with no error strings, codecvt, and state
		_Init(_Pcvt_arg);
		_State = _State_arg;
		}

	wstring_convert(const byte_string& _Berr_arg)
		: _Has_berr(true), _Has_werr(false), _Has_state(false),
			_Berr(_Berr_arg)
		{	// construct with byte error string
		_Init();
		}

	wstring_convert(const byte_string& _Berr_arg,
		const wide_string& _Werr_arg)
		: _Has_berr(true), _Has_werr(true), _Has_state(false),
			_Berr(_Berr_arg), _Werr(_Werr_arg)
		{	// construct with byte and wide error strings
		_Init();
		}

	virtual ~wstring_convert()
		{	// destroy the object
		}

	size_t converted() const
		{	// get conversion count
		return (_Nconv);
		}

	state_type state() const
		{	// get state
		return (_State);
		}

	wide_string from_bytes(char _Byte)
		{	// convert a byte to a wide string
		return (from_bytes(&_Byte, &_Byte + 1));
		}

	wide_string from_bytes(const char *_Ptr)
		{	// convert a NTBS to a wide string
		return (from_bytes(_Ptr, _Ptr + strlen(_Ptr)));
		}

	wide_string from_bytes(const byte_string& _Bstr)
		{	// convert a byte string to a wide string
		const char *_Ptr = _Bstr.c_str();
		return (from_bytes(_Ptr, _Ptr + _Bstr.size()));
		}

	wide_string from_bytes(const char *_First, const char *_Last)
		{	// convert byte sequence [_First, _Last) to a wide string
		static state_type _State0;
		wide_string _Wbuf, _Wstr;
		const char *_First_sav = _First;

		if (!_Has_state)
			_State = _State0;	// reset state if not remembered
		_Wbuf.append((_CSTD size_t)_BUF_INC, (_Elem)'\0');
		for (_Nconv = 0; _First != _Last; _Nconv = _First - _First_sav)
			{	// convert one or more bytes
			_Elem *_Dest = &*_Wbuf.begin();
			_Elem *_Dnext;

			switch (_Pcvt->in(_State,
				_First, _Last, _First,
				_Dest, _Dest + _Wbuf.size(), _Dnext))
				{	// test result of converting one or more bytes
			case _Codecvt::partial:
			case _Codecvt::ok:
				if (_Dest < _Dnext)
					_Wstr.append(_Dest, (_CSTD size_t)(_Dnext - _Dest));
				else if (_Wbuf.size() < _BUF_MAX)
					_Wbuf.append((_CSTD size_t)_BUF_INC, '\0');
				else if (_Has_werr)
					return (_Werr);
				else
					_THROW(_STD range_error, "bad conversion");
				break;

			case _Codecvt::noconv:
				for (; _First != _Last; ++_First)
					_Wstr.append((_CSTD size_t)1,
						(_Elem)(unsigned char)*_First);
				break;	// no conversion, just copy code values

			default:
				if (_Has_werr)
					return (_Werr);
				else
					_THROW(_STD range_error, "bad conversion");
				}
			}
		return (_Wstr);
		}

	byte_string to_bytes(_Elem _Char)
		{	// convert a wide char to a byte string
		return (to_bytes(&_Char, &_Char + 1));
		}

	byte_string to_bytes(const _Elem *_Wptr)
		{	// convert a NTWCS to a byte string
		const _Elem *_Next = _Wptr;
		for (; (int_type)*_Next != 0; ++_Next)
			;
		return (to_bytes(_Wptr, _Next));
		}

	byte_string to_bytes(const wide_string& _Wstr)
		{	// convert a wide string to a byte string
		const _Elem *_Wptr = _Wstr.c_str();
		return (to_bytes(_Wptr, _Wptr + _Wstr.size()));
		}

	byte_string to_bytes(const _Elem *_First, const _Elem *_Last)
		{	// convert wide sequence [_First, _Last) to a byte string
		static state_type _State0;
		byte_string _Bbuf, _Bstr;
		const _Elem *_First_sav = _First;

		if (!_Has_state)
			_State = _State0;	// reset state if not remembered
		_Bbuf.append((_CSTD size_t)_BUF_INC, '\0');
		for (_Nconv = 0; _First != _Last; _Nconv = _First - _First_sav)
			{	// convert one or more wide chars
			char *_Dest = &*_Bbuf.begin();
			char *_Dnext;

			switch (_Pcvt->out(_State,
				_First, _Last, _First,
				_Dest, _Dest + _Bbuf.size(), _Dnext))
				{	// test result of converting one or more wide chars
			case _Codecvt::partial:
			case _Codecvt::ok:
				if (_Dest < _Dnext)
					_Bstr.append(_Dest, (_CSTD size_t)(_Dnext - _Dest));
				else if (_Bbuf.size() < _BUF_MAX)
					_Bbuf.append((_CSTD size_t)_BUF_INC, '\0');
				else if (_Has_berr)
					return (_Berr);
				else
					_THROW(_STD range_error, "bad conversion");
				break;

			case _Codecvt::noconv:
				for (; _First != _Last; ++_First)
					_Bstr.append((_CSTD size_t)1,
						(char)(int_type)*_First);
				break;	// no conversion, just copy code values

			default:
				if (_Has_berr)
					return (_Berr);
				else
					_THROW(_STD range_error, "bad conversion");
				}
			}
		return (_Bstr);
		}

private:
	_Codecvt *_Pcvt;	// the codecvt facet
	_STD locale _Loc;	// manages reference to codecvt facet
	byte_string _Berr;
	wide_string _Werr;
	state_type _State;	// the remembered state
	bool _Has_state;
	bool _Has_berr;
	bool _Has_werr;
	size_t _Nconv;
	};
		}	// namespace cvt
	}	// namespace stdext
 #pragma warning(pop)
 #pragma pack(pop)

#endif /* RC_INVOKED */
#endif /* _CVT_WSTRING_ */

/*
 * Copyright (c) 1992-2009 by P.J. Plauger.  ALL RIGHTS RESERVED. 
 * Consult your license regarding permissions and restrictions.
V5.20:0009 */
