xref: /freebsd/contrib/llvm-project/libcxx/include/__locale_dir/wstring_convert.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
30 template <class _Codecvt,
31           class _Elem      = wchar_t,
32           class _WideAlloc = allocator<_Elem>,
33           class _ByteAlloc = allocator<char> >
34 class _LIBCPP_DEPRECATED_IN_CXX17 wstring_convert {
35 public:
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 
41 private:
42   byte_string __byte_err_string_;
43   wide_string __wide_err_string_;
44   _Codecvt* __cvtptr_;
45   state_type __cvtstate_;
46   size_t __cvtcount_;
47 
48 public:
49 #    ifndef _LIBCPP_CXX03_LANG
wstring_convert()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 
from_bytes(char __byte)67   _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(char __byte) { return from_bytes(&__byte, &__byte + 1); }
from_bytes(const char * __ptr)68   _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const char* __ptr) {
69     return from_bytes(__ptr, __ptr + char_traits<char>::length(__ptr));
70   }
from_bytes(const byte_string & __str)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 
to_bytes(_Elem __wchar)76   _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(_Elem __wchar) {
77     return to_bytes(std::addressof(__wchar), std::addressof(__wchar) + 1);
78   }
to_bytes(const _Elem * __wptr)79   _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const _Elem* __wptr) {
80     return to_bytes(__wptr, __wptr + char_traits<_Elem>::length(__wptr));
81   }
to_bytes(const wide_string & __wstr)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 
converted()87   _LIBCPP_HIDE_FROM_ABI size_t converted() const _NOEXCEPT { return __cvtcount_; }
state()88   _LIBCPP_HIDE_FROM_ABI state_type state() const { return __cvtstate_; }
89 };
90 
91 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
92 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
wstring_convert(_Codecvt * __pcvt)93 inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt)
94     : __cvtptr_(__pcvt), __cvtstate_(), __cvtcount_(0) {}
95 _LIBCPP_SUPPRESS_DEPRECATED_POP
96 
97 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
wstring_convert(_Codecvt * __pcvt,state_type __state)98 inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt, state_type __state)
99     : __cvtptr_(__pcvt), __cvtstate_(__state), __cvtcount_(0) {}
100 
101 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
wstring_convert(const byte_string & __byte_err,const wide_string & __wide_err)102 wstring_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 
110 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
wstring_convert(wstring_convert && __wc)111 inline 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
123 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
~wstring_convert()124 wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::~wstring_convert() {
125   delete __cvtptr_;
126 }
127 
128 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
129 typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wide_string
from_bytes(const char * __frm,const char * __frm_end)130 wstring_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 
177 template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
178 typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::byte_string
to_bytes(const _Elem * __frm,const _Elem * __frm_end)179 wstring_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
255