📄 wbuffer
字号:
// wbuffer -- stream buffer for code conversions
#pragma once
#ifndef _CVT_WBUFFER_
#define _CVT_WBUFFER_
#ifndef RC_INVOKED
#include <streambuf>
#include <string>
#pragma pack(push,_CRT_PACKING)
#pragma warning(push,3)
/* Example: to convert from UCS to UTF-8 and write to cout
wbuffer_convert< codecvt_utf8<wchar_t> >
mybuf(cout.rdbuf()); // construct wide stream buffer object
wostream mywcout(&mybuf); // construct wide ostream object
mywcout << (wchar_t)0x80; // writes 0xc2 0x80
*/
namespace stdext {
namespace cvt {
// TEMPLATE CLASS wbuffer_convert
template<class _Codecvt,
class _Elem = wchar_t,
class _Traits = _STD char_traits<_Elem> >
class wbuffer_convert
: public _STD 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 _STD streambuf _Mysb;
typedef _STD 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 _Traits::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 = _STD _ADDFAC(_Loc, _Pcvt);
}
wbuffer_convert(_Mysb *_Strbuf, _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 = _STD _ADDFAC(_Loc, _Pcvt);
}
wbuffer_convert(_Mysb *_Strbuf,
_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 = _STD _ADDFAC(_Loc, _Pcvt);
}
virtual ~wbuffer_convert()
{ // 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
size_t _Count = _Dest - _Buf;
if (0 < _Count
&& _Byte_traits::eq_int_type(
_Byte_traits::eof(),
(typename _Traits::int_type)_Mystrbuf->sputn(
_Buf,
(_STD streamsize)_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);
}
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
size_t _Count = _Dest - _Buf;
if (0 < _Count
&& _Byte_traits::eq_int_type(
_Byte_traits::eof(),
(typename _Traits::int_type)_Mystrbuf->sputn(
_Buf,
(_STD streamsize)_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,
(_STD 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,
_STD ios::seekdir,
_STD ios::openmode =
(_STD ios::openmode)(_STD ios::in | _STD ios::out))
{ // change position by _Off
return (pos_type(-1)); // always fail
}
virtual pos_type seekpos(pos_type,
_STD ios::openmode =
(_STD ios::openmode)(_STD ios::in | _STD 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
_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
_STD string _Str; // unconsumed input bytes
_STD locale _Loc; // manages reference to codecvt facet
};
} // namespace cvt
} // namespace stdext
#pragma warning(pop)
#pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _CVT_WBUFFER_ */
/*
* Copyright (c) 1992-2009 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
V5.20:0009 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -