master
  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-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#ifndef _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H
 10#define _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H
 11
 12#include <__config>
 13#include <__locale>
 14#include <__memory/allocator.h>
 15#include <string>
 16
 17#if _LIBCPP_HAS_LOCALIZATION
 18
 19#  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 20#    pragma GCC system_header
 21#  endif
 22
 23#  if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)
 24
 25_LIBCPP_PUSH_MACROS
 26#    include <__undef_macros>
 27
 28_LIBCPP_BEGIN_NAMESPACE_STD
 29
 30template <class _Codecvt,
 31          class _Elem      = wchar_t,
 32          class _WideAlloc = allocator<_Elem>,
 33          class _ByteAlloc = allocator<char> >
 34class _LIBCPP_DEPRECATED_IN_CXX17 wstring_convert {
 35public:
 36  typedef basic_string<char, char_traits<char>, _ByteAlloc> byte_string;
 37  typedef basic_string<_Elem, char_traits<_Elem>, _WideAlloc> wide_string;
 38  typedef typename _Codecvt::state_type state_type;
 39  typedef typename wide_string::traits_type::int_type int_type;
 40
 41private:
 42  byte_string __byte_err_string_;
 43  wide_string __wide_err_string_;
 44  _Codecvt* __cvtptr_;
 45  state_type __cvtstate_;
 46  size_t __cvtcount_;
 47
 48public:
 49#    ifndef _LIBCPP_CXX03_LANG
 50  _LIBCPP_HIDE_FROM_ABI wstring_convert() : wstring_convert(new _Codecvt) {}
 51  _LIBCPP_HIDE_FROM_ABI explicit wstring_convert(_Codecvt* __pcvt);
 52#    else
 53  _LIBCPP_HIDE_FROM_ABI _LIBCPP_EXPLICIT_SINCE_CXX14 wstring_convert(_Codecvt* __pcvt = new _Codecvt);
 54#    endif
 55
 56  _LIBCPP_HIDE_FROM_ABI wstring_convert(_Codecvt* __pcvt, state_type __state);
 57  _LIBCPP_EXPLICIT_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI
 58  wstring_convert(const byte_string& __byte_err, const wide_string& __wide_err = wide_string());
 59#    ifndef _LIBCPP_CXX03_LANG
 60  _LIBCPP_HIDE_FROM_ABI wstring_convert(wstring_convert&& __wc);
 61#    endif
 62  _LIBCPP_HIDE_FROM_ABI ~wstring_convert();
 63
 64  wstring_convert(const wstring_convert& __wc)            = delete;
 65  wstring_convert& operator=(const wstring_convert& __wc) = delete;
 66
 67  _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(char __byte) { return from_bytes(&__byte, &__byte + 1); }
 68  _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const char* __ptr) {
 69    return from_bytes(__ptr, __ptr + char_traits<char>::length(__ptr));
 70  }
 71  _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const byte_string& __str) {
 72    return from_bytes(__str.data(), __str.data() + __str.size());
 73  }
 74  _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const char* __first, const char* __last);
 75
 76  _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(_Elem __wchar) {
 77    return to_bytes(std::addressof(__wchar), std::addressof(__wchar) + 1);
 78  }
 79  _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const _Elem* __wptr) {
 80    return to_bytes(__wptr, __wptr + char_traits<_Elem>::length(__wptr));
 81  }
 82  _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const wide_string& __wstr) {
 83    return to_bytes(__wstr.data(), __wstr.data() + __wstr.size());
 84  }
 85  _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const _Elem* __first, const _Elem* __last);
 86
 87  _LIBCPP_HIDE_FROM_ABI size_t converted() const _NOEXCEPT { return __cvtcount_; }
 88  _LIBCPP_HIDE_FROM_ABI state_type state() const { return __cvtstate_; }
 89};
 90
 91_LIBCPP_SUPPRESS_DEPRECATED_PUSH
 92template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
 93inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt)
 94    : __cvtptr_(__pcvt), __cvtstate_(), __cvtcount_(0) {}
 95_LIBCPP_SUPPRESS_DEPRECATED_POP
 96
 97template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
 98inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt, state_type __state)
 99    : __cvtptr_(__pcvt), __cvtstate_(__state), __cvtcount_(0) {}
