1// wstring_convert implementation -*- C++ -*- 
2 
3// Copyright (C) 2015-2019 Free Software Foundation, Inc. 
4// 
5// This file is part of the GNU ISO C++ Library. This library is free 
6// software; you can redistribute it and/or modify it under the 
7// terms of the GNU General Public License as published by the 
8// Free Software Foundation; either version 3, or (at your option) 
9// any later version. 
10 
11// This library is distributed in the hope that it will be useful, 
12// but WITHOUT ANY WARRANTY; without even the implied warranty of 
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
14// GNU General Public License for more details. 
15 
16// Under Section 7 of GPL version 3, you are granted additional 
17// permissions described in the GCC Runtime Library Exception, version 
18// 3.1, as published by the Free Software Foundation. 
19 
20// You should have received a copy of the GNU General Public License and 
21// a copy of the GCC Runtime Library Exception along with this program; 
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 
23// <http://www.gnu.org/licenses/>. 
24 
25/** @file bits/locale_conv.h 
26 * This is an internal header file, included by other library headers. 
27 * Do not attempt to use it directly. @headername{locale} 
28 */ 
29 
30#ifndef _LOCALE_CONV_H 
31#define _LOCALE_CONV_H 1 
32 
33#if __cplusplus < 201103L 
34# include <bits/c++0x_warning.h> 
35#else 
36 
37#include <streambuf> 
38#include <bits/stringfwd.h> 
39#include <bits/allocator.h> 
40#include <bits/codecvt.h> 
41#include <bits/unique_ptr.h> 
42 
43namespace std _GLIBCXX_VISIBILITY(default) 
44{ 
45_GLIBCXX_BEGIN_NAMESPACE_VERSION 
46 
47 /** 
48 * @addtogroup locales 
49 * @{ 
50 */ 
51 
52 template<typename _OutStr, typename _InChar, typename _Codecvt, 
53 typename _State, typename _Fn> 
54 bool 
55 __do_str_codecvt(const _InChar* __first, const _InChar* __last, 
56 _OutStr& __outstr, const _Codecvt& __cvt, _State& __state, 
57 size_t& __count, _Fn __fn) 
58 { 
59 if (__first == __last) 
60 { 
61 __outstr.clear(); 
62 __count = 0; 
63 return true; 
64 } 
65 
66 size_t __outchars = 0; 
67 auto __next = __first; 
68 const auto __maxlen = __cvt.max_length() + 1; 
69 
70 codecvt_base::result __result; 
71 do 
72 { 
73 __outstr.resize(__outstr.size() + (__last - __next) * __maxlen); 
74 auto __outnext = &__outstr.front() + __outchars; 
75 auto const __outlast = &__outstr.back() + 1; 
76 __result = (__cvt.*__fn)(__state, __next, __last, __next, 
77 __outnext, __outlast, __outnext); 
78 __outchars = __outnext - &__outstr.front(); 
79 } 
80 while (__result == codecvt_base::partial && __next != __last 
81 && (__outstr.size() - __outchars) < __maxlen); 
82 
83 if (__result == codecvt_base::error) 
84 { 
85 __count = __next - __first; 
86 return false; 
87 } 
88 
89 // The codecvt facet will only return noconv when the types are 
90 // the same, so avoid instantiating basic_string::assign otherwise 
91 if _GLIBCXX17_CONSTEXPR (is_same<typename _Codecvt::intern_type, 
92 typename _Codecvt::extern_type>()) 
93 if (__result == codecvt_base::noconv) 
94 { 
95 __outstr.assign(__first, __last); 
96 __count = __last - __first; 
97 return true; 
98 } 
99 
100 __outstr.resize(__outchars); 
101 __count = __next - __first; 
102 return true; 
103 } 
104 
105 // Convert narrow character string to wide. 
106 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
107 inline bool 
108 __str_codecvt_in(const char* __first, const char* __last, 
109 basic_string<_CharT, _Traits, _Alloc>& __outstr, 
110 const codecvt<_CharT, char, _State>& __cvt, 
111 _State& __state, size_t& __count) 
112 { 
113 using _Codecvt = codecvt<_CharT, char, _State>; 
114 using _ConvFn 
115 = codecvt_base::result 
116 (_Codecvt::*)(_State&, const char*, const char*, const char*&, 
117 _CharT*, _CharT*, _CharT*&) const; 
118 _ConvFn __fn = &codecvt<_CharT, char, _State>::in; 
119 return __do_str_codecvt(__first, __last, __outstr, __cvt, __state, 
120 __count, __fn); 
121 } 
122 
123 // As above, but with no __count parameter 
124 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
125 inline bool 
126 __str_codecvt_in(const char* __first, const char* __last, 
127 basic_string<_CharT, _Traits, _Alloc>& __outstr, 
128 const codecvt<_CharT, char, _State>& __cvt) 
129 { 
130 _State __state = {}; 
131 size_t __n; 
132 return __str_codecvt_in(__first, __last, __outstr, __cvt, __state, __n); 
133 } 
134 
135 // As above, but returns false for partial conversion 
136 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
137 inline bool 
138 __str_codecvt_in_all(const char* __first, const char* __last, 
139 basic_string<_CharT, _Traits, _Alloc>& __outstr, 
140 const codecvt<_CharT, char, _State>& __cvt) 
141 { 
142 _State __state = {}; 
143 size_t __n; 
144 return __str_codecvt_in(__first, __last, __outstr, __cvt, __state, __n) 
145 && (__n == (__last - __first)); 
146 } 
147 
148 // Convert wide character string to narrow. 
149 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
150 inline bool 
151 __str_codecvt_out(const _CharT* __first, const _CharT* __last, 
152 basic_string<char, _Traits, _Alloc>& __outstr, 
153 const codecvt<_CharT, char, _State>& __cvt, 
154 _State& __state, size_t& __count) 
155 { 
156 using _Codecvt = codecvt<_CharT, char, _State>; 
157 using _ConvFn 
158 = codecvt_base::result 
159 (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&, 
160 char*, char*, char*&) const; 
161 _ConvFn __fn = &codecvt<_CharT, char, _State>::out; 
162 return __do_str_codecvt(__first, __last, __outstr, __cvt, __state, 
163 __count, __fn); 
164 } 
165 
166 // As above, but with no __count parameter 
167 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
168 inline bool 
169 __str_codecvt_out(const _CharT* __first, const _CharT* __last, 
170 basic_string<char, _Traits, _Alloc>& __outstr, 
171 const codecvt<_CharT, char, _State>& __cvt) 
172 { 
173 _State __state = {}; 
174 size_t __n; 
175 return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n); 
176 } 
177 
178 // As above, but returns false for partial conversions 
179 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
180 inline bool 
181 __str_codecvt_out_all(const _CharT* __first, const _CharT* __last, 
182 basic_string<char, _Traits, _Alloc>& __outstr, 
183 const codecvt<_CharT, char, _State>& __cvt) 
184 { 
185 _State __state = {}; 
186 size_t __n; 
187 return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n) 
188 && (__n == (__last - __first)); 
189 } 
190 
191#ifdef _GLIBCXX_USE_CHAR8_T 
192 
193 // Convert wide character string to narrow. 
194 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
195 inline bool 
196 __str_codecvt_out(const _CharT* __first, const _CharT* __last, 
197 basic_string<char8_t, _Traits, _Alloc>& __outstr, 
198 const codecvt<_CharT, char8_t, _State>& __cvt, 
199 _State& __state, size_t& __count) 
200 { 
201 using _Codecvt = codecvt<_CharT, char8_t, _State>; 
202 using _ConvFn 
203 = codecvt_base::result 
204 (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&, 
205 char8_t*, char8_t*, char8_t*&) const; 
206 _ConvFn __fn = &codecvt<_CharT, char8_t, _State>::out; 
207 return __do_str_codecvt(__first, __last, __outstr, __cvt, __state, 
208 __count, __fn); 
209 } 
210 
211 template<typename _CharT, typename _Traits, typename _Alloc, typename _State> 
212 inline bool 
213 __str_codecvt_out(const _CharT* __first, const _CharT* __last, 
214 basic_string<char8_t, _Traits, _Alloc>& __outstr, 
215 const codecvt<_CharT, char8_t, _State>& __cvt) 
216 { 
217 _State __state = {}; 
218 size_t __n; 
219 return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n); 
220 } 
221 
222#endif // _GLIBCXX_USE_CHAR8_T 
223 
224#ifdef _GLIBCXX_USE_WCHAR_T 
225 
226_GLIBCXX_BEGIN_NAMESPACE_CXX11 
227 
228 /// String conversions 
229 template<typename _Codecvt, typename _Elem = wchar_t, 
230 typename _Wide_alloc = allocator<_Elem>, 
231 typename _Byte_alloc = allocator<char>> 
232 class wstring_convert 
233 { 
234 public: 
235 typedef basic_string<char, char_traits<char>, _Byte_alloc> byte_string; 
236 typedef basic_string<_Elem, char_traits<_Elem>, _Wide_alloc> wide_string; 
237 typedef typename _Codecvt::state_type state_type; 
238 typedef typename wide_string::traits_type::int_type int_type; 
239 
240 /// Default constructor. 
241 wstring_convert() : _M_cvt(new _Codecvt()) { } 
242 
243 /** Constructor. 
244 * 
245 * @param __pcvt The facet to use for conversions. 
246 * 
247 * Takes ownership of @p __pcvt and will delete it in the destructor. 
248 */ 
249 explicit 
250 wstring_convert(_Codecvt* __pcvt) : _M_cvt(__pcvt) 
251 { 
252 if (!_M_cvt) 
253 __throw_logic_error("wstring_convert"); 
254 } 
255 
256 /** Construct with an initial converstion state. 
257 * 
258 * @param __pcvt The facet to use for conversions. 
259 * @param __state Initial conversion state. 
260 * 
261 * Takes ownership of @p __pcvt and will delete it in the destructor. 
262 * The object's conversion state will persist between conversions. 
263 */ 
264 wstring_convert(_Codecvt* __pcvt, state_type __state) 
265 : _M_cvt(__pcvt), _M_state(__state), _M_with_cvtstate(true) 
266 { 
267 if (!_M_cvt) 
268 __throw_logic_error("wstring_convert"); 
269 } 
270 
271 /** Construct with error strings. 
272 * 
273 * @param __byte_err A string to return on failed conversions. 
274 * @param __wide_err A wide string to return on failed conversions. 
275 */ 
276 explicit 
277 wstring_convert(const byte_string& __byte_err, 
278 const wide_string& __wide_err = wide_string()) 
279 : _M_cvt(new _Codecvt), 
280 _M_byte_err_string(__byte_err), _M_wide_err_string(__wide_err), 
281 _M_with_strings(true) 
282 { 
283 if (!_M_cvt) 
284 __throw_logic_error("wstring_convert"); 
285 } 
286 
287 ~wstring_convert() = default; 
288 
289 // _GLIBCXX_RESOLVE_LIB_DEFECTS 
290 // 2176. Special members for wstring_convert and wbuffer_convert 
291 wstring_convert(const wstring_convert&) = delete; 
292 wstring_convert& operator=(const wstring_convert&) = delete; 
293 
294 /// @{ Convert from bytes. 
295 wide_string 
296 from_bytes(char __byte) 
297 { 
298 char __bytes[2] = { __byte }; 
299 return from_bytes(__bytes, __bytes+1); 
300 } 
301 
302 wide_string 
303 from_bytes(const char* __ptr) 
304 { return from_bytes(__ptr, __ptr+char_traits<char>::length(__ptr)); } 
305 
306 wide_string 
307 from_bytes(const byte_string& __str) 
308 { 
309 auto __ptr = __str.data(); 
310 return from_bytes(__ptr, __ptr + __str.size()); 
311 } 
312 
313 wide_string 
314 from_bytes(const char* __first, const char* __last) 
315 { 
316 if (!_M_with_cvtstate) 
317 _M_state = state_type(); 
318 wide_string __out{ _M_wide_err_string.get_allocator() }; 
319 if (__str_codecvt_in(__first, __last, __out, *_M_cvt, _M_state, 
320 _M_count)) 
321 return __out; 
322 if (_M_with_strings) 
323 return _M_wide_err_string; 
324 __throw_range_error("wstring_convert::from_bytes"); 
325 } 
326 /// @} 
327 
328 /// @{ Convert to bytes. 
329 byte_string 
330 to_bytes(_Elem __wchar) 
331 { 
332 _Elem __wchars[2] = { __wchar }; 
333 return to_bytes(__wchars, __wchars+1); 
334 } 
335 
336 byte_string 
337 to_bytes(const _Elem* __ptr) 
338 { 
339 return to_bytes(__ptr, __ptr+wide_string::traits_type::length(__ptr)); 
340 } 
341 
342 byte_string 
343 to_bytes(const wide_string& __wstr) 
344 { 
345 auto __ptr = __wstr.data(); 
346 return to_bytes(__ptr, __ptr + __wstr.size()); 
347 } 
348 
349 byte_string 
350 to_bytes(const _Elem* __first, const _Elem* __last) 
351 { 
352 if (!_M_with_cvtstate) 
353 _M_state = state_type(); 
354 byte_string __out{ _M_byte_err_string.get_allocator() }; 
355 if (__str_codecvt_out(__first, __last, __out, *_M_cvt, _M_state, 
356 _M_count)) 
357 return __out; 
358 if (_M_with_strings) 
359 return _M_byte_err_string; 
360 __throw_range_error("wstring_convert::to_bytes"); 
361 } 
362 /// @} 
363 
364 // _GLIBCXX_RESOLVE_LIB_DEFECTS 
365 // 2174. wstring_convert::converted() should be noexcept 
366 /// The number of elements successfully converted in the last conversion. 
367 size_t converted() const noexcept { return _M_count; } 
368 
369 /// The final conversion state of the last conversion. 
370 state_type state() const { return _M_state; } 
371 
372 private: 
373 unique_ptr<_Codecvt> _M_cvt; 
374 byte_string _M_byte_err_string; 
375 wide_string _M_wide_err_string; 
376 state_type _M_state = state_type(); 
377 size_t _M_count = 0; 
378 bool _M_with_cvtstate = false; 
379 bool _M_with_strings = false; 
380 }; 
381 
382_GLIBCXX_END_NAMESPACE_CXX11 
383 
384 /// Buffer conversions 
385 template<typename _Codecvt, typename _Elem = wchar_t, 
386 typename _Tr = char_traits<_Elem>> 
387 class wbuffer_convert : public basic_streambuf<_Elem, _Tr> 
388 { 
389 typedef basic_streambuf<_Elem, _Tr> _Wide_streambuf; 
390 
391 public: 
392 typedef typename _Codecvt::state_type state_type; 
393 
394 /// Default constructor. 
395 wbuffer_convert() : wbuffer_convert(nullptr) { } 
396 
397 /** Constructor. 
398 * 
399 * @param __bytebuf The underlying byte stream buffer. 
400 * @param __pcvt The facet to use for conversions. 
401 * @param __state Initial conversion state. 
402 * 
403 * Takes ownership of @p __pcvt and will delete it in the destructor. 
404 */ 
405 explicit 
406 wbuffer_convert(streambuf* __bytebuf, _Codecvt* __pcvt = new _Codecvt, 
407 state_type __state = state_type()) 
408 : _M_buf(__bytebuf), _M_cvt(__pcvt), _M_state(__state) 
409 { 
410 if (!_M_cvt) 
411 __throw_logic_error("wbuffer_convert"); 
412 
413 _M_always_noconv = _M_cvt->always_noconv(); 
414 
415 if (_M_buf) 
416 { 
417 this->setp(_M_put_area, _M_put_area + _S_buffer_length); 
418 this->setg(_M_get_area + _S_putback_length, 
419 _M_get_area + _S_putback_length, 
420 _M_get_area + _S_putback_length); 
421 } 
422 } 
423 
424 ~wbuffer_convert() = default; 
425 
426 // _GLIBCXX_RESOLVE_LIB_DEFECTS 
427 // 2176. Special members for wstring_convert and wbuffer_convert 
428 wbuffer_convert(const wbuffer_convert&) = delete; 
429 wbuffer_convert& operator=(const wbuffer_convert&) = delete; 
430 
431 streambuf* rdbuf() const noexcept { return _M_buf; } 
432 
433 streambuf* 
434 rdbuf(streambuf *__bytebuf) noexcept 
435 { 
436 auto __prev = _M_buf; 
437 _M_buf = __bytebuf; 
438 return __prev; 
439 } 
440 
441 /// The conversion state following the last conversion. 
442 state_type state() const noexcept { return _M_state; } 
443 
444 protected: 
445 int 
446 sync() 
447 { return _M_buf && _M_conv_put() && !_M_buf->pubsync() ? 0 : -1; } 
448 
449 typename _Wide_streambuf::int_type 
450 overflow(typename _Wide_streambuf::int_type __out) 
451 { 
452 if (!_M_buf || !_M_conv_put()) 
453 return _Tr::eof(); 
454 else if (!_Tr::eq_int_type(__out, _Tr::eof())) 
455 return this->sputc(__out); 
456 return _Tr::not_eof(__out); 
457 } 
458 
459 typename _Wide_streambuf::int_type 
460 underflow() 
461 { 
462 if (!_M_buf) 
463 return _Tr::eof(); 
464 
465 if (this->gptr() < this->egptr() || (_M_buf && _M_conv_get())) 
466 return _Tr::to_int_type(*this->gptr()); 
467 else 
468 return _Tr::eof(); 
469 } 
470 
471 streamsize 
472 xsputn(const typename _Wide_streambuf::char_type* __s, streamsize __n) 
473 { 
474 if (!_M_buf || __n == 0) 
475 return 0; 
476 streamsize __done = 0; 
477 do 
478 { 
479 auto __nn = std::min<streamsize>(this->epptr() - this->pptr(), 
480 __n - __done); 
481 _Tr::copy(this->pptr(), __s + __done, __nn); 
482 this->pbump(__nn); 
483 __done += __nn; 
484 } while (__done < __n && _M_conv_put()); 
485 return __done; 
486 } 
487 
488 private: 
489 // fill the get area from converted contents of the byte stream buffer 
490 bool 
491 _M_conv_get() 
492 { 
493 const streamsize __pb1 = this->gptr() - this->eback(); 
494 const streamsize __pb2 = _S_putback_length; 
495 const streamsize __npb = std::min(__pb1, __pb2); 
496 
497 _Tr::move(_M_get_area + _S_putback_length - __npb, 
498 this->gptr() - __npb, __npb); 
499 
500 streamsize __nbytes = sizeof(_M_get_buf) - _M_unconv; 
501 __nbytes = std::min(__nbytes, _M_buf->in_avail()); 
502 if (__nbytes < 1) 
503 __nbytes = 1; 
504 __nbytes = _M_buf->sgetn(_M_get_buf + _M_unconv, __nbytes); 
505 if (__nbytes < 1) 
506 return false; 
507 __nbytes += _M_unconv; 
508 
509 // convert _M_get_buf into _M_get_area 
510 
511 _Elem* __outbuf = _M_get_area + _S_putback_length; 
512 _Elem* __outnext = __outbuf; 
513 const char* __bnext = _M_get_buf; 
514 
515 codecvt_base::result __result; 
516 if (_M_always_noconv) 
517 __result = codecvt_base::noconv; 
518 else 
519 { 
520 _Elem* __outend = _M_get_area + _S_buffer_length; 
521 
522 __result = _M_cvt->in(_M_state, 
523 __bnext, __bnext + __nbytes, __bnext, 
524 __outbuf, __outend, __outnext); 
525 } 
526 
527 if (__result == codecvt_base::noconv) 
528 { 
529 // cast is safe because noconv means _Elem is same type as char 
530 auto __get_buf = reinterpret_cast<const _Elem*>(_M_get_buf); 
531 _Tr::copy(__outbuf, __get_buf, __nbytes); 
532 _M_unconv = 0; 
533 return true; 
534 } 
535 
536 if ((_M_unconv = _M_get_buf + __nbytes - __bnext)) 
537 char_traits<char>::move(_M_get_buf, __bnext, _M_unconv); 
538 
539 this->setg(__outbuf, __outbuf, __outnext); 
540 
541 return __result != codecvt_base::error; 
542 } 
543 
544 // unused 
545 bool 
546 _M_put(...) 
547 { return false; } 
548 
549 bool 
550 _M_put(const char* __p, streamsize __n) 
551 { 
552 if (_M_buf->sputn(__p, __n) < __n) 
553 return false; 
554 return true; 
555 } 
556 
557 // convert the put area and write to the byte stream buffer 
558 bool 
559 _M_conv_put() 
560 { 
561 _Elem* const __first = this->pbase(); 
562 const _Elem* const __last = this->pptr(); 
563 const streamsize __pending = __last - __first; 
564 
565 if (_M_always_noconv) 
566 return _M_put(__first, __pending); 
567 
568 char __outbuf[2 * _S_buffer_length]; 
569 
570 const _Elem* __next = __first; 
571 const _Elem* __start; 
572 do 
573 { 
574 __start = __next; 
575 char* __outnext = __outbuf; 
576 char* const __outlast = __outbuf + sizeof(__outbuf); 
577 auto __result = _M_cvt->out(_M_state, __next, __last, __next, 
578 __outnext, __outlast, __outnext); 
579 if (__result == codecvt_base::error) 
580 return false; 
581 else if (__result == codecvt_base::noconv) 
582 return _M_put(__next, __pending); 
583 
584 if (!_M_put(__outbuf, __outnext - __outbuf)) 
585 return false; 
586 } 
587 while (__next != __last && __next != __start); 
588 
589 if (__next != __last) 
590 _Tr::move(__first, __next, __last - __next); 
591 
592 this->pbump(__first - __next); 
593 return __next != __first; 
594 } 
595 
596 streambuf* _M_buf; 
597 unique_ptr<_Codecvt> _M_cvt; 
598 state_type _M_state; 
599 
600 static const streamsize _S_buffer_length = 32; 
601 static const streamsize _S_putback_length = 3; 
602 _Elem _M_put_area[_S_buffer_length]; 
603 _Elem _M_get_area[_S_buffer_length]; 
604 streamsize _M_unconv = 0; 
605 char _M_get_buf[_S_buffer_length-_S_putback_length]; 
606 bool _M_always_noconv; 
607 }; 
608 
609#endif // _GLIBCXX_USE_WCHAR_T 
610 
611 /// @} group locales 
612 
613_GLIBCXX_END_NAMESPACE_VERSION 
614} // namespace 
615 
616#endif // __cplusplus 
617 
618#endif /* _LOCALE_CONV_H */ 
619