brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.0 KiB · a6818aa Raw
431 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H10#define _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H11 12#include <__algorithm/reverse.h>13#include <__config>14#include <__string/char_traits.h>15#include <ios>16#include <streambuf>17 18#if _LIBCPP_HAS_LOCALIZATION19 20#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)21#    pragma GCC system_header22#  endif23 24#  if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)25 26_LIBCPP_PUSH_MACROS27#    include <__undef_macros>28 29_LIBCPP_BEGIN_NAMESPACE_STD30 31template <class _Codecvt, class _Elem = wchar_t, class _Tr = char_traits<_Elem> >32class _LIBCPP_DEPRECATED_IN_CXX17 wbuffer_convert : public basic_streambuf<_Elem, _Tr> {33public:34  // types:35  typedef _Elem char_type;36  typedef _Tr traits_type;37  typedef typename traits_type::int_type int_type;38  typedef typename traits_type::pos_type pos_type;39  typedef typename traits_type::off_type off_type;40  typedef typename _Codecvt::state_type state_type;41 42private:43  char* __extbuf_;44  const char* __extbufnext_;45  const char* __extbufend_;46  char __extbuf_min_[8];47  size_t __ebs_;48  char_type* __intbuf_;49  size_t __ibs_;50  streambuf* __bufptr_;51  _Codecvt* __cv_;52  state_type __st_;53  ios_base::openmode __cm_;54  bool __owns_eb_;55  bool __owns_ib_;56  bool __always_noconv_;57 58public:59#    ifndef _LIBCPP_CXX03_LANG60  _LIBCPP_HIDE_FROM_ABI wbuffer_convert() : wbuffer_convert(nullptr) {}61  explicit _LIBCPP_HIDE_FROM_ABI62  wbuffer_convert(streambuf* __bytebuf, _Codecvt* __pcvt = new _Codecvt, state_type __state = state_type());63#    else64  _LIBCPP_EXPLICIT_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI65  wbuffer_convert(streambuf* __bytebuf = nullptr, _Codecvt* __pcvt = new _Codecvt, state_type __state = state_type());66#    endif67 68  _LIBCPP_HIDE_FROM_ABI ~wbuffer_convert();69 70  _LIBCPP_HIDE_FROM_ABI streambuf* rdbuf() const { return __bufptr_; }71  _LIBCPP_HIDE_FROM_ABI streambuf* rdbuf(streambuf* __bytebuf) {72    streambuf* __r = __bufptr_;73    __bufptr_      = __bytebuf;74    return __r;75  }76 77  wbuffer_convert(const wbuffer_convert&)            = delete;78  wbuffer_convert& operator=(const wbuffer_convert&) = delete;79 80  _LIBCPP_HIDE_FROM_ABI state_type state() const { return __st_; }81 82protected:83  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type underflow();84  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type pbackfail(int_type __c = traits_type::eof());85  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int_type overflow(int_type __c = traits_type::eof());86  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual basic_streambuf<char_type, traits_type>* setbuf(char_type* __s, streamsize __n);87  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual pos_type88  seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __wch = ios_base::in | ios_base::out);89  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual pos_type90  seekpos(pos_type __sp, ios_base::openmode __wch = ios_base::in | ios_base::out);91  _LIBCPP_HIDE_FROM_ABI_VIRTUAL virtual int sync();92 93private:94  _LIBCPP_HIDE_FROM_ABI_VIRTUAL bool __read_mode();95  _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __write_mode();96  _LIBCPP_HIDE_FROM_ABI_VIRTUAL wbuffer_convert* __close();97};98 99_LIBCPP_SUPPRESS_DEPRECATED_PUSH100template <class _Codecvt, class _Elem, class _Tr>101wbuffer_convert<_Codecvt, _Elem, _Tr>::wbuffer_convert(streambuf* __bytebuf, _Codecvt* __pcvt, state_type __state)102    : __extbuf_(nullptr),103      __extbufnext_(nullptr),104      __extbufend_(nullptr),105      __ebs_(0),106      __intbuf_(0),107      __ibs_(0),108      __bufptr_(__bytebuf),109      __cv_(__pcvt),110      __st_(__state),111      __cm_(0),112      __owns_eb_(false),113      __owns_ib_(false),114      __always_noconv_(__cv_ ? __cv_->always_noconv() : false) {115  setbuf(0, 4096);116}117 118template <class _Codecvt, class _Elem, class _Tr>119wbuffer_convert<_Codecvt, _Elem, _Tr>::~wbuffer_convert() {120  __close();121  delete __cv_;122  if (__owns_eb_)123    delete[] __extbuf_;124  if (__owns_ib_)125    delete[] __intbuf_;126}127 128template <class _Codecvt, class _Elem, class _Tr>129typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type wbuffer_convert<_Codecvt, _Elem, _Tr>::underflow() {130  _LIBCPP_SUPPRESS_DEPRECATED_POP131  if (__cv_ == 0 || __bufptr_ == nullptr)132    return traits_type::eof();133  bool __initial = __read_mode();134  char_type __1buf;135  if (this->gptr() == 0)136    this->setg(std::addressof(__1buf), std::addressof(__1buf) + 1, std::addressof(__1buf) + 1);137  const size_t __unget_sz = __initial ? 0 : std::min<size_t>((this->egptr() - this->eback()) / 2, 4);138  int_type __c            = traits_type::eof();139  if (this->gptr() == this->egptr()) {140    std::memmove(this->eback(), this->egptr() - __unget_sz, __unget_sz * sizeof(char_type));141    if (__always_noconv_) {142      streamsize __nmemb = static_cast<streamsize>(this->egptr() - this->eback() - __unget_sz);143      __nmemb            = __bufptr_->sgetn((char*)this->eback() + __unget_sz, __nmemb);144      if (__nmemb != 0) {145        this->setg(this->eback(), this->eback() + __unget_sz, this->eback() + __unget_sz + __nmemb);146        __c = *this->gptr();147      }148    } else {149      if (__extbufend_ != __extbufnext_) {150        _LIBCPP_ASSERT_NON_NULL(__extbufnext_ != nullptr, "underflow moving from nullptr");151        _LIBCPP_ASSERT_NON_NULL(__extbuf_ != nullptr, "underflow moving into nullptr");152        std::memmove(__extbuf_, __extbufnext_, __extbufend_ - __extbufnext_);153      }154      __extbufnext_      = __extbuf_ + (__extbufend_ - __extbufnext_);155      __extbufend_       = __extbuf_ + (__extbuf_ == __extbuf_min_ ? sizeof(__extbuf_min_) : __ebs_);156      streamsize __nmemb = std::min(static_cast<streamsize>(this->egptr() - this->eback() - __unget_sz),157                                    static_cast<streamsize>(__extbufend_ - __extbufnext_));158      codecvt_base::result __r;159      // FIXME: Do we ever need to restore the state here?160      // state_type __svs = __st_;161      streamsize __nr = __bufptr_->sgetn(const_cast<char*>(__extbufnext_), __nmemb);162      if (__nr != 0) {163        __extbufend_ = __extbufnext_ + __nr;164        char_type* __inext;165        __r = __cv_->in(166            __st_, __extbuf_, __extbufend_, __extbufnext_, this->eback() + __unget_sz, this->egptr(), __inext);167        if (__r == codecvt_base::noconv) {168          this->setg((char_type*)__extbuf_, (char_type*)__extbuf_, (char_type*)const_cast<char*>(__extbufend_));169          __c = *this->gptr();170        } else if (__inext != this->eback() + __unget_sz) {171          this->setg(this->eback(), this->eback() + __unget_sz, __inext);172          __c = *this->gptr();173        }174      }175    }176  } else177    __c = *this->gptr();178  if (this->eback() == std::addressof(__1buf))179    this->setg(0, 0, 0);180  return __c;181}182 183_LIBCPP_SUPPRESS_DEPRECATED_PUSH184template <class _Codecvt, class _Elem, class _Tr>185typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type186wbuffer_convert<_Codecvt, _Elem, _Tr>::pbackfail(int_type __c) {187  _LIBCPP_SUPPRESS_DEPRECATED_POP188  if (__cv_ != 0 && __bufptr_ && this->eback() < this->gptr()) {189    if (traits_type::eq_int_type(__c, traits_type::eof())) {190      this->gbump(-1);191      return traits_type::not_eof(__c);192    }193    if (traits_type::eq(traits_type::to_char_type(__c), this->gptr()[-1])) {194      this->gbump(-1);195      *this->gptr() = traits_type::to_char_type(__c);196      return __c;197    }198  }199  return traits_type::eof();200}201 202_LIBCPP_SUPPRESS_DEPRECATED_PUSH203template <class _Codecvt, class _Elem, class _Tr>204typename wbuffer_convert<_Codecvt, _Elem, _Tr>::int_type wbuffer_convert<_Codecvt, _Elem, _Tr>::overflow(int_type __c) {205  _LIBCPP_SUPPRESS_DEPRECATED_POP206  if (__cv_ == 0 || !__bufptr_)207    return traits_type::eof();208  __write_mode();209  char_type __1buf;210  char_type* __pb_save  = this->pbase();211  char_type* __epb_save = this->epptr();212  if (!traits_type::eq_int_type(__c, traits_type::eof())) {213    if (this->pptr() == 0)214      this->setp(std::addressof(__1buf), std::addressof(__1buf) + 1);215    *this->pptr() = traits_type::to_char_type(__c);216    this->pbump(1);217  }218  if (this->pptr() != this->pbase()) {219    if (__always_noconv_) {220      streamsize __nmemb = static_cast<streamsize>(this->pptr() - this->pbase());221      if (__bufptr_->sputn((const char*)this->pbase(), __nmemb) != __nmemb)222        return traits_type::eof();223    } else {224      char* __extbe = __extbuf_;225      codecvt_base::result __r;226      do {227        const char_type* __e;228        __r = __cv_->out(__st_, this->pbase(), this->pptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);229        if (__e == this->pbase())230          return traits_type::eof();231        if (__r == codecvt_base::noconv) {232          streamsize __nmemb = static_cast<size_t>(this->pptr() - this->pbase());233          if (__bufptr_->sputn((const char*)this->pbase(), __nmemb) != __nmemb)234            return traits_type::eof();235        } else if (__r == codecvt_base::ok || __r == codecvt_base::partial) {236          streamsize __nmemb = static_cast<size_t>(__extbe - __extbuf_);237          if (__bufptr_->sputn(__extbuf_, __nmemb) != __nmemb)238            return traits_type::eof();239          if (__r == codecvt_base::partial) {240            this->setp(const_cast<char_type*>(__e), this->pptr());241            this->__pbump(this->epptr() - this->pbase());242          }243        } else244          return traits_type::eof();245      } while (__r == codecvt_base::partial);246    }247    this->setp(__pb_save, __epb_save);248  }249  return traits_type::not_eof(__c);250}251 252_LIBCPP_SUPPRESS_DEPRECATED_PUSH253template <class _Codecvt, class _Elem, class _Tr>254basic_streambuf<_Elem, _Tr>* wbuffer_convert<_Codecvt, _Elem, _Tr>::setbuf(char_type* __s, streamsize __n) {255  _LIBCPP_SUPPRESS_DEPRECATED_POP256  this->setg(0, 0, 0);257  this->setp(0, 0);258  if (__owns_eb_)259    delete[] __extbuf_;260  if (__owns_ib_)261    delete[] __intbuf_;262  __ebs_ = __n;263  if (__ebs_ > sizeof(__extbuf_min_)) {264    if (__always_noconv_ && __s) {265      __extbuf_  = (char*)__s;266      __owns_eb_ = false;267    } else {268      __extbuf_  = new char[__ebs_];269      __owns_eb_ = true;270    }271  } else {272    __extbuf_  = __extbuf_min_;273    __ebs_     = sizeof(__extbuf_min_);274    __owns_eb_ = false;275  }276  if (!__always_noconv_) {277    __ibs_ = max<streamsize>(__n, sizeof(__extbuf_min_));278    if (__s && __ibs_ >= sizeof(__extbuf_min_)) {279      __intbuf_  = __s;280      __owns_ib_ = false;281    } else {282      __intbuf_  = new char_type[__ibs_];283      __owns_ib_ = true;284    }285  } else {286    __ibs_     = 0;287    __intbuf_  = 0;288    __owns_ib_ = false;289  }290  return this;291}292 293_LIBCPP_SUPPRESS_DEPRECATED_PUSH294template <class _Codecvt, class _Elem, class _Tr>295typename wbuffer_convert<_Codecvt, _Elem, _Tr>::pos_type296wbuffer_convert<_Codecvt, _Elem, _Tr>::seekoff(off_type __off, ios_base::seekdir __way, ios_base::openmode __om) {297  int __width = __cv_->encoding();298  if (__cv_ == 0 || !__bufptr_ || (__width <= 0 && __off != 0) || sync())299    return pos_type(off_type(-1));300  // __width > 0 || __off == 0, now check __way301  if (__way != ios_base::beg && __way != ios_base::cur && __way != ios_base::end)302    return pos_type(off_type(-1));303  pos_type __r = __bufptr_->pubseekoff(__width * __off, __way, __om);304  __r.state(__st_);305  return __r;306}307 308template <class _Codecvt, class _Elem, class _Tr>309typename wbuffer_convert<_Codecvt, _Elem, _Tr>::pos_type310wbuffer_convert<_Codecvt, _Elem, _Tr>::seekpos(pos_type __sp, ios_base::openmode __wch) {311  if (__cv_ == 0 || !__bufptr_ || sync())312    return pos_type(off_type(-1));313  if (__bufptr_->pubseekpos(__sp, __wch) == pos_type(off_type(-1)))314    return pos_type(off_type(-1));315  return __sp;316}317 318template <class _Codecvt, class _Elem, class _Tr>319int wbuffer_convert<_Codecvt, _Elem, _Tr>::sync() {320  _LIBCPP_SUPPRESS_DEPRECATED_POP321  if (__cv_ == 0 || !__bufptr_)322    return 0;323  if (__cm_ & ios_base::out) {324    if (this->pptr() != this->pbase())325      if (overflow() == traits_type::eof())326        return -1;327    codecvt_base::result __r;328    do {329      char* __extbe;330      __r                = __cv_->unshift(__st_, __extbuf_, __extbuf_ + __ebs_, __extbe);331      streamsize __nmemb = static_cast<streamsize>(__extbe - __extbuf_);332      if (__bufptr_->sputn(__extbuf_, __nmemb) != __nmemb)333        return -1;334    } while (__r == codecvt_base::partial);335    if (__r == codecvt_base::error)336      return -1;337    if (__bufptr_->pubsync())338      return -1;339  } else if (__cm_ & ios_base::in) {340    off_type __c;341    if (__always_noconv_)342      __c = this->egptr() - this->gptr();343    else {344      int __width = __cv_->encoding();345      __c         = __extbufend_ - __extbufnext_;346      if (__width > 0)347        __c += __width * (this->egptr() - this->gptr());348      else {349        if (this->gptr() != this->egptr()) {350          std::reverse(this->gptr(), this->egptr());351          codecvt_base::result __r;352          const char_type* __e = this->gptr();353          char* __extbe;354          do {355            __r = __cv_->out(__st_, __e, this->egptr(), __e, __extbuf_, __extbuf_ + __ebs_, __extbe);356            switch (__r) {357            case codecvt_base::noconv:358              __c += this->egptr() - this->gptr();359              break;360            case codecvt_base::ok:361            case codecvt_base::partial:362              __c += __extbe - __extbuf_;363              break;364            default:365              return -1;366            }367          } while (__r == codecvt_base::partial);368        }369      }370    }371    if (__bufptr_->pubseekoff(-__c, ios_base::cur, __cm_) == pos_type(off_type(-1)))372      return -1;373    this->setg(0, 0, 0);374    __cm_ = 0;375  }376  return 0;377}378 379_LIBCPP_SUPPRESS_DEPRECATED_PUSH380template <class _Codecvt, class _Elem, class _Tr>381bool wbuffer_convert<_Codecvt, _Elem, _Tr>::__read_mode() {382  if (!(__cm_ & ios_base::in)) {383    this->setp(0, 0);384    if (__always_noconv_)385      this->setg((char_type*)__extbuf_, (char_type*)__extbuf_ + __ebs_, (char_type*)__extbuf_ + __ebs_);386    else387      this->setg(__intbuf_, __intbuf_ + __ibs_, __intbuf_ + __ibs_);388    __cm_ = ios_base::in;389    return true;390  }391  return false;392}393 394template <class _Codecvt, class _Elem, class _Tr>395void wbuffer_convert<_Codecvt, _Elem, _Tr>::__write_mode() {396  if (!(__cm_ & ios_base::out)) {397    this->setg(0, 0, 0);398    if (__ebs_ > sizeof(__extbuf_min_)) {399      if (__always_noconv_)400        this->setp((char_type*)__extbuf_, (char_type*)__extbuf_ + (__ebs_ - 1));401      else402        this->setp(__intbuf_, __intbuf_ + (__ibs_ - 1));403    } else404      this->setp(0, 0);405    __cm_ = ios_base::out;406  }407}408 409template <class _Codecvt, class _Elem, class _Tr>410wbuffer_convert<_Codecvt, _Elem, _Tr>* wbuffer_convert<_Codecvt, _Elem, _Tr>::__close() {411  wbuffer_convert* __rt = nullptr;412  if (__cv_ != nullptr && __bufptr_ != nullptr) {413    __rt = this;414    if ((__cm_ & ios_base::out) && sync())415      __rt = nullptr;416  }417  return __rt;418}419 420_LIBCPP_SUPPRESS_DEPRECATED_POP421 422_LIBCPP_END_NAMESPACE_STD423 424_LIBCPP_POP_MACROS425 426#  endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)427 428#endif // _LIBCPP_HAS_LOCALIZATION429 430#endif // _LIBCPP___LOCALE_DIR_WBUFFER_CONVERT_H431