// xlocbuf internal header (from <locale>)
#pragma once
#ifndef _XLOCBUF_
#define _XLOCBUF_
#ifndef RC_INVOKED
#include <xlocale>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,3)
 #pragma push_macro("new")
 #undef new

 #pragma warning(disable: 6385)

_STD_BEGIN
		// TEMPLATE CLASS wbuffer_convert
template<class _Codecvt,
	class _Elem = wchar_t,
	class _Traits = char_traits<_Elem> >
	class wbuffer_convert
		: public basic_streambuf<_Elem, _Traits>
	{	// stream buffer associated with a codecvt facet
	enum _Mode {_Unused, _Wrote, _Need, _Got, _Eof};
	enum {_STRING_INC = 8};
public:
	typedef wbuffer_convert<_Codecvt, _Elem, _Traits> _Myt;
	typedef streambuf _Mysb;
	typedef char_traits<char> _Byte_traits;

	typedef typename _Traits::int_type int_type;
	typedef typename _Traits::pos_type pos_type;
	typedef typename _Traits::off_type off_type;
	typedef typename _Codecvt::state_type state_type;

	wbuffer_convert(_Mysb *_Strbuf = 0)
		: _Pcvt(new _Codecvt),
			_Mystrbuf(_Strbuf), _Status(_Unused), _Nback(0)
		{	// construct with byte stream buffer pointer
		static state_type _State0;

		_State = _State0;
		_Loc = locale(_Loc, _Pcvt);
		}

	wbuffer_convert(_Mysb *_Strbuf, const _Codecvt *_Pcvt_arg)
		: _Pcvt(_Pcvt_arg),
			_Mystrbuf(_Strbuf), _Status(_Unused), _Nback(0)
		{	// construct with byte stream buffer pointer and codecvt
		static state_type _State0;

		_State = _State0;
		_Loc = locale(_Loc, _Pcvt);
		}

	wbuffer_convert(_Mysb *_Strbuf,
		const _Codecvt *_Pcvt_arg, state_type _State_arg)
		: _Pcvt(_Pcvt_arg),
			_Mystrbuf(_Strbuf), _Status(_Unused), _Nback(0)
		{	// construct with byte stream buffer pointer, codecvt, and state
		_State = _State_arg;
		_Loc = locale(_Loc, _Pcvt);
		}

	virtual ~wbuffer_convert() _NOEXCEPT
		{	// destroy the object
		char *_Buf = (char *)_Str.c_str();

		for (; _Status == _Wrote ; )
			{	// put any trailing homing shift
			char *_Dest;

			if (_Str.size() < _STRING_INC)
				_Str.assign(_STRING_INC, '\0');
			switch (_Pcvt->unshift(_State,
				_Buf, _Buf + _Str.size(), _Dest))
				{	// test result of homing conversion
			case _Codecvt::ok:
				_Status = _Unused;	// homed successfully

			case _Codecvt::partial:	// fall through
				{	// put any generated bytes
				int _Count = (int)(_Dest - _Buf);
				if (0 < _Count
					&& _Byte_traits::eq_int_type(
						_Byte_traits::eof(),
						(_Byte_traits::int_type)_Mystrbuf->sputn(_Buf,
						_Count)))
					return;	// write failed

				if (_Status == _Wrote && _Count == 0)
					_Str.append(_STRING_INC, '\0');	// try with more space
				break;
				}

			case _Codecvt::noconv:
				return;	// nothing to do

			default:
				return;	// conversion failed
				}
			}
		}

	_Mysb *rdbuf() const
		{	// return byte stream buffer pointer
		return (_Mystrbuf);
		}

	_Mysb *rdbuf(_Mysb *_Strbuf)
		{	// set byte stream buffer pointer
		_Mysb *_Oldstrbuf = _Mystrbuf;
		_Mystrbuf = _Strbuf;
		return (_Oldstrbuf);
		}

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

	wbuffer_convert(const wbuffer_convert&) = delete;
	wbuffer_convert& operator=(const wbuffer_convert&) = delete;

protected:
	virtual int_type overflow(int_type _Meta = _Traits::eof())
		{	// put an element to stream
		if (_Traits::eq_int_type(_Traits::eof(), _Meta))
			return (_Traits::not_eof(_Meta));	// EOF, return success code
		else if (_Mystrbuf == 0 || 0 < _Nback
			|| (_Status != _Unused && _Status != _Wrote))
			return (_Traits::eof());	// no buffer or reading, fail
		else
			{	// put using codecvt facet
			char *_Buf = (char *)_Str.c_str();
			const _Elem _Ch = _Traits::to_char_type(_Meta);
			const _Elem *_Src;
			char *_Dest;

			if (_Str.size() < _STRING_INC)
				_Str.assign(_STRING_INC, '\0');
			for (_Status = _Wrote; ; )
				switch (_Pcvt->out(_State,
					&_Ch, &_Ch + 1, _Src,
					_Buf, _Buf + _Str.size(), _Dest))
				{	// test result of converting one element
				case _Codecvt::partial:
				case _Codecvt::ok:
					{	// converted something, try to put it out
					int _Count = (int)(_Dest - _Buf);
					if (0 < _Count
						&& _Byte_traits::eq_int_type(
							_Byte_traits::eof(),
							(_Byte_traits::int_type)_Mystrbuf->sputn(_Buf,
							_Count)))
						return (_Traits::eof());	// write failed

					if (_Src != &_Ch)
						return (_Meta);	// converted whole element

					if (0 < _Count)
						;
					else if (_Str.size() < 4 * _STRING_INC)
						_Str.append(_STRING_INC, '\0');	// try with more space
					else
						return (_Traits::eof());	// conversion failed
					break;
					}

				case _Codecvt::noconv:
					if (_Traits::eq_int_type(
						_Traits::eof(),
						(typename _Traits::int_type)_Mystrbuf->sputn(
							(char *)&_Ch,
							(streamsize)sizeof (_Elem))))
						return (_Traits::eof());
					else
						return (_Meta);	// put native byte order

				default:
					return (_Traits::eof());	// conversion failed
				}
			}
		}

	virtual int_type pbackfail(int_type _Meta = _Traits::eof())
		{	// put an element back to stream
		if (sizeof (_Myback) / sizeof (_Myback[0]) <= _Nback
			|| _Status == _Wrote)
			return (_Traits::eof());	// nowhere to put back
		else
			{	// enough room, put it back
			 if (!_Traits::eq_int_type(_Traits::eof(), _Meta))
				_Myback[_Nback] = _Traits::to_char_type(_Meta);
			++_Nback;
			if (_Status == _Unused)
				_Status = _Got;
			return (_Meta);
			}
		}

	virtual int_type underflow()
		{	// get an element from stream, but don't point past it
		int_type _Meta;

		if (0 < _Nback)
			;
		else if (_Traits::eq_int_type(_Traits::eof(), _Meta = _Get_elem()))
			return (_Meta);	// _Get_elem failed, return EOF
		else
			_Myback[_Nback++] = _Traits::to_char_type(_Meta);
		return (_Traits::to_int_type(_Myback[_Nback - 1]));
		}

	virtual int_type uflow()
		{	// get an element from stream, point past it
		int_type _Meta;

		if (0 < _Nback)
			;
		else if (_Traits::eq_int_type(_Traits::eof(), _Meta = _Get_elem()))
			return (_Meta);	// _Get_elem failed, return EOF
		else
			_Myback[_Nback++] = _Traits::to_char_type(_Meta);
		return (_Traits::to_int_type(_Myback[--_Nback]));
		}

	virtual pos_type seekoff(off_type,
		ios::seekdir,
		ios::openmode =
			(ios::openmode)(ios::in | ios::out))
		{	// change position by _Off
		return (pos_type(-1));	// always fail
		}

	virtual pos_type seekpos(pos_type,
		ios::openmode =
			(ios::openmode)(ios::in | ios::out))
		{	// change position to _Pos
		return (pos_type(-1));	// always fail
		}

private:
	int_type _Get_elem()
		{	// compose an element from byte stream buffer
		if (_Mystrbuf != 0 && _Status != _Wrote)
			{	// got buffer, haven't written, try to compose an element
			if (_Status == _Eof)
				;
			else if (_Str.size() == 0)
				_Status = _Need;
			else
				_Status = _Got;

			for (; _Status != _Eof; )
				{	// get using codecvt facet
				char *_Buf = (char *)_Str.c_str();
				_Elem _Ch, *_Dest;
				const char *_Src;
				int _Meta;

				if (_Status != _Need)
					;
				else if (_Byte_traits::eq_int_type(_Byte_traits::eof(),
					_Meta = _Mystrbuf->sbumpc()))
					_Status = _Eof;
				else
					_Str.append(1, _Byte_traits::to_char_type(_Meta));

				switch (_Pcvt->in(_State,
					_Buf, _Buf + _Str.size(), _Src,
					&_Ch, &_Ch + 1, _Dest))
					{	// test result of converting one element
				case _Codecvt::partial:
				case _Codecvt::ok:
					_Str.erase((size_t)0,	// discard any used input
						(size_t)(_Src - _Buf));
					if (_Dest != &_Ch)
						return (_Traits::to_int_type(_Ch));
					break;

				case _Codecvt::noconv:
					if (_Str.size() < sizeof (_Elem))
						break;	// no conversion, but need more chars
					_CSTD memcpy(&_Ch, _Buf,
						sizeof (_Elem));	// copy raw bytes to element
					_Str.erase((size_t)0, sizeof (_Elem));
					return (_Traits::to_int_type(_Ch));	// return result

				default:
					_Status = _Eof;	// conversion failed
					}
				}
			}

		return (_Traits::eof());
		}

	state_type _State;	// code conversion state
	const _Codecvt *_Pcvt;	// the codecvt facet
	_Mysb *_Mystrbuf;	// pointer to stream buffer
	_Mode _Status;		// buffer read/write status
	size_t _Nback;			// number of elements in putback buffer
	_Elem _Myback[8];	// putback buffer
	string _Str;	// unconsumed input bytes
	locale _Loc;	// manages reference to codecvt facet
	};

		// TEMPLATE CLASS wstring_convert
