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 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(char __byte) {
68 return from_bytes(&__byte, &__byte + 1);
69 }
70 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const char* __ptr) {
71 return from_bytes(__ptr, __ptr + char_traits<char>::length(__ptr));
72 }
73 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const byte_string& __str) {
74 return from_bytes(__str.data(), __str.data() + __str.size());
75 }
76 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI wide_string from_bytes(const char* __first, const char* __last);
77
78 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(_Elem __wchar) {
79 return to_bytes(std::addressof(__wchar), std::addressof(__wchar) + 1);
80 }
81 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const _Elem* __wptr) {
82 return to_bytes(__wptr, __wptr + char_traits<_Elem>::length(__wptr));
83 }
84 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const wide_string& __wstr) {
85 return to_bytes(__wstr.data(), __wstr.data() + __wstr.size());
86 }
87 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI byte_string to_bytes(const _Elem* __first, const _Elem* __last);
88
89 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t converted() const _NOEXCEPT { return __cvtcount_; }
90 [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI state_type state() const { return __cvtstate_; }
91};
92
93_LIBCPP_SUPPRESS_DEPRECATED_PUSH
94template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
95inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt)
96 : __cvtptr_(__pcvt), __cvtstate_(), __cvtcount_(0) {}
97_LIBCPP_SUPPRESS_DEPRECATED_POP
98
99template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
100inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(_Codecvt* __pcvt, state_type __state)
101 : __cvtptr_(__pcvt), __cvtstate_(__state), __cvtcount_(0) {}
102
103template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
104wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(
105 const byte_string& __byte_err, const wide_string& __wide_err)
106 : __byte_err_string_(__byte_err), __wide_err_string_(__wide_err), __cvtstate_(), __cvtcount_(0) {
107 __cvtptr_ = new _Codecvt;
108}
109
110# ifndef _LIBCPP_CXX03_LANG
111
112template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
113inline wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wstring_convert(wstring_convert&& __wc)
114 : __byte_err_string_(std::move(__wc.__byte_err_string_)),
115 __wide_err_string_(std::move(__wc.__wide_err_string_)),
116 __cvtptr_(__wc.__cvtptr_),
117 __cvtstate_(__wc.__cvtstate_),
118 __cvtcount_(__wc.__cvtcount_) {
119 __wc.__cvtptr_ = nullptr;
120}
121
122# endif // _LIBCPP_CXX03_LANG
123
124_LIBCPP_SUPPRESS_DEPRECATED_PUSH
125template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
126wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::~wstring_convert() {
127 delete __cvtptr_;
128}
129
130template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
131typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::wide_string
132wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::from_bytes(const char* __frm, const char* __frm_end) {
133 _LIBCPP_SUPPRESS_DEPRECATED_POP
134 __cvtcount_ = 0;
135 if (__cvtptr_ != nullptr) {
136 wide_string __ws(2 * (__frm_end - __frm), _Elem());
137 if (__frm != __frm_end)
138 __ws.resize(__ws.capacity());
139 codecvt_base::result __r = codecvt_base::ok;
140 state_type __st = __cvtstate_;
141 if (__frm != __frm_end) {
142 _Elem* __to = std::addressof(__ws[0]);
143 _Elem* __to_end = __to + __ws.size();
144 const char* __frm_nxt;
145 do {
146 _Elem* __to_nxt;
147 __r = __cvtptr_->in(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
148 __cvtcount_ += __frm_nxt - __frm;
149 if (__frm_nxt == __frm) {
150 __r = codecvt_base::error;
151 } else if (__r == codecvt_base::noconv) {
152 __ws.resize(__to - std::addressof(__ws[0]));
153 // This only gets executed if _Elem is char
154 __ws.append((const _Elem*)__frm, (const _Elem*)__frm_end);
155 __frm = __frm_nxt;
156 __r = codecvt_base::ok;
157 } else if (__r == codecvt_base::ok) {
158 __ws.resize(__to_nxt - std::addressof(__ws[0]));
159 __frm = __frm_nxt;
160 } else if (__r == codecvt_base::partial) {
161 ptrdiff_t __s = __to_nxt - std::addressof(__ws[0]);
162 __ws.resize(2 * __s);
163 __to = std::addressof(__ws[0]) + __s;
164 __to_end = std::addressof(__ws[0]) + __ws.size();
165 __frm = __frm_nxt;
166 }
167 } while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
168 }
169 if (__r == codecvt_base::ok)
170 return __ws;
171 }
172
173 if (__wide_err_string_.empty())
174 std::__throw_range_error("wstring_convert: from_bytes error");
175
176 return __wide_err_string_;
177}
178
179_LIBCPP_SUPPRESS_DEPRECATED_PUSH
180template <class _Codecvt, class _Elem, class _WideAlloc, class _ByteAlloc>
181typename wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::byte_string
182wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::to_bytes(const _Elem* __frm, const _Elem* __frm_end) {
183 _LIBCPP_SUPPRESS_DEPRECATED_POP
184 __cvtcount_ = 0;
185 if (__cvtptr_ != nullptr) {
186 byte_string __bs(2 * (__frm_end - __frm), char());
187 if (__frm != __frm_end)
188 __bs.resize(__bs.capacity());
189 codecvt_base::result __r = codecvt_base::ok;
190 state_type __st = __cvtstate_;
191 if (__frm != __frm_end) {
192 char* __to = std::addressof(__bs[0]);
193 char* __to_end = __to + __bs.size();
194 const _Elem* __frm_nxt;
195 do {
196 char* __to_nxt;
197 __r = __cvtptr_->out(__st, __frm, __frm_end, __frm_nxt, __to, __to_end, __to_nxt);
198 __cvtcount_ += __frm_nxt - __frm;
199 if (__frm_nxt == __frm) {
200 __r = codecvt_base::error;
201 } else if (__r == codecvt_base::noconv) {
202 __bs.resize(__to - std::addressof(__bs[0]));
203 // This only gets executed if _Elem is char
204 __bs.append((const char*)__frm, (const char*)__frm_end);
205 __frm = __frm_nxt;
206 __r = codecvt_base::ok;
207 } else if (__r == codecvt_base::ok) {
208 __bs.resize(__to_nxt - std::addressof(__bs[0]));
209 __frm = __frm_nxt;
210 } else if (__r == codecvt_base::partial) {
211 ptrdiff_t __s = __to_nxt - std::addressof(__bs[0]);
212 __bs.resize(2 * __s);
213 __to = std::addressof(__bs[0]) + __s;
214 __to_end = std::addressof(__bs[0]) + __bs.size();
215 __frm = __frm_nxt;
216 }
217 } while (__r == codecvt_base::partial && __frm_nxt < __frm_end);
218 }
219 if (__r == codecvt_base::ok) {
220 size_t __s = __bs.size();
221 __bs.resize(__bs.capacity());
222 char* __to = std::addressof(__bs[0]) + __s;
223 char* __to_end = __to + __bs.size();
224 do {
225 char* __to_nxt;
226 __r = __cvtptr_->unshift(__st, __to, __to_end, __to_nxt);
227 if (__r == codecvt_base::noconv) {
228 __bs.resize(__to - std::addressof(__bs[0]));
229 __r = codecvt_base::ok;
230 } else if (__r == codecvt_base::ok) {
231 __bs.resize(__to_nxt - std::addressof(__bs[0]));
232 } else if (__r == codecvt_base::partial) {
233 ptrdiff_t __sp = __to_nxt - std::addressof(__bs[0]);
234 __bs.resize(2 * __sp);
235 __to = std::addressof(__bs[0]) + __sp;
236 __to_end = std::addressof(__bs[0]) + __bs.size();
237 }
238 } while (__r == codecvt_base::partial);
239 if (__r == codecvt_base::ok)
240 return __bs;
241 }
242 }
243
244 if (__byte_err_string_.empty())
245 std::__throw_range_error("wstring_convert: to_bytes error");
246
247 return __byte_err_string_;
248}
249
250_LIBCPP_END_NAMESPACE_STD
251
252_LIBCPP_POP_MACROS
253
254# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)
255
256#endif // _LIBCPP_HAS_LOCALIZATION
257
258#endif // _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H
259