summaryrefslogtreecommitdiffstats
path: root/libcxx/include/fstream
diff options
context:
space:
mode:
authorHoward Hinnant <hhinnant@apple.com>2012-08-24 21:20:56 +0000
committerHoward Hinnant <hhinnant@apple.com>2012-08-24 21:20:56 +0000
commitbfd96e11edfc80662967401f62f5955e3deca17d (patch)
treece779b3910c3af1309dac1064e29aeff35cf7ebc /libcxx/include/fstream
parent5eb99ccd3e5f7dcf4da17072503995f723f81ec9 (diff)
downloadbcm5719-llvm-bfd96e11edfc80662967401f62f5955e3deca17d.tar.gz
bcm5719-llvm-bfd96e11edfc80662967401f62f5955e3deca17d.zip
Hyeon-Bin Jeong: 1. sync() should reset it’s external buffer pointers.
Remaining characters should be discarded once sync() called. If don’t, garbage characters can be inserted to the front of external buffer in underflow(). Because underflow() copies remaining characters in external buffer to it’s front. This results wrong characters insertion when seekpos() or seekoff() is called. this line should be inserted in sync() just before return: __extbufnext_ = __extbufend_ = __extbuf_; 2. sync() should use length() rather than out() to calculate offset. Reversing iterators and calling out() to calculate offset from behind is working fine in stateless character encoding. However, in stateful encoding, escape sequences could differ in length. As a result, out() could return wrong length. For example, if we have internal buffer converted from this external sequence: (capital letters mean escape sequence) … a a a a B b b b b out() produces this sequence. b b b b A a a a a Because out() inserts escape sequence A rather than B, result sequence doesn't match to external sequence. A and B could have different lengths, result offset could be wrong value too. length() method in codecvt is right for calculating offset, but it counts offset from the beginning of buffer. So it requires another state member variable to hold state before conversion. Fixes http://llvm.org/bugs/show_bug.cgi?id=13667 llvm-svn: 162601
Diffstat (limited to 'libcxx/include/fstream')
-rw-r--r--libcxx/include/fstream40
1 files changed, 17 insertions, 23 deletions
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index aa78d85f3d6..7b6578f1e57 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -234,6 +234,7 @@ private:
FILE* __file_;
const codecvt<char_type, char, state_type>* __cv_;
state_type __st_;
+ state_type __st_last_;
ios_base::openmode __om_;
ios_base::openmode __cm_;
bool __owns_eb_;
@@ -255,6 +256,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf()
__file_(0),
__cv_(nullptr),
__st_(),
+ __st_last_(),
__om_(0),
__cm_(0),
__owns_eb_(false),
@@ -293,6 +295,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf(basic_filebuf&& __rhs)
__file_ = __rhs.__file_;
__cv_ = __rhs.__cv_;
__st_ = __rhs.__st_;
+ __st_last_ = __rhs.__st_last_;
__om_ = __rhs.__om_;
__cm_ = __rhs.__cm_;
__owns_eb_ = __rhs.__owns_eb_;
@@ -325,6 +328,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf(basic_filebuf&& __rhs)
__rhs.__ibs_ = 0;
__rhs.__file_ = 0;
__rhs.__st_ = state_type();
+ __rhs.__st_last_ = state_type();
__rhs.__om_ = 0;
__rhs.__cm_ = 0;
__rhs.__owns_eb_ = false;
@@ -402,6 +406,7 @@ basic_filebuf<_CharT, _Traits>::swap(basic_filebuf& __rhs)
_VSTD::swap(__file_, __rhs.__file_);
_VSTD::swap(__cv_, __rhs.__cv_);
_VSTD::swap(__st_, __rhs.__st_);
+ _VSTD::swap(__st_last_, __rhs.__st_last_);
_VSTD::swap(__om_, __rhs.__om_);
_VSTD::swap(__cm_, __rhs.__cm_);
_VSTD::swap(__owns_eb_, __rhs.__owns_eb_);
@@ -599,7 +604,7 @@ basic_filebuf<_CharT, _Traits>::underflow()
size_t __nmemb = _VSTD::min(static_cast<size_t>(__ibs_ - __unget_sz),
static_cast<size_t>(__extbufend_ - __extbufnext_));
codecvt_base::result __r;
- state_type __svs = __st_;
+ __st_last_ = __st_;
size_t __nr = fread((void*)__extbufnext_, 1, __nmemb, __file_);
if (__nr != 0)
{
@@ -816,7 +821,7 @@ basic_filebuf<_CharT, _Traits>::seekpos(pos_type __sp, ios_base::openmode)
return pos_type(off_type(-1));
if (fseeko(__file_, __sp, SEEK_SET))
return pos_type(off_type(-1));
- __st_ = __sp.state;
+ __st_ = __sp.state();
return __sp;
}
@@ -852,6 +857,8 @@ basic_filebuf<_CharT, _Traits>::sync()
else if (__cm_ & ios_base::in)
{
off_type __c;
+ state_type __state = __st_last_;
+ bool __update_st = false;
if (__always_noconv_)
__c = this->egptr() - this->gptr();
else
@@ -864,32 +871,19 @@ basic_filebuf<_CharT, _Traits>::sync()
{
if (this->gptr() != this->egptr())
{
- reverse(this->gptr(), this->egptr());
- codecvt_base::result __r;
- const char_type* __e = this->gptr();
- char* __extbe;
- do
- {
- __r = __cv_->out(__st_, __e, this->egptr(), __e,
- __extbuf_, __extbuf_ + __ebs_, __extbe);
- switch (__r)
- {
- case codecvt_base::noconv:
- __c += this->egptr() - this->gptr();
- break;
- case codecvt_base::ok:
- case codecvt_base::partial:
- __c += __extbe - __extbuf_;
- break;
- default:
- return -1;
- }
- } while (__r == codecvt_base::partial);
+ const int __off = __cv_->length(__state, __extbuf_,
+ __extbufnext_,
+ this->gptr() - this->eback());
+ __c += __extbufnext_ - __extbuf_ - __off;
+ __update_st = true;
}
}
}
if (fseeko(__file_, -__c, SEEK_CUR))
return -1;
+ if (__update_st)
+ __st_ = __state;
+ __extbufnext_ = __extbufend_ = __extbuf_;
this->setg(0, 0, 0);
__cm_ = 0;
}
OpenPOWER on IntegriCloud