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