255 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H10#define _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H11 12#include <__config>13#include <__locale>14#include <__memory/allocator.h>15#include <string>16 17#if _LIBCPP_HAS_LOCALIZATION18 19# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)20# pragma GCC system_header21# endif22 23# if _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)24 25_LIBCPP_PUSH_MACROS26# include <__undef_macros>27 28_LIBCPP_BEGIN_NAMESPACE_STD29 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_LANG50 _LIBCPP_HIDE_FROM_ABI wstring_convert() : wstring_convert(new _Codecvt) {}51 _LIBCPP_HIDE_FROM_ABI explicit wstring_convert(_Codecvt* __pcvt);52# else53 _LIBCPP_HIDE_FROM_ABI _LIBCPP_EXPLICIT_SINCE_CXX14 wstring_convert(_Codecvt* __pcvt = new _Codecvt);54# endif55 56 _LIBCPP_HIDE_FROM_ABI wstring_convert(_Codecvt* __pcvt, state_type __state);57 _LIBCPP_EXPLICIT_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI58 wstring_convert(const byte_string& __byte_err, const wide_string& __wide_err = wide_string());59# ifndef _LIBCPP_CXX03_LANG60 _LIBCPP_HIDE_FROM_ABI wstring_convert(wstring_convert&& __wc);61# endif62 _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_PUSH92template <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_POP96 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_LANG109 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_LANG121 122_LIBCPP_SUPPRESS_DEPRECATED_PUSH123template <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_string130wstring_convert<_Codecvt, _Elem, _WideAlloc, _ByteAlloc>::from_bytes(const char* __frm, const char* __frm_end) {131 _LIBCPP_SUPPRESS_DEPRECATED_POP132 __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 char152 __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_string179wstring_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 char200 __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_STD247 248_LIBCPP_POP_MACROS249 250# endif // _LIBCPP_STD_VER < 26 || defined(_LIBCPP_ENABLE_CXX26_REMOVED_WSTRING_CONVERT)251 252#endif // _LIBCPP_HAS_LOCALIZATION253 254#endif // _LIBCPP___LOCALE_DIR_WSTRING_CONVERT_H255