100
101template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
102wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(
103    const byte_string& __byte_err, const wide_string& __wide_err)
104    : __byte_err_string_(__byte_err), __wide_err_string_(__wide_err), __cvtstate_(), __cvtcount_(0) {
105  __cvtptr_ = new _Codecvt;
106}
107
108#    ifndef _LIBCPP_CXX03_LANG
109
110template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
111inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(wstring_convert&& __wc)
112    : __byte_err_string_(std::move(__wc.__byte_err_string_)),
113      __wide_err_string_(std::move(__wc.__wide_err_string_)),
114      __cvtptr_(__wc.__cvtptr_),
115      __cvtstate_(__wc.__cvtstate_),
116      __cvtcount_(__wc.__cvtcount_) {
117  __wc.__cvtptr_ = nullptr;
118}
119
120#    endif // _LIBCPP_CXX03_LANG
121
122_LIBCPP_SUPPRESS_DEPRECATED_PUSH
123template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
124wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::~wstring_convert() {
125  delete __cvtptr_;
126}
127
128template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
129typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wide_string
130wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::from_bytes(const char* __frm, const char* __frm_end) {
131  _LIBCPP_SUPPRESS_DEPRECATED_POP
132  __cvtcount_ = 0;
133  if (__cvtptr_ != nullptr) {
134    wide_string __ws(2 * (__frm_end - __frm), _Elem());
135    if (__frm != __frm_end)
136      __ws.resize(__ws.capacity());
137    codecvt_base::result __r = codecvt_base::ok;
138    state_type __st          = __cvtstate_;
139    if (__frm != __frm_end) {
140      _Elem* __to     = std::addressof(__ws[0]);
141      _Elem* __to_end = __to + __ws.size();
142      const char* __frm_nxt;
143      do {
144        _Elem* __to_nxt;
145        __r = __cvtptr_->in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
146        __cvtcount_ += __frm_nxt - __frm;
147        if (__frm_nxt == __frm) {
148          __r = codecvt_base::error;
149        } else if (__r == codecvt_base::noconv) {
150          __ws.resize(__to - std::addressof(__ws[0]));
151          // This only gets executed if _Elem is char
152          __ws.append((const _Elem*)__frm, (const _Elem*)__frm_end);
153          __frm = __frm_nxt;
154          __r   = codecvt_base::ok;
155        } else if (__r == codecvt_base::ok) {
156          __ws.resize(__to_nxt - std::addressof(__ws[0]));
157          __frm = __frm_nxt;
158        } else if (__r == codecvt_base::partial) {
159          ptrdiff_t __s = __to_nxt - std::addressof(__ws[0]);
160          __ws.resize(2 * __s);
161          __to     = std::addressof(__ws[0]) + __s;
162          __to_end = std::addressof(__ws[0]) + __ws.size();
163          __frm    = __frm_nxt;
164        }
165      } while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
166    }
167    if (__r == codecvt_base::ok)
168      return __ws;
169  }
170
171  if (__wide_err_string_.empty())
172    std::__throw_range_error("wstring_convert: from_bytes error");
173
174  return __wide_err_string_;
175}
176
177template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
178typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::byte_string
179wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::to_bytes(const _Elem* __frm, const _Elem* __frm_end) {
180  __cvtcount_ = 0;
181  if (__cvtptr_ != nullptr) {
182    byte_string __bs(2 * (__frm_end - __frm), char());
183    if (__frm != __frm_end)
184      __bs.resize(__bs.capacity());
185    codecvt_base::result __r = codecvt_base::ok;
186    state_type __st          = __cvtstate_;
187    if (__frm != __frm_end) {
188      char* __to     = std::addressof(__bs[0]);
189      char* __to_end = __to + __bs.size();
190      const _Elem* __frm_nxt;
191      do {
192        char* __to_nxt;
193        __r = __cvtptr_->out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
194        __cvtcount_ += __frm_nxt - __frm;
195        if (__frm_nxt == __frm) {
196          __r = codecvt_base::error;
197        } else if (__r == codecvt_base::noconv) {
198          __bs.resize(__to - std::addressof(__bs[0]));
199          // This only gets executed if _Elem is char
200          __bs.append((const char*)__frm, (const char*)__frm_end);
201          __frm = __frm_nxt;
202          __r   = codecvt_base::ok;
203        } else if (__r == codecvt_base::ok) {
204          __bs.resize(__to_nxt - std::addressof(__bs[0]));
205          __frm = __frm_nxt;
206        } else if (__r == codecvt_base::partial) {
207          ptrdiff_t __s = __to_nxt - std::addressof(__bs[0]);
208          __bs.resize(2 * __s);
209          __to     = std::addressof(__bs[0]) + __s;
210          __to_end = std::addressof(__bs[0]) + __bs.size();
211          __frm    = __frm_nxt;
212        }
213      } while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
214    }
215    if (__r == codecvt_base::ok) {
216      size_t __s = __bs.size();
217      __bs.resize(__bs.capacity());
218      char* __to     = std::addressof(__bs[0]) + __s;
219      char* __to_end = __to + __bs.size();
220      do {
221        char* __to_nxt;
222        __r = __cvtptr_->unshift(__st, __to, __to_end, __to_nxt);
223        if (__r == codecvt_base::noconv) {
224          __bs.resize(__to - std::addressof(__bs[0]));
225          __r = codecvt_base::ok;
226        } else if (__r == codecvt_base::ok) {
227          __bs.resize(__to_nxt - std::addressof(__bs[0]));
228        } else if (__r == codecvt_base::partial) {
229          ptrdiff_t __sp = __to_nxt - std::addressof(__bs[0]);
230          __bs.resize(2 * __sp);
231          __to     = std::addressof(__bs[0]) + __sp;
232          __to_end = std::addressof(__bs[0]) + __bs.size();
233        }
234      } while (__r == codecvt_base::partial);
235      if (__r == codecvt_base::ok)
236        return __bs;
237    }
238  }
239
240  if (__byte_err_string_.empty())
241    std::__throw_range_error("wstring_convert: to_bytes error");
242
243  return __byte_err_string_;
244}
245
246_LIBCPP_END_NAMESPACE_STD
247
248_LIBCPP_POP_MACROS
249
250#  endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)
251
252#endif // _LIBCPP_HAS_LOCALIZATION
253
254#endif // _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H