Path: blob/main/contrib/llvm-project/libcxx/include/__locale_dir/wbuffer_convert.h
213766 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#ifndef _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H9#define _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H1011#include <__algorithm/reverse.h>12#include <__config>13#include <__string/char_traits.h>14#include <ios>15#include <streambuf>1617#if _LIBCPP_HAS_LOCALIZATION1819# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)20# pragma GCC system_header21# endif2223# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)2425_LIBCPP_PUSH_MACROS26# include <__undef_macros>2728_LIBCPP_BEGIN_NAMESPACE_STD2930template <class _Codecvt, class _Elem = wchar_t, class _Tr = char_traits<_Elem> >31class _LIBCPP_DEPRECATED_IN_CXX17 wbuffer_convert : public basic_streambuf<_Elem, _Tr> {32public:33// types:34typedef _Elem char_type;35typedef _Tr traits_type;36typedef typename traits_type::int_type int_type;37typedef typename traits_type::pos_type pos_type;38typedef typename traits_type::off_type off_type;39typedef typename _Codecvt::state_type state_type;4041private:42char* __extbuf_;43const char* __extbufnext_;44const char* __extbufend_;45char __extbuf_min_[8];46size_t __ebs_;47char_type* __intbuf_;48size_t __ibs_;49streambuf* __bufptr_;50_Codecvt* __cv_;51state_type __st_;52ios_base::openmode __cm_;53bool __owns_eb_;54bool __owns_ib_;55bool __always_noconv_;5657public:58# ifndef _LIBCPP_CXX03_LANG59_LIBCPP_HIDE_FROM_ABI wbuffer_convert() : wbuffer_convert(nullptr) {}60explicit _LIBCPP_HIDE_FROM_ABI61wbuffer_convert(streambuf* __bytebuf, _Codecvt* __pcvt = new _Codecvt, state_type __state = state_type());62# else63_LIBCPP_EXPLICIT_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI64wbuffer_convert(streambuf* __bytebuf = nullptr, _Codecvt* __pcvt = new _Codecvt, state_type __state = state_type());65# endif6667_LIBCPP_HIDE_FROM_ABI ~wbuffer_convert();6869_LIBCPP_HIDE_FROM_ABI streambuf* rdbuf() const { return __bufptr_; }70_LIBCPP_HIDE_FROM_ABI streambuf* rdbuf(streambuf* __bytebuf) {71streambuf* __r = __bufptr_;72__bufptr_ = __bytebuf;73return __r;74}7576wbuffer_convert(const wbuffer_convert&) = delete;77wbuffer_convert& operator=(const wbuffer_convert&) = delete;7879_LIBCPP_HIDE_FROM_ABI state_type state() const { return __st_; }8081protected:82_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type underflow();83_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type pbackfail(int_type __c = traits_type::eof());84_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type overflow(int_type __c = traits_type::eof());85_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual basic_streambuf<char_type, traits_type>* setbuf(char_type* __s, streamsize __n);86_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual pos_type87seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __wch = ios_base::in | ios_base::out);88_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual pos_type89seekpos(pos_type __sp, ios_base::openmode __wch = ios_base::in | ios_base::out);90_LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int sync();9192private:93_LIBCPP_HIDE_FROM_ABI_VIRTUAL bool __read_mode();94_LIBCPP_HIDE_FROM_ABI_VIRTUAL void __write_mode();95_LIBCPP_HIDE_FROM_ABI_VIRTUAL wbuffer_convert* __close();96};9798_LIBCPP_SUPPRESS_DEPRECATED_PUSH99template <class _Codecvt, class _Elem, class _Tr>100wbuffer_convert<_Codecvt, _Elem, _Tr>::wbuffer_convert(streambuf* __bytebuf, _Codecvt* __pcvt, state_type __state)101: __extbuf_(nullptr),102__extbufnext_(nullptr),103__extbufend_(nullptr),104__ebs_(0),105__intbuf_(0),106__ibs_(0),107__bufptr_(__bytebuf),108__cv_(__pcvt),109__st_(__state),110__cm_(0),111__owns_eb_(false),112__owns_ib_(false),113__always_noconv_(__cv_ ? __cv_->always_noconv() : false) {114setbuf(0, 4096);115}116117template <class _Codecvt, class _Elem, class _Tr>118wbuffer_convert<_Codecvt, _Elem, _Tr>::~wbuffer_convert() {119__close();120delete __cv_;121if (__owns_eb_)122delete[] __extbuf_;123if (__owns_ib_)124delete[] __intbuf_;125}126127template <class _Codecvt, class _Elem, class _Tr>128typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type wbuffer_convert<_Codecvt, _Elem, _Tr>::underflow() {129_LIBCPP_SUPPRESS_DEPRECATED_POP130if (__cv_ == 0 || __bufptr_ == nullptr)131return traits_type::eof();132bool __initial = __read_mode();133char_type __1buf;134if (this->gptr() == 0)135this->setg(std::addressof(__1buf), std::addressof(__1buf) + 1, std::addressof(__1buf) + 1);136const size_t __unget_sz = __initial ? 0 : std::min<size_t>((this->egptr() - this->eback()) / 2, 4);137int_type __c = traits_type::eof();138if (this->gptr() == this->egptr()) {139std::memmove(this->eback(), this->egptr() - __unget_sz, __unget_sz * sizeof(char_type));140if (__always_noconv_) {141streamsize __nmemb = static_cast<streamsize>(this->egptr() - this->eback() - __unget_sz);142__nmemb = __bufptr_->sgetn((char*)this->eback() + __unget_sz, __nmemb);143if (__nmemb != 0) {144this->setg(this->eback(), this->eback() + __unget_sz, this->eback() + __unget_sz + __nmemb);145__c = *this->gptr();146}147} else {148if (__extbufend_ != __extbufnext_) {149_LIBCPP_ASSERT_NON_NULL(__extbufnext_ != nullptr, "underflow moving from nullptr");150_LIBCPP_ASSERT_NON_NULL(__extbuf_ != nullptr, "underflow moving into nullptr");151std::memmove(__extbuf_, __extbufnext_, __extbufend_ - __extbufnext_);152}153__extbufnext_ = __extbuf_ + (__extbufend_ - __extbufnext_);154__extbufend_ = __extbuf_ + (__extbuf_ == __extbuf_min_ ? sizeof(__extbuf_min_) : __ebs_);155streamsize __nmemb = std::min(static_cast<streamsize>(this->egptr() - this->eback() - __unget_sz),156static_cast<streamsize>(__extbufend_ - __extbufnext_));157codecvt_base::result __r;158// FIXME: Do we ever need to restore the state here?159// state_type __svs = __st_;160streamsize __nr = __bufptr_->sgetn(const_cast<char*>(__extbufnext_), __nmemb);161if (__nr != 0) {162__extbufend_ = __extbufnext_ + __nr;163char_type* __inext;164__r = __cv_->in(165__st_, __extbuf_, __extbufend_, __extbufnext_, this->eback() + __unget_sz, this->egptr(), __inext);166if (__r == codecvt_base::noconv) {167this->setg((char_type*)__extbuf_, (char_type*)__extbuf_, (char_type*)const_cast<char*>(__extbufend_));168__c = *this->gptr();169} else if (__inext != this->eback() + __unget_sz) {170this->setg(this->eback(), this->eback() + __unget_sz, __inext);171__c = *this->gptr();172}173}174}175} else176__c = *this->gptr();177if (this->eback() == std::addressof(__1buf))178this->setg(0, 0, 0);179return __c;180}181182_LIBCPP_SUPPRESS_DEPRECATED_PUSH183template <class _Codecvt, class _Elem, class _Tr>184typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type185wbuffer_convert<_Codecvt, _Elem, _Tr>::pbackfail(int_type __c) {186_LIBCPP_SUPPRESS_DEPRECATED_POP187if (__cv_ != 0 && __bufptr_ && this->eback() < this->gptr()) {188if (traits_type::eq_int_type(__c, traits_type::eof())) {189this->gbump(-1);190return traits_type::not_eof(__c);191}192if (traits_type::eq(traits_type::to_char_type(__c), this->gptr()[-1])) {193this->gbump(-1);194*this->gptr() = traits_type::to_char_type(__c);195return __c;196}197}198return traits_type::eof();199}200201_LIBCPP_SUPPRESS_DEPRECATED_PUSH202template <class _Codecvt, class _Elem, class _Tr>203typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type wbuffer_convert<_Codecvt, _Elem, _Tr>::overflow(int_type __c) {204_LIBCPP_SUPPRESS_DEPRECATED_POP205if (__cv_ == 0 || !__bufptr_)206return traits_type::eof();207__write_mode();208char_type __1buf;209char_type* __pb_save = this->pbase();210char_type* __epb_save = this->epptr();211if (!traits_type::eq_int_type(__c, traits_type::eof())) {212if (this->pptr() == 0)213this->setp(std::addressof(__1buf), std::addressof(__1buf) + 1);214*this->pptr() = traits_type::to_char_type(__c);215this->pbump(1);216}217if (this->pptr() != this->pbase()) {218if (__always_noconv_) {219streamsize __nmemb = static_cast<streamsize>(this->pptr() - this->pbase());220if (__bufptr_->sputn((const char*)this->pbase(), __nmemb) != __nmemb)221return traits_type::eof();222} else {223char* __extbe = __extbuf_;224codecvt_base::result __r;225do {226const char_type* __e;227__r = __cv_->out(__st_, this->pbase(), this->pptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);228if (__e == this->pbase())229return traits_type::eof();230if (__r == codecvt_base::noconv) {231streamsize __nmemb = static_cast<size_t>(this->pptr() - this->pbase());232if (__bufptr_->sputn((const char*)this->pbase(), __nmemb) != __nmemb)233return traits_type::eof();234} else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {235streamsize __nmemb = static_cast<size_t>(__extbe - __extbuf_);236if (__bufptr_->sputn(__extbuf_, __nmemb) != __nmemb)237return traits_type::eof();238if (__r == codecvt_base::partial) {239this->setp(const_cast<char_type*>(__e), this->pptr());240this->__pbump(this->epptr() - this->pbase());241}242} else243return traits_type::eof();244} while (__r == codecvt_base::partial);245}246this->setp(__pb_save, __epb_save);247}248return traits_type::not_eof(__c);249}250251_LIBCPP_SUPPRESS_DEPRECATED_PUSH252template <class _Codecvt, class _Elem, class _Tr>253basic_streambuf<_Elem, _Tr>* wbuffer_convert<_Codecvt, _Elem, _Tr>::setbuf(char_type* __s, streamsize __n) {254_LIBCPP_SUPPRESS_DEPRECATED_POP255this->setg(0, 0, 0);256this->setp(0, 0);257if (__owns_eb_)258delete[] __extbuf_;259if (__owns_ib_)260delete[] __intbuf_;261__ebs_ = __n;262if (__ebs_ > sizeof(__extbuf_min_)) {263if (__always_noconv_ && __s) {264__extbuf_ = (char*)__s;265__owns_eb_ = false;266} else {267__extbuf_ = new char[__ebs_];268__owns_eb_ = true;269}270} else {271__extbuf_ = __extbuf_min_;272__ebs_ = sizeof(__extbuf_min_);273__owns_eb_ = false;274}275if (!__always_noconv_) {276__ibs_ = max<streamsize>(__n, sizeof(__extbuf_min_));277if (__s && __ibs_ >= sizeof(__extbuf_min_)) {278__intbuf_ = __s;279__owns_ib_ = false;280} else {281__intbuf_ = new char_type[__ibs_];282__owns_ib_ = true;283}284} else {285__ibs_ = 0;286__intbuf_ = 0;287__owns_ib_ = false;288}289return this;290}291292_LIBCPP_SUPPRESS_DEPRECATED_PUSH293template <class _Codecvt, class _Elem, class _Tr>294typename wbuffer_convert<_Codecvt, _Elem, _Tr>::pos_type295wbuffer_convert<_Codecvt, _Elem, _Tr>::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __om) {296int __width = __cv_->encoding();297if (__cv_ == 0 || !__bufptr_ || (__width <= 0 && __off != 0) || sync())298return pos_type(off_type(-1));299// __width > 0 || __off == 0, now check __way300if (__way != ios_base::beg && __way != ios_base::cur && __way != ios_base::end)301return pos_type(off_type(-1));302pos_type __r = __bufptr_->pubseekoff(__width * __off, __way, __om);303__r.state(__st_);304return __r;305}306307template <class _Codecvt, class _Elem, class _Tr>308typename wbuffer_convert<_Codecvt, _Elem, _Tr>::pos_type309wbuffer_convert<_Codecvt, _Elem, _Tr>::seekpos(pos_type __sp, ios_base::openmode __wch) {310if (__cv_ == 0 || !__bufptr_ || sync())311return pos_type(off_type(-1));312if (__bufptr_->pubseekpos(__sp, __wch) == pos_type(off_type(-1)))313return pos_type(off_type(-1));314return __sp;315}316317template <class _Codecvt, class _Elem, class _Tr>318int wbuffer_convert<_Codecvt, _Elem, _Tr>::sync() {319_LIBCPP_SUPPRESS_DEPRECATED_POP320if (__cv_ == 0 || !__bufptr_)321return 0;322if (__cm_ & ios_base::out) {323if (this->pptr() != this->pbase())324if (overflow() == traits_type::eof())325return -1;326codecvt_base::result __r;327do {328char* __extbe;329__r = __cv_->unshift(__st_, __extbuf_, __extbuf_ + __ebs_, __extbe);330streamsize __nmemb = static_cast<streamsize>(__extbe - __extbuf_);331if (__bufptr_->sputn(__extbuf_, __nmemb) != __nmemb)332return -1;333} while (__r == codecvt_base::partial);334if (__r == codecvt_base::error)335return -1;336if (__bufptr_->pubsync())337return -1;338} else if (__cm_ & ios_base::in) {339off_type __c;340if (__always_noconv_)341__c = this->egptr() - this->gptr();342else {343int __width = __cv_->encoding();344__c = __extbufend_ - __extbufnext_;345if (__width > 0)346__c += __width * (this->egptr() - this->gptr());347else {348if (this->gptr() != this->egptr()) {349std::reverse(this->gptr(), this->egptr());350codecvt_base::result __r;351const char_type* __e = this->gptr();352char* __extbe;353do {354__r = __cv_->out(__st_, __e, this->egptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);355switch (__r) {356case codecvt_base::noconv:357__c += this->egptr() - this->gptr();358break;359case codecvt_base::ok:360case codecvt_base::partial:361__c += __extbe - __extbuf_;362break;363default:364return -1;365}366} while (__r == codecvt_base::partial);367}368}369}370if (__bufptr_->pubseekoff(-__c, ios_base::cur, __cm_) == pos_type(off_type(-1)))371return -1;372this->setg(0, 0, 0);373__cm_ = 0;374}375return 0;376}377378_LIBCPP_SUPPRESS_DEPRECATED_PUSH379template <class _Codecvt, class _Elem, class _Tr>380bool wbuffer_convert<_Codecvt, _Elem, _Tr>::__read_mode() {381if (!(__cm_ & ios_base::in)) {382this->setp(0, 0);383if (__always_noconv_)384this->setg((char_type*)__extbuf_, (char_type*)__extbuf_ + __ebs_, (char_type*)__extbuf_ + __ebs_);385else386this->setg(__intbuf_, __intbuf_ + __ibs_, __intbuf_ + __ibs_);387__cm_ = ios_base::in;388return true;389}390return false;391}392393template <class _Codecvt, class _Elem, class _Tr>394void wbuffer_convert<_Codecvt, _Elem, _Tr>::__write_mode() {395if (!(__cm_ & ios_base::out)) {396this->setg(0, 0, 0);397if (__ebs_ > sizeof(__extbuf_min_)) {398if (__always_noconv_)399this->setp((char_type*)__extbuf_, (char_type*)__extbuf_ + (__ebs_ - 1));400else401this->setp(__intbuf_, __intbuf_ + (__ibs_ - 1));402} else403this->setp(0, 0);404__cm_ = ios_base::out;405}406}407408template <class _Codecvt, class _Elem, class _Tr>409wbuffer_convert<_Codecvt, _Elem, _Tr>* wbuffer_convert<_Codecvt, _Elem, _Tr>::__close() {410wbuffer_convert* __rt = nullptr;411if (__cv_ != nullptr && __bufptr_ != nullptr) {412__rt = this;413if ((__cm_ & ios_base::out) && sync())414__rt = nullptr;415}416return __rt;417}418419_LIBCPP_SUPPRESS_DEPRECATED_POP420421_LIBCPP_END_NAMESPACE_STD422423_LIBCPP_POP_MACROS424425# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)426427#endif // _LIBCPP_HAS_LOCALIZATION428429#endif // _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H430431432