You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
754 lines
25 KiB
754 lines
25 KiB
// -*- C++ -*-
|
|
/***************************************************************************
|
|
*
|
|
* fstream.cc - Definition for the Standard Library file streams
|
|
*
|
|
* $Id: fstream.cc 172106 2011-11-02 17:04:12Z statham $
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* Copyright (c) 1994-2001 Rogue Wave Software, Inc. All Rights Reserved.
|
|
*
|
|
* This computer software is owned by Rogue Wave Software, Inc. and is
|
|
* protected by U.S. copyright laws and other laws and by international
|
|
* treaties. This computer software is furnished by Rogue Wave Software,
|
|
* Inc. pursuant to a written license agreement and may be used, copied,
|
|
* transmitted, and stored only in accordance with the terms of such
|
|
* license and with the inclusion of the above copyright notice. This
|
|
* computer software or any other copies thereof may not be provided or
|
|
* otherwise made available to any other person.
|
|
*
|
|
* U.S. Government Restricted Rights. This computer software is provided
|
|
* with Restricted Rights. Use, duplication, or disclosure by the
|
|
* Government is subject to restrictions as set forth in subparagraph (c)
|
|
* (1) (ii) of The Rights in Technical Data and Computer Software clause
|
|
* at DFARS 252.227-7013 or subparagraphs (c) (1) and (2) of the
|
|
* Commercial Computer Software--Restricted Rights at 48 CFR 52.227-19,
|
|
* as applicable. Manufacturer is Rogue Wave Software, Inc., 5500
|
|
* Flatiron Parkway, Boulder, Colorado 80301 USA.
|
|
*
|
|
**************************************************************************/
|
|
|
|
_RWSTD_NAMESPACE_BEGIN (std)
|
|
|
|
template<class _CharT, class _Traits>
|
|
basic_filebuf<_CharT, _Traits>*
|
|
basic_filebuf<_CharT, _Traits>::
|
|
open (const char *__name, ios_base::openmode __mode, long __prot)
|
|
{
|
|
_RWSTD_ASSERT (0 != __name);
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (is_open ())
|
|
return 0;
|
|
|
|
this->_C_iomode = __mode;
|
|
|
|
_C_file._C_open (__name, __mode & ~ios_base::ate, __prot);
|
|
|
|
if (!is_open ())
|
|
return 0;
|
|
|
|
this->setg (0, 0, 0);
|
|
this->setp (0, 0);
|
|
|
|
if (__mode & ios_base::ate) {
|
|
if ((_C_cur_pos = _C_beg_pos = _C_file_seek (0, ios_base::end))
|
|
== _RWSTD_INVALID_FPOS) {
|
|
close ();
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
_C_cur_pos = _C_beg_pos = pos_type();
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
basic_filebuf<_CharT, _Traits>*
|
|
basic_filebuf<_CharT, _Traits>::close ()
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!is_open ())
|
|
return 0; // failure
|
|
|
|
// avoid expensive call to overflow() unless necessary
|
|
if (this->pptr () != this->pbase () && this->_C_is_eof (overflow ()))
|
|
return 0; // failure
|
|
|
|
// write out any unshift sequence if necessary
|
|
// (applies to multibyte, state dependent encodings only)
|
|
if (this->_C_out_last () && !_C_unshift ())
|
|
return 0; // failure
|
|
|
|
_C_cur_pos = _C_beg_pos = _RWSTD_INVALID_FPOS;
|
|
|
|
this->setg (0, 0, 0);
|
|
this->setp (0, 0);
|
|
|
|
if (!_C_file._C_is_std () && !_C_file._C_close ())
|
|
return 0; // failure
|
|
|
|
_C_file = _RWSTD_INVALID_FILE;
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
streamsize
|
|
basic_filebuf<_CharT, _Traits>::showmanyc ()
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!this->_C_is_in () || !is_open () || _C_cur_pos == _RWSTD_INVALID_FPOS)
|
|
return -1;
|
|
|
|
// start with the number of chars in get area
|
|
streamsize __retval = this->egptr () - this->gptr ();
|
|
|
|
// no prob if this fails for non-seekable devices
|
|
pos_type __end_pos = _C_file_seek (0, ios_base::end);
|
|
|
|
if (__end_pos != _RWSTD_INVALID_FPOS) {
|
|
|
|
// restore position within file only if seek succeeded
|
|
_C_file_seek (_C_cur_pos, ios_base::beg);
|
|
|
|
const _C_codecvt_t &__cvt =
|
|
_USE_FACET (_C_codecvt_t, this->getloc ());
|
|
|
|
if (__cvt.always_noconv ())
|
|
__retval += __end_pos - _C_cur_pos;
|
|
else
|
|
// make most pessimistic conversion estimate
|
|
__retval += (__end_pos - _C_cur_pos) / __cvt.max_length ();
|
|
}
|
|
|
|
return __retval > 0 ? __retval : 0;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::int_type
|
|
basic_filebuf<_CharT, _Traits>::uflow ()
|
|
{
|
|
int_type __c = underflow ();
|
|
|
|
if (!this->_C_is_eof(__c))
|
|
this->gbump (1);
|
|
|
|
return __c;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::int_type
|
|
basic_filebuf<_CharT, _Traits>::underflow ()
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
this->setp (0, 0); // invalidate put area
|
|
|
|
this->_C_out_last (false); // needed by close ()
|
|
|
|
if (!this->_C_is_in () || !is_open())
|
|
return traits_type::eof ();
|
|
|
|
char_type* const __to_end = this->_C_buffer + this->_C_bufsize;
|
|
|
|
// fill the buffer if it's empty
|
|
|
|
if (this->gptr () == this->egptr()) { // N.B.: gptr() could be null here
|
|
|
|
// determine the maximum possible size of putback area (if any)
|
|
// make sure putback area isn't too big - try to honor
|
|
// _RWSTD_PBACK_SIZE if possible, otherwise shrink
|
|
|
|
_C_pbacksize = min (this->_C_putback_avail (),
|
|
_RWSTD_PBACK_SIZE);
|
|
|
|
_RWSTD_ASSERT (0 != this->_C_bufsize);
|
|
|
|
if (_C_pbacksize == this->_C_bufsize)
|
|
_C_pbacksize = this->_C_bufsize - 1;
|
|
|
|
traits_type::move (this->eback(), this->gptr () - _C_pbacksize,
|
|
_C_pbacksize);
|
|
|
|
// fill the get area from the file, performing code conversion if
|
|
// necessary
|
|
|
|
streamsize __nread = 0; // number of bytes read from file
|
|
|
|
_C_beg_pos = _C_cur_pos;
|
|
|
|
const _C_codecvt_t &__cvt = _USE_FACET (_C_codecvt_t, this->getloc ());
|
|
|
|
if (__cvt.always_noconv ()) {
|
|
// no conversion required
|
|
__nread = (__to_end - this->_C_buffer) - _C_pbacksize;
|
|
__nread = _C_file._C_read (this->_C_buffer + _C_pbacksize,
|
|
sizeof (char_type), __nread);
|
|
if (__nread < 0)
|
|
return traits_type::eof (); // error while reading
|
|
|
|
this->setg (this->_C_buffer,
|
|
this->_C_buffer + _C_pbacksize,
|
|
this->_C_buffer + _C_pbacksize + __nread);
|
|
|
|
// adjust the current position in the file,
|
|
// taking into account CR/LF conversion on windows
|
|
__nread += _C_crlf_intern_count (this->gptr (),
|
|
this->gptr () + __nread);
|
|
}
|
|
else { // conversion required
|
|
|
|
char __xbuf[_RWSTD_DEFAULT_BUFSIZE];
|
|
char* __from_base = __xbuf;
|
|
const char* __from_next = 0;
|
|
char_type* __to_base = this->_C_buffer + _C_pbacksize;
|
|
char_type* __to_next = __to_base;
|
|
|
|
state_type __state = _C_cur_pos.state ();
|
|
|
|
codecvt_base::result __res = codecvt_base::ok;
|
|
|
|
while (__to_next != __to_end) {
|
|
|
|
// read only as many characters as we have positions left in
|
|
// internal buffer - guarantees we won't read more characters
|
|
// than we can put into the internal buffer after conversion
|
|
// and ending file position isn't in the middle of a shift
|
|
// sequence
|
|
// N.B.: area between __xbuf and __from_base contains partially
|
|
// converted sequences left from previous read
|
|
streamsize __n =
|
|
min (ptrdiff_t (__to_end - __to_next),
|
|
ptrdiff_t (sizeof __xbuf - (__from_base - __xbuf)));
|
|
|
|
__n = _C_file._C_read (__from_base, sizeof (char), __n);
|
|
|
|
if (0 > __n)
|
|
return traits_type::eof (); // error while reading
|
|
|
|
if (0 == __n)
|
|
break; // reached eof
|
|
|
|
// take into account CR/LF conversion on Win32
|
|
__nread += __n +
|
|
_C_crlf_extern_count (__from_base, __from_base + __n);
|
|
|
|
// adjust `n' to hold the number of external chars in buffer
|
|
__n += __from_base - __xbuf;
|
|
|
|
// convert any partially converted sequence from the previous
|
|
// iteration (possibly empty) plus what we just read in
|
|
__res = __cvt.in (__state, __xbuf, __xbuf + __n, __from_next,
|
|
__to_base, __to_end, __to_next);
|
|
|
|
if (codecvt_base::partial == __res) {
|
|
// compute the length of partially converted sequence
|
|
__n -= __from_next - __xbuf;
|
|
|
|
// copy the sequence to beginning of xbuf
|
|
memmove (__xbuf, __from_next, __n);
|
|
|
|
// will append external chars to end of the sequence
|
|
__from_base = __xbuf + __n;
|
|
}
|
|
else if (codecvt_base::ok == __res)
|
|
__from_base = __xbuf;
|
|
else // codecvt_base::error
|
|
return traits_type::eof ();
|
|
|
|
__to_base = __to_next; // continue at end of converted seq
|
|
}
|
|
|
|
_RWSTD_ASSERT (codecvt_base::ok == __res);
|
|
|
|
_C_cur_pos.state (__state);
|
|
|
|
this->setg (this->_C_buffer, this->_C_buffer + _C_pbacksize,
|
|
__to_next);
|
|
} // end conversion block
|
|
|
|
if (__nread == 0)
|
|
return traits_type::eof ();
|
|
|
|
_C_cur_pos += __nread;
|
|
}
|
|
|
|
return traits_type::to_int_type (*this->gptr ());
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::int_type
|
|
basic_filebuf<_CharT, _Traits>::overflow (int_type __c /* = eof () */)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
this->setg (0, 0, 0); // invalidate the get area
|
|
|
|
if (!this->_C_is_out () || !is_open())
|
|
return traits_type::eof ();
|
|
|
|
char_type* __from_beg; // pointer to start of sequence to write
|
|
char_type* __from_end; // pointer to end of sequence to write
|
|
char_type __c_to_char; // input arg converted to char_type
|
|
// (used only in unbuffered mode)
|
|
|
|
if (this->_C_is_unbuffered ()) {
|
|
__c_to_char = traits_type::to_char_type(__c);
|
|
__from_beg = &__c_to_char;
|
|
__from_end = __from_beg + 1;
|
|
}
|
|
else {
|
|
__from_beg = this->_C_buffer;
|
|
__from_end = this->pptr ();
|
|
}
|
|
|
|
if (this->pptr () == 0 && !this->_C_is_unbuffered ()) {
|
|
// put area not valid yet - just need to initialize it
|
|
this->setp (this->_C_buffer, this->_C_buf_end ());
|
|
}
|
|
else if ( this->pptr () == this->epptr ()
|
|
|| this->_C_is_eof (__c)
|
|
|| this->_C_is_unbuffered ()) {
|
|
|
|
// flush put area to file,
|
|
// performing code conversion if necessary
|
|
|
|
streamsize __nwrote = 0; // num chars to write
|
|
state_type __state = _C_cur_pos.state (); // state of stream
|
|
|
|
// N.B. the sentry constructed by the ostream currently
|
|
// seeks to the end of the file when in append mode
|
|
// but we're going to seek anyway because the user
|
|
// can manipulate the buffer directly
|
|
if (this->_C_iomode & ios_base::app)
|
|
_C_cur_pos = _C_file_seek (0, ios_base::end);
|
|
|
|
_C_beg_pos = _C_cur_pos;
|
|
|
|
const _C_codecvt_t &__cvt = _USE_FACET (_C_codecvt_t, this->getloc ());
|
|
|
|
if (__cvt.always_noconv ()) {
|
|
|
|
// no conversion
|
|
|
|
__nwrote = __from_end - __from_beg;;
|
|
|
|
if (!_C_file._C_write (__from_beg, sizeof (char_type), __nwrote))
|
|
return traits_type::eof (); // error while writing
|
|
}
|
|
|
|
else {
|
|
|
|
// conversion required: we do this a chunk at a time
|
|
// to avoid dynamic allocation of memory
|
|
|
|
char __xbuf[_RWSTD_DEFAULT_BUFSIZE];
|
|
char* __xbuf_end = __xbuf + sizeof __xbuf;
|
|
char* __to_next = 0;
|
|
const char_type* __from_next = 0;
|
|
const char_type* __base = __from_beg;
|
|
|
|
while (__from_next != __from_end) {
|
|
codecvt_base::result __res =
|
|
__cvt.out (__state, __base, __from_end, __from_next,
|
|
__xbuf, __xbuf_end, __to_next);
|
|
if ( __res == codecvt_base::error
|
|
|| ! _C_file._C_write (__xbuf, sizeof (char),
|
|
__to_next - __xbuf))
|
|
return traits_type::eof ();
|
|
// N.B. a partial conversion will result if there's
|
|
// not enough space in the conversion buffer
|
|
// to hold the converted sequence, but we're o.k.
|
|
// since we'll be passing any remaining unconverted
|
|
// characters (starting at __from_next) in the next iteration
|
|
|
|
// __res is ok or partial
|
|
__nwrote += __to_next - __xbuf +
|
|
_C_crlf_extern_count (__xbuf, __to_next);
|
|
|
|
__base = __from_next; // do the next chunk
|
|
}
|
|
} // end conversion block
|
|
|
|
// adjust the current position in the file
|
|
_C_cur_pos += __nwrote;
|
|
_C_cur_pos.state (__state);
|
|
|
|
// reset the put area
|
|
if (!this->_C_is_unbuffered ())
|
|
this->setp (this->_C_buffer, this->_C_buf_end ());
|
|
}
|
|
|
|
// now that there's room in the buffer, call sputc() recursively
|
|
// to actually place the character in the buffer (unless we're
|
|
// in unbuffered mode because we just wrote it out)
|
|
if (!this->_C_is_eof (__c) && !this->_C_is_unbuffered ())
|
|
this->sputc (__c);
|
|
|
|
this->_C_out_last (true); // needed by close ()
|
|
|
|
return traits_type::not_eof (__c);
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::int_type
|
|
basic_filebuf<_CharT, _Traits>::pbackfail (int_type __c)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!is_open ())
|
|
return traits_type::eof ();
|
|
|
|
// we could get here if gptr = eback or if __c != *(gptr-1)
|
|
if (!this->_C_putback_avail ()) {
|
|
// try to make a putback area available
|
|
|
|
if (this->seekoff (-1, ios_base::cur) == _RWSTD_INVALID_FPOS)
|
|
return traits_type::eof ();
|
|
|
|
if (this->_C_is_eof (underflow ()))
|
|
return traits_type::eof ();
|
|
|
|
this->gbump (1);
|
|
}
|
|
|
|
if (traits_type::eq (traits_type::to_char_type (__c), *(this->gptr () - 1))
|
|
|| this->_C_is_eof (__c)) {
|
|
// "put back" original value
|
|
this->gbump (-1);
|
|
return traits_type::not_eof (__c);
|
|
}
|
|
else if (this->_C_is_out ()) {
|
|
// overwrite existing value with new value
|
|
this->gbump (-1);
|
|
*this->gptr () = traits_type::to_char_type (__c);
|
|
return __c;
|
|
}
|
|
else
|
|
return traits_type::eof ();
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
basic_streambuf<_CharT, _Traits>*
|
|
basic_filebuf<_CharT, _Traits>::setbuf (char_type *__buf, streamsize __len)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
// sync the buffer to the external file so it can be deallocated
|
|
if (sync () != 0)
|
|
return 0;
|
|
|
|
bool __own_old_buf = this->_C_own_buf ();
|
|
|
|
if (__len > 0) {
|
|
// replace the buffer...
|
|
if (__buf == 0) {
|
|
// ...newly allocated buffer...
|
|
__buf = new char_type[__len]; // try to allocate before deleting
|
|
this->_C_own_buf (true);
|
|
}
|
|
else
|
|
// ...or with supplied buffer
|
|
this->_C_own_buf (false);
|
|
|
|
if (__own_old_buf)
|
|
delete [] this->_C_buffer;
|
|
|
|
this->_C_buffer = __buf;
|
|
this->_C_bufsize = __len;
|
|
this->_C_set_unbuffered (false);
|
|
}
|
|
|
|
else {
|
|
// unbuffer this stream
|
|
if (__buf != 0) // invalid input (__len == 0 => __buf == 0)
|
|
return 0;
|
|
|
|
// character buffer is preserved (used as get area only),
|
|
// streambuf object unbuffered for writing
|
|
|
|
// to put a streambuf object into an unbuffered mode (see 27.8.1.4,
|
|
// p10) and affect the size of the get area, setbuf() should first
|
|
// be called with the desired (non-zero) size and then again with
|
|
// both arguments being 0
|
|
this->_C_set_unbuffered (true);
|
|
}
|
|
|
|
this->setg (0, 0, 0);
|
|
this->setp (0, 0);
|
|
|
|
// a character buffer of nonzero size must exist
|
|
// even in unbuffered mode
|
|
_RWSTD_ASSERT (0 != this->_C_buffer);
|
|
_RWSTD_ASSERT (0 != this->_C_bufsize);
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
// 27.8.1.4, p 11
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::pos_type
|
|
basic_filebuf<_CharT, _Traits>::
|
|
seekoff (off_type __off, ios_base::seekdir __way, ios_base::openmode)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!is_open ())
|
|
return _RWSTD_INVALID_FPOS;
|
|
|
|
int __width = _USE_FACET (_C_codecvt_t, this->getloc ()).encoding ();
|
|
|
|
// offset must be zero with multibyte encoding
|
|
if (0 != __off && __width <= 0)
|
|
return _RWSTD_INVALID_FPOS;
|
|
|
|
// sync the buffer... (this also invalidates the get/put area)
|
|
if (sync () != 0)
|
|
return _RWSTD_INVALID_FPOS;
|
|
|
|
// ...and, if last op was output, append an unshift sequence
|
|
if (this->_C_out_last ())
|
|
_C_unshift ();
|
|
|
|
// perform the seek
|
|
pos_type __new_pos;
|
|
if (__width > 0)
|
|
__new_pos = _C_file_seek (__width * __off, __way);
|
|
else
|
|
__new_pos = _C_file_seek (0, __way);
|
|
|
|
if (__new_pos != _RWSTD_INVALID_FPOS)
|
|
_C_cur_pos = _C_beg_pos = __new_pos;
|
|
|
|
this->_C_out_last (false); // needed by close()
|
|
|
|
return __new_pos;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
_TYPENAME basic_filebuf<_CharT, _Traits>::pos_type
|
|
basic_filebuf<_CharT, _Traits>::seekpos (pos_type __pos, ios_base::openmode)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!is_open ())
|
|
return _RWSTD_INVALID_FPOS;
|
|
|
|
// flush the output area if it exists
|
|
if (this->pptr () != 0) {
|
|
if (this->_C_is_eof (this->overflow (traits_type::eof ())))
|
|
return _RWSTD_INVALID_FPOS;
|
|
}
|
|
|
|
if (_C_file_seek (__pos, ios_base::beg) == _RWSTD_INVALID_FPOS)
|
|
return _RWSTD_INVALID_FPOS;
|
|
|
|
_C_cur_pos = _C_beg_pos = __pos;
|
|
|
|
this->setg (0, 0, 0);
|
|
this->setp (0, 0);
|
|
|
|
this->_C_out_last (false); // needed by close()
|
|
|
|
return __pos;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
int
|
|
basic_filebuf<_CharT, _Traits>::sync ()
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
// put area active
|
|
if (this->pptr () != 0) {
|
|
// flush the buffer to the file
|
|
if (this->_C_is_eof (overflow (traits_type::eof ())))
|
|
return -1;
|
|
}
|
|
|
|
// get area active
|
|
if (this->gptr () != 0) {
|
|
// get the number of chars consumed in the buffer
|
|
streamoff __consumed = (this->gptr () - this->eback ()) - _C_pbacksize;
|
|
|
|
const _C_codecvt_t &__cvt = _USE_FACET (_C_codecvt_t, this->getloc ());
|
|
int __width = __cvt.encoding ();
|
|
|
|
if (__width > 0) {
|
|
// constant width conversion:
|
|
// adjust the current position/state in the file,
|
|
// taking into account CR/LF conversion on Win32
|
|
_C_cur_pos = _C_beg_pos;
|
|
_C_cur_pos += (__width * __consumed)
|
|
+ _C_crlf_intern_count (this->eback () + _C_pbacksize,
|
|
this->gptr());
|
|
}
|
|
else {
|
|
// This gets a bit tricky here because we don't know the external
|
|
// file position corresponding to the position in the
|
|
// internal buffer. To figure this out, we'll use the known
|
|
// file position/state corresponding to the start of the buffer
|
|
// (which we have carefully saved in _C_beg_pos) and
|
|
// convert the characters up to the current position in the
|
|
// buffer, counting how many external chars result. We can
|
|
// then use the offset from _C_beg_pos and the state
|
|
// returned from codecvt::out() to construct the current file
|
|
// position
|
|
|
|
streamoff __ext_chars = 0; // converted external chars
|
|
|
|
char __xbuf[_RWSTD_DEFAULT_BUFSIZE];
|
|
char* __xbuf_end = __xbuf + sizeof __xbuf;
|
|
char* __to_next = 0;
|
|
const char_type* __from_next = 0;
|
|
const char_type* __from_end = this->gptr ();
|
|
state_type __state = _C_beg_pos.state ();
|
|
const char_type* __base = this->eback () + _C_pbacksize;
|
|
|
|
while (__from_next != __from_end) {
|
|
codecvt_base::result __res =
|
|
__cvt.out (__state, __base, __from_end, __from_next,
|
|
__xbuf, __xbuf_end, __to_next);
|
|
if (__res == codecvt_base::error)
|
|
return -1;
|
|
|
|
// take into account CR/LF conversion on Win32
|
|
__ext_chars += (__to_next - __xbuf) +
|
|
_C_crlf_extern_count (__xbuf, __to_next);
|
|
|
|
// repeat with next chunk
|
|
__base = __from_next;
|
|
}
|
|
|
|
_C_cur_pos = _C_beg_pos + __ext_chars;
|
|
_C_cur_pos.state (__state);
|
|
}
|
|
if (_C_file_seek (_C_cur_pos, ios_base::beg) == _RWSTD_INVALID_FPOS)
|
|
return -1;
|
|
|
|
traits_type::move (this->eback(), this->gptr () - _C_pbacksize,
|
|
_C_pbacksize);
|
|
|
|
this->setg (this->eback(), this->eback() + _C_pbacksize,
|
|
this->eback() + _C_pbacksize);
|
|
}
|
|
|
|
_C_beg_pos = _C_cur_pos;
|
|
|
|
this->setp (0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
streamsize
|
|
basic_filebuf<_CharT, _Traits>::xsputn (const char_type* __s, streamsize __len)
|
|
{
|
|
_RWSTD_ASSERT (this->_C_is_valid ());
|
|
|
|
if (!__s || (__len == 0) || !this->_C_is_out ())
|
|
return 0;
|
|
|
|
if (this->pptr () != 0 && (this->pptr () + __len) < this->epptr ()) {
|
|
traits_type::copy (this->pptr (), __s, __len);
|
|
this->pbump (int(__len));
|
|
}
|
|
else {
|
|
for (streamsize __n = 0; __n < __len; ++__n) {
|
|
if (this->_C_is_eof (this->sputc (*__s++)))
|
|
return __n;
|
|
}
|
|
}
|
|
return __len;
|
|
}
|
|
|
|
|
|
template<class _CharT, class _Traits>
|
|
basic_filebuf<_CharT, _Traits>*
|
|
basic_filebuf<_CharT, _Traits>::_C_open (_RW::__rw_file_t __frep,
|
|
char_type *__buf,
|
|
streamsize __n)
|
|
{
|
|
if (is_open () || !setbuf (__buf,__n) || !__frep._C_is_open ())
|
|
return 0;
|
|
|
|
_C_file = __frep;
|
|
|
|
this->_C_iomode = _C_file._C_get_mode ();
|
|
|
|
this->setg (0, 0, 0);
|
|
this->setp (0, 0);
|
|
|
|
_C_cur_pos = _C_beg_pos = pos_type(); // offset == 0, state = state()
|
|
|
|
return this;
|
|
}
|
|
|
|
|
|
// write an unshift sequence if not in initial state
|
|
// N.B.: this is a no-op unless the stream is imbued with user-defined
|
|
// locale/facet because the default implementations of unshift()
|
|
// always return noconv
|
|
// returns: true on success
|
|
|
|
template<class _CharT, class _Traits>
|
|
bool
|
|
basic_filebuf<_CharT, _Traits>::_C_unshift ()
|
|
{
|
|
// unshifting isn't necessary if encoding isn't state dependent or
|
|
// if state is equivalent to initial state (determined by mbsinit())
|
|
state_type __state = _C_cur_pos.state ();
|
|
if ( _USE_FACET (_C_codecvt_t, this->getloc ()).encoding () >= 0
|
|
|| _MBSINIT (&__state) != 0)
|
|
return true;
|
|
|
|
// buf to hold unshift sequence - assumes that the shift
|
|
// sequence will be less than 64 chars (we can't safely
|
|
// use dynamic allocation because _C_unshift
|
|
// could be called as a result of memory alloc exception)
|
|
|
|
char __useq[64];
|
|
char* __useq_end = 0;
|
|
|
|
codecvt_base::result __res =
|
|
_USE_FACET (_C_codecvt_t, this->getloc ()).unshift (
|
|
__state, __useq, __useq + sizeof __useq,
|
|
__useq_end);
|
|
|
|
streamoff __nbytes = __useq_end - __useq;
|
|
|
|
// in the unlikely event that the buffer isn't big enough, assert
|
|
_RWSTD_ASSERT(__res != codecvt_base::partial);
|
|
|
|
if (__res == codecvt_base::error)
|
|
return false;
|
|
if (__res == codecvt_base::noconv)
|
|
return true;
|
|
|
|
if (_C_file._C_write (__useq, sizeof (char), __nbytes))
|
|
return false;
|
|
|
|
_C_cur_pos += __nbytes; // CR/LF conversion not an issue here
|
|
|
|
return true;
|
|
}
|
|
|
|
_RWSTD_NAMESPACE_END // std
|
|
|