template<class _Codecvt,
	class _Elem = wchar_t,
	class _Walloc = allocator<_Elem>,
	class _Balloc = allocator<char> >
	class wstring_convert
	{	// converts between _Elem (wide) and char (byte) strings
	enum {_BUF_INC = 8, _BUF_MAX = 16};
	void _Init(const _Codecvt *_Pcvt_arg = new _Codecvt)
		{	// initialize the object
		static state_type _State0;
		_State = _State0;
		_Pcvt = _Pcvt_arg;
		_Loc = locale(_Loc, _Pcvt);
		_Nconv = 0;
		}

public:
	typedef basic_string<char, char_traits<char>, _Balloc> byte_string;
	typedef basic_string<_Elem, char_traits<_Elem>, _Walloc> 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(const _Codecvt *_Pcvt_arg)
		: _Has_berr(false), _Has_werr(false), _Has_state(false)
		{	// construct with no error strings and codecvt
		_Init(_Pcvt_arg);
		}

	wstring_convert(const _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() _NOEXCEPT
		{	// 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_NCEE(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_NCEE(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_NCEE(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_NCEE(range_error, "bad conversion");
				}
			}
		return (_Bstr);
		}

	wstring_convert(const wstring_convert&) = delete;
	wstring_convert& operator=(const wstring_convert&) = delete;

private:
	const _Codecvt *_Pcvt;	// the codecvt facet
	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;
	};
_STD_END
 #pragma pop_macro("new")
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _XLOCBUF_ */

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