1d874057dim//===------------------------- locale.cpp ---------------------------------===//
2d874057dim//
3d874057dim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d874057dim// See https://llvm.org/LICENSE.txt for license information.
5d874057dim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d874057dim//
7d874057dim//===----------------------------------------------------------------------===//
8d874057dim
9d874057dim// On Solaris, we need to define something to make the C99 parts of localeconv
10d874057dim// visible.
11d874057dim#ifdef __sun__
12d874057dim#define _LCONV_C99
13d874057dim#endif
14d874057dim
15d874057dim#include "string"
16d874057dim#include "locale"
17d874057dim#include "codecvt"
18d874057dim#include "vector"
19d874057dim#include "algorithm"
20d874057dim#include "typeinfo"
21d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
22d874057dim#  include "type_traits"
23d874057dim#endif
24d874057dim#include "clocale"
25d874057dim#include "cstring"
26d874057dim#if defined(_LIBCPP_MSVCRT)
27d874057dim#define _CTYPE_DISABLE_MACROS
28d874057dim#endif
29d874057dim#include "cwctype"
30d874057dim#include "__sso_allocator"
31d874057dim#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
32d874057dim#include "support/win32/locale_win32.h"
33d874057dim#elif !defined(__BIONIC__)
34d874057dim#include <langinfo.h>
35d874057dim#endif
36d874057dim#include <stdlib.h>
37d874057dim#include <stdio.h>
38d874057dim#include "include/atomic_support.h"
39d874057dim#include "__undef_macros"
40d874057dim
41d874057dim// On Linux, wint_t and wchar_t have different signed-ness, and this causes
42332da66dim// lots of noise in the build log, but no bugs that I know of.
43d874057dim#if defined(__clang__)
44d874057dim#pragma clang diagnostic ignored "-Wsign-conversion"
45d874057dim#endif
46d874057dim
47d874057dim_LIBCPP_BEGIN_NAMESPACE_STD
48d874057dim
49d874057dimstruct __libcpp_unique_locale {
50d874057dim  __libcpp_unique_locale(const char* nm) : __loc_(newlocale(LC_ALL_MASK, nm, 0)) {}
51d874057dim
52d874057dim  ~__libcpp_unique_locale() {
53d874057dim    if (__loc_)
54d874057dim      freelocale(__loc_);
55d874057dim  }
56d874057dim
57d874057dim  explicit operator bool() const { return __loc_; }
58d874057dim
59d874057dim  locale_t& get() { return __loc_; }
60d874057dim
61d874057dim  locale_t __loc_;
62d874057dimprivate:
63d874057dim  __libcpp_unique_locale(__libcpp_unique_locale const&);
64d874057dim  __libcpp_unique_locale& operator=(__libcpp_unique_locale const&);
65d874057dim};
66d874057dim
67d874057dim#ifdef __cloc_defined
68d874057dimlocale_t __cloc() {
69d874057dim  // In theory this could create a race condition. In practice
70d874057dim  // the race condition is non-fatal since it will just create
71d874057dim  // a little resource leak. Better approach would be appreciated.
72d874057dim  static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
73d874057dim  return result;
74d874057dim}
75d874057dim#endif // __cloc_defined
76d874057dim
77d874057dimnamespace {
78d874057dim
79d874057dimstruct release
80d874057dim{
81d874057dim    void operator()(locale::facet* p) {p->__release_shared();}
82d874057dim};
83d874057dim
84d874057dimtemplate <class T, class A0>
85d874057diminline
86d874057dimT&
87d874057dimmake(A0 a0)
88d874057dim{
89d874057dim    static typename aligned_storage<sizeof(T)>::type buf;
90d874057dim    auto *obj = ::new (&buf) T(a0);
91d874057dim    return *obj;
92d874057dim}
93d874057dim
94d874057dimtemplate <class T, class A0, class A1>
95d874057diminline
96d874057dimT&
97d874057dimmake(A0 a0, A1 a1)
98d874057dim{
99d874057dim    static typename aligned_storage<sizeof(T)>::type buf;
100d874057dim    ::new (&buf) T(a0, a1);
101d874057dim    return *reinterpret_cast<T*>(&buf);
102d874057dim}
103d874057dim
104d874057dimtemplate <class T, class A0, class A1, class A2>
105d874057diminline
106d874057dimT&
107d874057dimmake(A0 a0, A1 a1, A2 a2)
108d874057dim{
109d874057dim    static typename aligned_storage<sizeof(T)>::type buf;
110d874057dim    auto *obj = ::new (&buf) T(a0, a1, a2);
111d874057dim    return *obj;
112d874057dim}
113d874057dim
114d874057dimtemplate <typename T, size_t N>
115d874057diminline
116d874057dim_LIBCPP_CONSTEXPR
117d874057dimsize_t
118d874057dimcountof(const T (&)[N])
119d874057dim{
120d874057dim    return N;
121d874057dim}
122d874057dim
123d874057dimtemplate <typename T>
124d874057diminline
125d874057dim_LIBCPP_CONSTEXPR
126d874057dimsize_t
127d874057dimcountof(const T * const begin, const T * const end)
128d874057dim{
129d874057dim    return static_cast<size_t>(end - begin);
130d874057dim}
131d874057dim
132d874057dim_LIBCPP_NORETURN static void __throw_runtime_error(const string &msg)
133d874057dim{
134d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
135d874057dim    throw runtime_error(msg);
136d874057dim#else
137d874057dim    (void)msg;
138d874057dim    _VSTD::abort();
139d874057dim#endif
140d874057dim}
141d874057dim
142d874057dim}
143d874057dim
144d874057dim#if defined(_AIX)
145d874057dim// Set priority to INT_MIN + 256 + 150
146d874057dim# pragma priority ( -2147483242 )
147d874057dim#endif
148d874057dim
149d874057dimconst locale::category locale::none;
150d874057dimconst locale::category locale::collate;
151d874057dimconst locale::category locale::ctype;
152d874057dimconst locale::category locale::monetary;
153d874057dimconst locale::category locale::numeric;
154d874057dimconst locale::category locale::time;
155d874057dimconst locale::category locale::messages;
156d874057dimconst locale::category locale::all;
157d874057dim
158d874057dimclass _LIBCPP_HIDDEN locale::__imp
159d874057dim    : public facet
160d874057dim{
161d874057dim    enum {N = 28};
162d874057dim#if defined(_LIBCPP_COMPILER_MSVC)
163d874057dim// FIXME: MSVC doesn't support aligned parameters by value.
164d874057dim// I can't get the __sso_allocator to work here
165d874057dim// for MSVC I think for this reason.
166d874057dim    vector<facet*> facets_;
167d874057dim#else
168d874057dim    vector<facet*, __sso_allocator<facet*, N> > facets_;
169d874057dim#endif
170d874057dim    string         name_;
171d874057dimpublic:
172d874057dim    explicit __imp(size_t refs = 0);
173d874057dim    explicit __imp(const string& name, size_t refs = 0);
174d874057dim    __imp(const __imp&);
175d874057dim    __imp(const __imp&, const string&, locale::category c);
176d874057dim    __imp(const __imp& other, const __imp& one, locale::category c);
177d874057dim    __imp(const __imp&, facet* f, long id);
178d874057dim    ~__imp();
179d874057dim
180d874057dim    const string& name() const {return name_;}
181d874057dim    bool has_facet(long id) const
182d874057dim        {return static_cast<size_t>(id) < facets_.size() && facets_[static_cast<size_t>(id)];}
183d874057dim    const locale::facet* use_facet(long id) const;
184d874057dim
185d874057dim    static const locale& make_classic();
186d874057dim    static       locale& make_global();
187d874057dimprivate:
188d874057dim    void install(facet* f, long id);
189d874057dim    template <class F> void install(F* f) {install(f, f->id.__get());}
190d874057dim    template <class F> void install_from(const __imp& other);
191d874057dim};
192d874057dim
193d874057dimlocale::__imp::__imp(size_t refs)
194d874057dim    : facet(refs),
195d874057dim      facets_(N),
196d874057dim      name_("C")
197d874057dim{
198d874057dim    facets_.clear();
199d874057dim    install(&make<_VSTD::collate<char> >(1u));
200d874057dim    install(&make<_VSTD::collate<wchar_t> >(1u));
201d874057dim    install(&make<_VSTD::ctype<char> >(nullptr, false, 1u));
202d874057dim    install(&make<_VSTD::ctype<wchar_t> >(1u));
203d874057dim    install(&make<codecvt<char, char, mbstate_t> >(1u));
204d874057dim    install(&make<codecvt<wchar_t, char, mbstate_t> >(1u));
205d874057dim    install(&make<codecvt<char16_t, char, mbstate_t> >(1u));
206d874057dim    install(&make<codecvt<char32_t, char, mbstate_t> >(1u));
207d874057dim    install(&make<numpunct<char> >(1u));
208d874057dim    install(&make<numpunct<wchar_t> >(1u));
209d874057dim    install(&make<num_get<char> >(1u));
210d874057dim    install(&make<num_get<wchar_t> >(1u));
211d874057dim    install(&make<num_put<char> >(1u));
212d874057dim    install(&make<num_put<wchar_t> >(1u));
213d874057dim    install(&make<moneypunct<char, false> >(1u));
214d874057dim    install(&make<moneypunct<char, true> >(1u));
215d874057dim    install(&make<moneypunct<wchar_t, false> >(1u));
216d874057dim    install(&make<moneypunct<wchar_t, true> >(1u));
217d874057dim    install(&make<money_get<char> >(1u));
218d874057dim    install(&make<money_get<wchar_t> >(1u));
219d874057dim    install(&make<money_put<char> >(1u));
220d874057dim    install(&make<money_put<wchar_t> >(1u));
221d874057dim    install(&make<time_get<char> >(1u));
222d874057dim    install(&make<time_get<wchar_t> >(1u));
223d874057dim    install(&make<time_put<char> >(1u));
224d874057dim    install(&make<time_put<wchar_t> >(1u));
225d874057dim    install(&make<_VSTD::messages<char> >(1u));
226d874057dim    install(&make<_VSTD::messages<wchar_t> >(1u));
227d874057dim}
228d874057dim
229d874057dimlocale::__imp::__imp(const string& name, size_t refs)
230d874057dim    : facet(refs),
231d874057dim      facets_(N),
232d874057dim      name_(name)
233d874057dim{
234d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
235d874057dim    try
236d874057dim    {
237d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
238d874057dim        facets_ = locale::classic().__locale_->facets_;
239d874057dim        for (unsigned i = 0; i < facets_.size(); ++i)
240d874057dim            if (facets_[i])
241d874057dim                facets_[i]->__add_shared();
242d874057dim        install(new collate_byname<char>(name_));
243d874057dim        install(new collate_byname<wchar_t>(name_));
244d874057dim        install(new ctype_byname<char>(name_));
245d874057dim        install(new ctype_byname<wchar_t>(name_));
246d874057dim        install(new codecvt_byname<char, char, mbstate_t>(name_));
247d874057dim        install(new codecvt_byname<wchar_t, char, mbstate_t>(name_));
248d874057dim        install(new codecvt_byname<char16_t, char, mbstate_t>(name_));
249d874057dim        install(new codecvt_byname<char32_t, char, mbstate_t>(name_));
250d874057dim        install(new numpunct_byname<char>(name_));
251d874057dim        install(new numpunct_byname<wchar_t>(name_));
252d874057dim        install(new moneypunct_byname<char, false>(name_));
253d874057dim        install(new moneypunct_byname<char, true>(name_));
254d874057dim        install(new moneypunct_byname<wchar_t, false>(name_));
255d874057dim        install(new moneypunct_byname<wchar_t, true>(name_));
256d874057dim        install(new time_get_byname<char>(name_));
257d874057dim        install(new time_get_byname<wchar_t>(name_));
258d874057dim        install(new time_put_byname<char>(name_));
259d874057dim        install(new time_put_byname<wchar_t>(name_));
260d874057dim        install(new messages_byname<char>(name_));
261d874057dim        install(new messages_byname<wchar_t>(name_));
262d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
263d874057dim    }
264d874057dim    catch (...)
265d874057dim    {
266d874057dim        for (unsigned i = 0; i < facets_.size(); ++i)
267d874057dim            if (facets_[i])
268d874057dim                facets_[i]->__release_shared();
269d874057dim        throw;
270d874057dim    }
271d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
272d874057dim}
273d874057dim
274d874057dim// NOTE avoid the `base class should be explicitly initialized in the
275d874057dim// copy constructor` warning emitted by GCC
276d874057dim#if defined(__clang__) || _GNUC_VER >= 406
277d874057dim#pragma GCC diagnostic push
278d874057dim#pragma GCC diagnostic ignored "-Wextra"
279d874057dim#endif
280d874057dim
281d874057dimlocale::__imp::__imp(const __imp& other)
282d874057dim    : facets_(max<size_t>(N, other.facets_.size())),
283d874057dim      name_(other.name_)
284d874057dim{
285d874057dim    facets_ = other.facets_;
286d874057dim    for (unsigned i = 0; i < facets_.size(); ++i)
287d874057dim        if (facets_[i])
288d874057dim            facets_[i]->__add_shared();
289d874057dim}
290d874057dim
291d874057dim#if defined(__clang__) || _GNUC_VER >= 406
292d874057dim#pragma GCC diagnostic pop
293d874057dim#endif
294d874057dim
295d874057dimlocale::__imp::__imp(const __imp& other, const string& name, locale::category c)
296d874057dim    : facets_(N),
297d874057dim      name_("*")
298d874057dim{
299d874057dim    facets_ = other.facets_;
300d874057dim    for (unsigned i = 0; i < facets_.size(); ++i)
301d874057dim        if (facets_[i])
302d874057dim            facets_[i]->__add_shared();
303d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
304d874057dim    try
305d874057dim    {
306d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
307d874057dim        if (c & locale::collate)
308d874057dim        {
309d874057dim            install(new collate_byname<char>(name));
310d874057dim            install(new collate_byname<wchar_t>(name));
311d874057dim        }
312d874057dim        if (c & locale::ctype)
313d874057dim        {
314d874057dim            install(new ctype_byname<char>(name));
315d874057dim            install(new ctype_byname<wchar_t>(name));
316d874057dim            install(new codecvt_byname<char, char, mbstate_t>(name));
317d874057dim            install(new codecvt_byname<wchar_t, char, mbstate_t>(name));
318d874057dim            install(new codecvt_byname<char16_t, char, mbstate_t>(name));
319d874057dim            install(new codecvt_byname<char32_t, char, mbstate_t>(name));
320d874057dim        }
321d874057dim        if (c & locale::monetary)
322d874057dim        {
323d874057dim            install(new moneypunct_byname<char, false>(name));
324d874057dim            install(new moneypunct_byname<char, true>(name));
325d874057dim            install(new moneypunct_byname<wchar_t, false>(name));
326d874057dim            install(new moneypunct_byname<wchar_t, true>(name));
327d874057dim        }
328d874057dim        if (c & locale::numeric)
329d874057dim        {
330d874057dim            install(new numpunct_byname<char>(name));
331d874057dim            install(new numpunct_byname<wchar_t>(name));
332d874057dim        }
333d874057dim        if (c & locale::time)
334d874057dim        {
335d874057dim            install(new time_get_byname<char>(name));
336d874057dim            install(new time_get_byname<wchar_t>(name));
337d874057dim            install(new time_put_byname<char>(name));
338d874057dim            install(new time_put_byname<wchar_t>(name));
339d874057dim        }
340d874057dim        if (c & locale::messages)
341d874057dim        {
342d874057dim            install(new messages_byname<char>(name));
343d874057dim            install(new messages_byname<wchar_t>(name));
344d874057dim        }
345d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
346d874057dim    }
347d874057dim    catch (...)
348d874057dim    {
349d874057dim        for (unsigned i = 0; i < facets_.size(); ++i)
350d874057dim            if (facets_[i])
351d874057dim                facets_[i]->__release_shared();
352d874057dim        throw;
353d874057dim    }
354d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
355d874057dim}
356d874057dim
357d874057dimtemplate<class F>
358d874057diminline
359d874057dimvoid
360d874057dimlocale::__imp::install_from(const locale::__imp& one)
361d874057dim{
362d874057dim    long id = F::id.__get();
363d874057dim    install(const_cast<F*>(static_cast<const F*>(one.use_facet(id))), id);
364d874057dim}
365d874057dim
366d874057dimlocale::__imp::__imp(const __imp& other, const __imp& one, locale::category c)
367d874057dim    : facets_(N),
368d874057dim      name_("*")
369d874057dim{
370d874057dim    facets_ = other.facets_;
371d874057dim    for (unsigned i = 0; i < facets_.size(); ++i)
372d874057dim        if (facets_[i])
373d874057dim            facets_[i]->__add_shared();
374d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
375d874057dim    try
376d874057dim    {
377d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
378d874057dim        if (c & locale::collate)
379d874057dim        {
380d874057dim            install_from<_VSTD::collate<char> >(one);
381d874057dim            install_from<_VSTD::collate<wchar_t> >(one);
382d874057dim        }
383d874057dim        if (c & locale::ctype)
384d874057dim        {
385d874057dim            install_from<_VSTD::ctype<char> >(one);
386d874057dim            install_from<_VSTD::ctype<wchar_t> >(one);
387d874057dim            install_from<_VSTD::codecvt<char, char, mbstate_t> >(one);
388d874057dim            install_from<_VSTD::codecvt<char16_t, char, mbstate_t> >(one);
389d874057dim            install_from<_VSTD::codecvt<char32_t, char, mbstate_t> >(one);
390d874057dim            install_from<_VSTD::codecvt<wchar_t, char, mbstate_t> >(one);
391d874057dim        }
392d874057dim        if (c & locale::monetary)
393d874057dim        {
394d874057dim            install_from<moneypunct<char, false> >(one);
395d874057dim            install_from<moneypunct<char, true> >(one);
396d874057dim            install_from<moneypunct<wchar_t, false> >(one);
397d874057dim            install_from<moneypunct<wchar_t, true> >(one);
398d874057dim            install_from<money_get<char> >(one);
399d874057dim            install_from<money_get<wchar_t> >(one);
400d874057dim            install_from<money_put<char> >(one);
401d874057dim            install_from<money_put<wchar_t> >(one);
402d874057dim        }
403d874057dim        if (c & locale::numeric)
404d874057dim        {
405d874057dim            install_from<numpunct<char> >(one);
406d874057dim            install_from<numpunct<wchar_t> >(one);
407d874057dim            install_from<num_get<char> >(one);
408d874057dim            install_from<num_get<wchar_t> >(one);
409d874057dim            install_from<num_put<char> >(one);
410d874057dim            install_from<num_put<wchar_t> >(one);
411d874057dim        }
412d874057dim        if (c & locale::time)
413d874057dim        {
414d874057dim            install_from<time_get<char> >(one);
415d874057dim            install_from<time_get<wchar_t> >(one);
416d874057dim            install_from<time_put<char> >(one);
417d874057dim            install_from<time_put<wchar_t> >(one);
418d874057dim        }
419d874057dim        if (c & locale::messages)
420d874057dim        {
421d874057dim            install_from<_VSTD::messages<char> >(one);
422d874057dim            install_from<_VSTD::messages<wchar_t> >(one);
423d874057dim        }
424d874057dim#ifndef _LIBCPP_NO_EXCEPTIONS
425d874057dim    }
426d874057dim    catch (...)
427d874057dim    {
428d874057dim        for (unsigned i = 0; i < facets_.size(); ++i)
429d874057dim            if (facets_[i])
430d874057dim                facets_[i]->__release_shared();
431d874057dim        throw;
432d874057dim    }
433d874057dim#endif  // _LIBCPP_NO_EXCEPTIONS
434d874057dim}
435d874057dim
436d874057dimlocale::__imp::__imp(const __imp& other, facet* f, long id)
437d874057dim    : facets_(max<size_t>(N, other.facets_.size()+1)),
438d874057dim      name_("*")
439d874057dim{
440d874057dim    f->__add_shared();
441d874057dim    unique_ptr<facet, release> hold(f);
442d874057dim    facets_ = other.facets_;
443d874057dim    for (unsigned i = 0; i < other.facets_.size(); ++i)
444d874057dim        if (facets_[i])
445d874057dim            facets_[i]->__add_shared();
446d874057dim    install(hold.get(), id);
447d874057dim}
448d874057dim
449d874057dimlocale::__imp::~__imp()
450d874057dim{
451d874057dim    for (unsigned i = 0; i < facets_.size(); ++i)
452d874057dim        if (facets_[i])
453d874057dim            facets_[i]->__release_shared();
454d874057dim}
455d874057dim
456d874057dimvoid
457d874057dimlocale::__imp::install(facet* f, long id)
458d874057dim{
459d874057dim    f->__add_shared();
460d874057dim    unique_ptr<facet, release> hold(f);
461d874057dim    if (static_cast<size_t>(id) >= facets_.size())
462d874057dim        facets_.resize(static_cast<size_t>(id+1));
463d874057dim    if (facets_[static_cast<size_t>(id)])
464d874057dim        facets_[static_cast<size_t>(id)]->__release_shared();
465d874057dim    facets_[static_cast<size_t>(id)] = hold.release();
466d874057dim}
467d874057dim
468d874057dimconst locale::facet*
469d874057dimlocale::__imp::use_facet(long id) const
470d874057dim{
471d874057dim    if (!has_facet(id))
472d874057dim        __throw_bad_cast();
473d874057dim    return facets_[static_cast<size_t>(id)];
474d874057dim}
475d874057dim
476d874057dim// locale
477d874057dim
478d874057dimconst locale&
479d874057dimlocale::__imp::make_classic()
480d874057dim{
481d874057dim    // only one thread can get in here and it only gets in once
482d874057dim    static aligned_storage<sizeof(locale)>::type buf;
483d874057dim    locale* c = reinterpret_cast<locale*>(&buf);
484d874057dim    c->__locale_ = &make<__imp>(1u);
485d874057dim    return *c;
486d874057dim}
487d874057dim
488d874057dimconst locale&
489d874057dimlocale::classic()
490d874057dim{
491d874057dim    static const locale& c = __imp::make_classic();
492d874057dim    return c;
493d874057dim}
494d874057dim
495d874057dimlocale&
496d874057dimlocale::__imp::make_global()
497d874057dim{
498d874057dim    // only one thread can get in here and it only gets in once
499d874057dim    static aligned_storage<sizeof(locale)>::type buf;
500d874057dim    auto *obj = ::new (&buf) locale(locale::classic());
501d874057dim    return *obj;
502d874057dim}
503d874057dim
504d874057dimlocale&
505d874057dimlocale::__global()
506d874057dim{
507d874057dim    static locale& g = __imp::make_global();
508d874057dim    return g;
509d874057dim}
510d874057dim
511d874057dimlocale::locale()  _NOEXCEPT
512d874057dim    : __locale_(__global().__locale_)
513d874057dim{
514d874057dim    __locale_->__add_shared();
515d874057dim}
516d874057dim
517d874057dimlocale::locale(const locale& l)  _NOEXCEPT
518d874057dim    : __locale_(l.__locale_)
519d874057dim{
520d874057dim    __locale_->__add_shared();
521d874057dim}
522d874057dim
523d874057dimlocale::~locale()
524d874057dim{
525d874057dim    __locale_->__release_shared();
526d874057dim}
527d874057dim
528d874057dimconst locale&
529d874057dimlocale::operator=(const locale& other)  _NOEXCEPT
530d874057dim{
531d874057dim    other.__locale_->__add_shared();
532d874057dim    __locale_->__release_shared();
533d874057dim    __locale_ = other.__locale_;
534d874057dim    return *this;
535d874057dim}
536d874057dim
537d874057dimlocale::locale(const char* name)
538d874057dim    : __locale_(name ? new __imp(name)
539d874057dim                     : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
540d874057dim{
541d874057dim    __locale_->__add_shared();
542d874057dim}
543d874057dim
544d874057dimlocale::locale(const string& name)
545d874057dim    : __locale_(new __imp(name))
546d874057dim{
547d874057dim    __locale_->__add_shared();
548d874057dim}
549d874057dim
550d874057dimlocale::locale(const locale& other, const char* name, category c)
551d874057dim    : __locale_(name ? new __imp(*other.__locale_, name, c)
552d874057dim                     : (__throw_runtime_error("locale constructed with null"), (__imp*)0))
553d874057dim{
554d874057dim    __locale_->__add_shared();
555d874057dim}
556d874057dim
557d874057dimlocale::locale(const locale& other, const string& name, category c)
558d874057dim    : __locale_(new __imp(*other.__locale_, name, c))
559d874057dim{
560d874057dim    __locale_->__add_shared();
561d874057dim}
562d874057dim
563d874057dimlocale::locale(const locale& other, const locale& one, category c)
564d874057dim    : __locale_(new __imp(*other.__locale_, *one.__locale_, c))
565d874057dim{
566d874057dim    __locale_->__add_shared();
567d874057dim}
568d874057dim
569d874057dimstring
570d874057dimlocale::name() const
571d874057dim{
572d874057dim    return __locale_->name();
573d874057dim}
574d874057dim
575d874057dimvoid
576d874057dimlocale::__install_ctor(const locale& other, facet* f, long id)
577d874057dim{
578d874057dim    if (f)
579d874057dim        __locale_ = new __imp(*other.__locale_, f, id);
580d874057dim    else
581d874057dim        __locale_ = other.__locale_;
582d874057dim    __locale_->__add_shared();
583d874057dim}
584d874057dim
585d874057dimlocale
586d874057dimlocale::global(const locale& loc)
587d874057dim{
588d874057dim    locale& g = __global();
589d874057dim    locale r = g;
590d874057dim    g = loc;
591d874057dim    if (g.name() != "*")
592d874057dim        setlocale(LC_ALL, g.name().c_str());
593d874057dim    return r;
594d874057dim}
595d874057dim
596d874057dimbool
597d874057dimlocale::has_facet(id& x) const
598d874057dim{
599d874057dim    return __locale_->has_facet(x.__get());
600d874057dim}
601d874057dim
602d874057dimconst locale::facet*
603d874057dimlocale::use_facet(id& x) const
604d874057dim{
605d874057dim    return __locale_->use_facet(x.__get());
606d874057dim}
607d874057dim
608d874057dimbool
609d874057dimlocale::operator==(const locale& y) const
610d874057dim{
611d874057dim    return (__locale_ == y.__locale_)
612d874057dim        || (__locale_->name() != "*" && __locale_->name() == y.__locale_->name());
613d874057dim}
614d874057dim
615d874057dim// locale::facet
616d874057dim
617d874057dimlocale::facet::~facet()
618d874057dim{
619d874057dim}
620d874057dim
621d874057dimvoid
622d874057dimlocale::facet::__on_zero_shared() _NOEXCEPT
623d874057dim{
624d874057dim    delete this;
625d874057dim}
626d874057dim
627d874057dim// locale::id
628d874057dim
629d874057dimint32_t locale::id::__next_id = 0;
630d874057dim
631d874057dimnamespace
632d874057dim{
633d874057dim
634d874057dimclass __fake_bind
635d874057dim{
636d874057dim    locale::id* id_;
637d874057dim    void (locale::id::* pmf_)();
638d874057dimpublic:
639d874057dim    __fake_bind(void (locale::id::* pmf)(), locale::id* id)
640d874057dim        : id_(id), pmf_(pmf) {}
641d874057dim
642d874057dim    void operator()() const
643d874057dim    {
644d874057dim        (id_->*pmf_)();
645d874057dim    }
646d874057dim};
647d874057dim
648d874057dim}
649d874057dim
650d874057dimlong
651d874057dimlocale::id::__get()
652d874057dim{
653d874057dim    call_once(__flag_, __fake_bind(&locale::id::__init, this));
654d874057dim    return __id_ - 1;
655d874057dim}
656d874057dim
657d874057dimvoid
658d874057dimlocale::id::__init()
659d874057dim{
660d874057dim    __id_ = __libcpp_atomic_add(&__next_id, 1);
661d874057dim}
662d874057dim
663d874057dim// template <> class collate_byname<char>
664d874057dim
665d874057dimcollate_byname<char>::collate_byname(const char* n, size_t refs)
666d874057dim    : collate<char>(refs),
667d874057dim      __l(newlocale(LC_ALL_MASK, n, 0))
668d874057dim{
669d874057dim    if (__l == 0)
670d874057dim        __throw_runtime_error("collate_byname<char>::collate_byname"
671d874057dim                            " failed to construct for " + string(n));
672d874057dim}
673d874057dim
674d874057dimcollate_byname<char>::collate_byname(const string& name, size_t refs)
675d874057dim    : collate<char>(refs),
676d874057dim      __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
677d874057dim{
678d874057dim    if (__l == 0)
679d874057dim        __throw_runtime_error("collate_byname<char>::collate_byname"
680d874057dim                            " failed to construct for " + name);
681d874057dim}
682d874057dim
683d874057dimcollate_byname<char>::~collate_byname()
684d874057dim{
685d874057dim    freelocale(__l);
686d874057dim}
687d874057dim
688d874057dimint
689d874057dimcollate_byname<char>::do_compare(const char_type* __lo1, const char_type* __hi1,
690d874057dim                                 const char_type* __lo2, const char_type* __hi2) const
691d874057dim{
692d874057dim    string_type lhs(__lo1, __hi1);
693d874057dim    string_type rhs(__lo2, __hi2);
694d874057dim    int r = strcoll_l(lhs.c_str(), rhs.c_str(), __l);
695d874057dim    if (r < 0)
696d874057dim        return -1;
697d874057dim    if (r > 0)
698d874057dim        return 1;
699d874057dim    return r;
700d874057dim}
701d874057dim
702d874057dimcollate_byname<char>::string_type
703d874057dimcollate_byname<char>::do_transform(const char_type* lo, const char_type* hi) const
704d874057dim{
705d874057dim    const string_type in(lo, hi);
706d874057dim    string_type out(strxfrm_l(0, in.c_str(), 0, __l), char());
707d874057dim    strxfrm_l(const_cast<char*>(out.c_str()), in.c_str(), out.size()+1, __l);
708d874057dim    return out;
709d874057dim}
710d874057dim
711d874057dim// template <> class collate_byname<wchar_t>
712d874057dim
713d874057dimcollate_byname<wchar_t>::collate_byname(const char* n, size_t refs)
714d874057dim    : collate<wchar_t>(refs),
715d874057dim      __l(newlocale(LC_ALL_MASK, n, 0))
716d874057dim{
717d874057dim    if (__l == 0)
718d874057dim        __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
719d874057dim                            " failed to construct for " + string(n));
720d874057dim}
721d874057dim
722d874057dimcollate_byname<wchar_t>::collate_byname(const string& name, size_t refs)
723d874057dim    : collate<wchar_t>(refs),
724d874057dim      __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
725d874057dim{
726d874057dim    if (__l == 0)
727d874057dim        __throw_runtime_error("collate_byname<wchar_t>::collate_byname(size_t refs)"
728d874057dim                            " failed to construct for " + name);
729d874057dim}
730d874057dim
731d874057dimcollate_byname<wchar_t>::~collate_byname()
732d874057dim{
733d874057dim    freelocale(__l);
734d874057dim}
735d874057dim
736d874057dimint
737d874057dimcollate_byname<wchar_t>::do_compare(const char_type* __lo1, const char_type* __hi1,
738d874057dim                                 const char_type* __lo2, const char_type* __hi2) const
739d874057dim{
740d874057dim    string_type lhs(__lo1, __hi1);
741d874057dim    string_type rhs(__lo2, __hi2);
742d874057dim    int r = wcscoll_l(lhs.c_str(), rhs.c_str(), __l);
743d874057dim    if (r < 0)
744d874057dim        return -1;
745d874057dim    if (r > 0)
746d874057dim        return 1;
747d874057dim    return r;
748d874057dim}
749d874057dim
750d874057dimcollate_byname<wchar_t>::string_type
751d874057dimcollate_byname<wchar_t>::do_transform(const char_type* lo, const char_type* hi) const
752d874057dim{
753d874057dim    const string_type in(lo, hi);
754d874057dim    string_type out(wcsxfrm_l(0, in.c_str(), 0, __l), wchar_t());
755d874057dim    wcsxfrm_l(const_cast<wchar_t*>(out.c_str()), in.c_str(), out.size()+1, __l);
756d874057dim    return out;
757d874057dim}
758d874057dim
759d874057dim// template <> class ctype<wchar_t>;
760d874057dim
761d874057dimconst ctype_base::mask ctype_base::space;
762d874057dimconst ctype_base::mask ctype_base::print;
763d874057dimconst ctype_base::mask ctype_base::cntrl;
764d874057dimconst ctype_base::mask ctype_base::upper;
765d874057dimconst ctype_base::mask ctype_base::lower;
766d874057dimconst ctype_base::mask ctype_base::alpha;
767d874057dimconst ctype_base::mask ctype_base::digit;
768d874057dimconst ctype_base::mask ctype_base::punct;
769d874057dimconst ctype_base::mask ctype_base::xdigit;
770d874057dimconst ctype_base::mask ctype_base::blank;
771d874057dimconst ctype_base::mask ctype_base::alnum;
772d874057dimconst ctype_base::mask ctype_base::graph;
773332da66dim
774d874057dimlocale::id ctype<wchar_t>::id;
775d874057dim
776d874057dimctype<wchar_t>::~ctype()
777d874057dim{
778d874057dim}
779d874057dim
780d874057dimbool
781d874057dimctype<wchar_t>::do_is(mask m, char_type c) const
782d874057dim{
783d874057dim    return isascii(c) ? (ctype<char>::classic_table()[c] & m) != 0 : false;
784d874057dim}
785d874057dim
786d874057dimconst wchar_t*
787d874057dimctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
788d874057dim{
789d874057dim    for (; low != high; ++low, ++vec)
790d874057dim        *vec = static_cast<mask>(isascii(*low) ?
791d874057dim                                   ctype<char>::classic_table()[*low] : 0);
792d874057dim    return low;
793d874057dim}
794d874057dim
795d874057dimconst wchar_t*
796d874057dimctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
797d874057dim{
798d874057dim    for (; low != high; ++low)
799d874057dim        if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
800d874057dim            break;
801d874057dim    return low;
802d874057dim}
803d874057dim
804d874057dimconst wchar_t*
805d874057dimctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
806d874057dim{
807d874057dim    for (; low != high; ++low)
808d874057dim        if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
809d874057dim            break;
810d874057dim    return low;
811d874057dim}
812d874057dim
813d874057dimwchar_t
814d874057dimctype<wchar_t>::do_toupper(char_type c) const
815d874057dim{
816d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
817d874057dim    return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
818d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
819d874057dim      defined(__NetBSD__)
820d874057dim    return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
821d874057dim#else
822d874057dim    return (isascii(c) && iswlower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'a'+L'A' : c;
823d874057dim#endif
824d874057dim}
825d874057dim
826d874057dimconst wchar_t*
827d874057dimctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
828d874057dim{
829d874057dim    for (; low != high; ++low)
830d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
831d874057dim        *low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low;
832d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
833d874057dim      defined(__NetBSD__)
834d874057dim        *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
835d874057dim                             : *low;
836d874057dim#else
837d874057dim        *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? (*low-L'a'+L'A') : *low;
838d874057dim#endif
839d874057dim    return low;
840d874057dim}
841d874057dim
842d874057dimwchar_t
843d874057dimctype<wchar_t>::do_tolower(char_type c) const
844d874057dim{
845d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
846d874057dim    return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
847d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
848d874057dim      defined(__NetBSD__)
849d874057dim    return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
850d874057dim#else
851d874057dim    return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-L'A'+'a' : c;
852d874057dim#endif
853d874057dim}
854d874057dim
855d874057dimconst wchar_t*
856d874057dimctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
857d874057dim{
858d874057dim    for (; low != high; ++low)
859d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
860d874057dim        *low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low;
861d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__) || \
862d874057dim      defined(__NetBSD__)
863d874057dim        *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
864d874057dim                             : *low;
865d874057dim#else
866d874057dim        *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-L'A'+L'a' : *low;
867d874057dim#endif
868d874057dim    return low;
869d874057dim}
870d874057dim
871d874057dimwchar_t
872d874057dimctype<wchar_t>::do_widen(char c) const
873d874057dim{
874d874057dim    return c;
875d874057dim}
876d874057dim
877d874057dimconst char*
878d874057dimctype<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
879d874057dim{
880d874057dim    for (; low != high; ++low, ++dest)
881d874057dim        *dest = *low;
882d874057dim    return low;
883d874057dim}
884d874057dim
885d874057dimchar
886d874057dimctype<wchar_t>::do_narrow(char_type c, char dfault) const
887d874057dim{
888d874057dim    if (isascii(c))
889d874057dim        return static_cast<char>(c);
890d874057dim    return dfault;
891d874057dim}
892d874057dim
893d874057dimconst wchar_t*
894d874057dimctype<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
895d874057dim{
896d874057dim    for (; low != high; ++low, ++dest)
897d874057dim        if (isascii(*low))
898d874057dim            *dest = static_cast<char>(*low);
899d874057dim        else
900d874057dim            *dest = dfault;
901d874057dim    return low;
902d874057dim}
903d874057dim
904d874057dim// template <> class ctype<char>;
905d874057dim
906d874057dimlocale::id ctype<char>::id;
907d874057dim
908d874057dimctype<char>::ctype(const mask* tab, bool del, size_t refs)
909d874057dim    : locale::facet(refs),
910d874057dim      __tab_(tab),
911d874057dim      __del_(del)
912d874057dim{
913d874057dim  if (__tab_ == 0)
914d874057dim      __tab_ = classic_table();
915d874057dim}
916d874057dim
917d874057dimctype<char>::~ctype()
918d874057dim{
919d874057dim    if (__tab_ && __del_)
920d874057dim        delete [] __tab_;
921d874057dim}
922d874057dim
923d874057dimchar
924d874057dimctype<char>::do_toupper(char_type c) const
925d874057dim{
926d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
927d874057dim    return isascii(c) ?
928d874057dim      static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(c)]) : c;
929d874057dim#elif defined(__NetBSD__)
930d874057dim    return static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]);
931d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
932d874057dim    return isascii(c) ?
933d874057dim      static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(c)]) : c;
934d874057dim#else
935d874057dim    return (isascii(c) && islower_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'a'+'A' : c;
936d874057dim#endif
937d874057dim}
938d874057dim
939d874057dimconst char*
940d874057dimctype<char>::do_toupper(char_type* low, const char_type* high) const
941d874057dim{
942d874057dim    for (; low != high; ++low)
943d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
944d874057dim        *low = isascii(*low) ?
945d874057dim          static_cast<char>(_DefaultRuneLocale.__mapupper[static_cast<ptrdiff_t>(*low)]) : *low;
946d874057dim#elif defined(__NetBSD__)
947d874057dim        *low = static_cast<char>(__classic_upper_table()[static_cast<unsigned char>(*low)]);
948d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
949d874057dim        *low = isascii(*low) ?
950d874057dim          static_cast<char>(__classic_upper_table()[static_cast<size_t>(*low)]) : *low;
951d874057dim#else
952d874057dim        *low = (isascii(*low) && islower_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'a'+'A' : *low;
953d874057dim#endif
954d874057dim    return low;
955d874057dim}
956d874057dim
957d874057dimchar
958d874057dimctype<char>::do_tolower(char_type c) const
959d874057dim{
960d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
961d874057dim    return isascii(c) ?
962d874057dim      static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(c)]) : c;
963d874057dim#elif defined(__NetBSD__)
964d874057dim    return static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(c)]);
965d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
966d874057dim    return isascii(c) ?
967d874057dim      static_cast<char>(__classic_lower_table()[static_cast<size_t>(c)]) : c;
968d874057dim#else
969d874057dim    return (isascii(c) && isupper_l(c, _LIBCPP_GET_C_LOCALE)) ? c-'A'+'a' : c;
970d874057dim#endif
971d874057dim}
972d874057dim
973d874057dimconst char*
974d874057dimctype<char>::do_tolower(char_type* low, const char_type* high) const
975d874057dim{
976d874057dim    for (; low != high; ++low)
977d874057dim#ifdef _LIBCPP_HAS_DEFAULTRUNELOCALE
978d874057dim        *low = isascii(*low) ? static_cast<char>(_DefaultRuneLocale.__maplower[static_cast<ptrdiff_t>(*low)]) : *low;
979d874057dim#elif defined(__NetBSD__)
980d874057dim        *low = static_cast<char>(__classic_lower_table()[static_cast<unsigned char>(*low)]);
981d874057dim#elif defined(__GLIBC__) || defined(__EMSCRIPTEN__)
982d874057dim        *low = isascii(*low) ? static_cast<char>(__classic_lower_table()[static_cast<size_t>(*low)]) : *low;
983d874057dim#else
984d874057dim        *low = (isascii(*low) && isupper_l(*low, _LIBCPP_GET_C_LOCALE)) ? *low-'A'+'a' : *low;
985d874057dim#endif
986d874057dim    return low;
987d874057dim}
988d874057dim
989d874057dimchar
990d874057dimctype<char>::do_widen(char c) const
991d874057dim{
992d874057dim    return c;
993d874057dim}
994d874057dim
995d874057dimconst char*
996d874057dimctype<char>::do_widen(const char* low, const char* high, char_type* dest) const
997d874057dim{
998d874057dim    for (; low != high; ++low, ++dest)
999d874057dim        *dest = *low;
1000d874057dim    return low;
1001d874057dim}
1002d874057dim
1003d874057dimchar
1004d874057dimctype<char>::do_narrow(char_type c, char dfault) const
1005d874057dim{
1006d874057dim    if (isascii(c))
1007d874057dim        return static_cast<char>(c);
1008d874057dim    return dfault;
1009d874057dim}
1010d874057dim
1011d874057dimconst char*
1012d874057dimctype<char>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
1013d874057dim{
1014d874057dim    for (; low != high; ++low, ++dest)
1015d874057dim        if (isascii(*low))
1016d874057dim            *dest = *low;
1017d874057dim        else
1018d874057dim            *dest = dfault;
1019d874057dim    return low;
1020d874057dim}
1021d874057dim
1022d874057dim#if defined(__EMSCRIPTEN__)
1023d874057dimextern "C" const unsigned short ** __ctype_b_loc();
1024d874057dimextern "C" const int ** __ctype_tolower_loc();
1025d874057dimextern "C" const int ** __ctype_toupper_loc();
1026d874057dim#endif
1027d874057dim
1028d874057dim#ifdef _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
1029d874057dimconst ctype<char>::mask*
1030d874057dimctype<char>::classic_table()  _NOEXCEPT
1031d874057dim{
1032d874057dim    static _LIBCPP_CONSTEXPR const ctype<char>::mask builtin_table[table_size] = {
1033d874057dim        cntrl,                          cntrl,
1034d874057dim        cntrl,                          cntrl,
1035d874057dim        cntrl,                          cntrl,
1036d874057dim        cntrl,                          cntrl,
1037d874057dim        cntrl,                          cntrl | space | blank,
1038d874057dim        cntrl | space,                  cntrl | space,
1039d874057dim        cntrl | space,                  cntrl | space,
1040d874057dim        cntrl,                          cntrl,
1041d874057dim        cntrl,                          cntrl,
1042d874057dim        cntrl,                          cntrl,
1043d874057dim        cntrl,                          cntrl,
1044d874057dim        cntrl,                          cntrl,
1045d874057dim        cntrl,                          cntrl,
1046d874057dim        cntrl,                          cntrl,
1047d874057dim        cntrl,                          cntrl,
1048d874057dim        cntrl,                          cntrl,
1049d874057dim        space | blank | print,          punct | print,
1050d874057dim        punct | print,                  punct | print,
1051d874057dim        punct | print,                  punct | print,
1052d874057dim        punct | print,                  punct | print,
1053d874057dim        punct | print,                  punct | print,
1054d874057dim        punct | print,                  punct | print,
1055d874057dim        punct | print,                  punct | print,
1056d874057dim        punct | print,                  punct | print,
1057d874057dim        digit | print | xdigit,         digit | print | xdigit,
1058d874057dim        digit | print | xdigit,         digit | print | xdigit,
1059d874057dim        digit | print | xdigit,         digit | print | xdigit,
1060d874057dim        digit | print | xdigit,         digit | print | xdigit,
1061d874057dim        digit | print | xdigit,         digit | print | xdigit,
1062d874057dim        punct | print,                  punct | print,
1063d874057dim        punct | print,                  punct | print,
1064d874057dim        punct | print,                  punct | print,
1065d874057dim        punct | print,                  upper | xdigit | print | alpha,
1066d874057dim        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
1067d874057dim        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
1068d874057dim        upper | xdigit | print | alpha, upper | print | alpha,
1069d874057dim        upper | print | alpha,          upper | print | alpha,
1070d874057dim        upper | print | alpha,          upper | print | alpha,
1071d874057dim        upper | print | alpha,          upper | print | alpha,
1072d874057dim        upper | print | alpha,          upper | print | alpha,
1073d874057dim        upper | print | alpha,          upper | print | alpha,
1074d874057dim        upper | print | alpha,          upper | print | alpha,
1075d874057dim        upper | print | alpha,          upper | print | alpha,
1076d874057dim        upper | print | alpha,          upper | print | alpha,
1077d874057dim        upper | print | alpha,          upper | print | alpha,
1078d874057dim        upper | print | alpha,          punct | print,
1079d874057dim        punct | print,                  punct | print,
1080d874057dim        punct | print,                  punct | print,
1081d874057dim        punct | print,                  lower | xdigit | print | alpha,
1082d874057dim        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
1083d874057dim        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
1084d874057dim        lower | xdigit | print | alpha, lower | print | alpha,
1085d874057dim        lower | print | alpha,          lower | print | alpha,
1086d874057dim        lower | print | alpha,          lower | print | alpha,
1087d874057dim        lower | print | alpha,          lower | print | alpha,
1088d874057dim        lower | print | alpha,          lower | print | alpha,
1089d874057dim        lower | print | alpha,          lower | print | alpha,
1090d874057dim        lower | print | alpha,          lower | print | alpha,
1091d874057dim        lower | print | alpha,          lower | print | alpha,
1092d874057dim        lower | print | alpha,          lower | print | alpha,
1093d874057dim        lower | print | alpha,          lower | print | alpha,
1094d874057dim        lower | print | alpha,          punct | print,
1095d874057dim        punct | print,                  punct | print,
1096d874057dim        punct | print,                  cntrl,
1097d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1098d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1099d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1100d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1101d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1102d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1103d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1104d874057dim        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1105d874057dim    };
1106d874057dim    return builtin_table;
1107d874057dim}
1108d874057dim#else
1109d874057dimconst ctype<char>::mask*
1110d874057dimctype<char>::classic_table()  _NOEXCEPT
1111d874057dim{
1112d874057dim#if defined(__APPLE__) || defined(__FreeBSD__)
1113d874057dim    return _DefaultRuneLocale.__runetype;
1114d874057dim#elif defined(__NetBSD__)
1115d874057dim    return _C_ctype_tab_ + 1;
1116d874057dim#elif defined(__GLIBC__)
1117d874057dim    return _LIBCPP_GET_C_LOCALE->__ctype_b;
1118d874057dim#elif __sun__
1119d874057dim    return __ctype_mask;
1120d874057dim#elif defined(_LIBCPP_MSVCRT) || defined(__MINGW32__)
1121d874057dim    return __pctype_func();
1122d874057dim#elif defined(__EMSCRIPTEN__)
1123d874057dim    return *__ctype_b_loc();
1124d874057dim#elif defined(_NEWLIB_VERSION)
1125d874057dim    // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
1126d874057dim    return _ctype_ + 1;
1127d874057dim#elif defined(_AIX)
1128d874057dim    return (const unsigned int *)__lc_ctype_ptr->obj->mask;
1129d874057dim#else
1130d874057dim    // Platform not supported: abort so the person doing the port knows what to
1131d874057dim    // fix
1132d874057dim# warning  ctype<char>::classic_table() is not implemented
1133d874057dim    printf("ctype<char>::classic_table() is not implemented\n");
1134d874057dim    abort();
1135d874057dim    return NULL;
1136d874057dim#endif
1137d874057dim}
1138d874057dim#endif
1139d874057dim
1140d874057dim#if defined(__GLIBC__)
1141d874057dimconst int*
1142d874057dimctype<char>::__classic_lower_table() _NOEXCEPT
1143d874057dim{
1144d874057dim    return _LIBCPP_GET_C_LOCALE->__ctype_tolower;
1145d874057dim}
1146d874057dim
1147d874057dimconst int*
1148d874057dimctype<char>::__classic_upper_table() _NOEXCEPT
1149d874057dim{
1150d874057dim    return _LIBCPP_GET_C_LOCALE->__ctype_toupper;
1151d874057dim}
1152d874057dim#elif __NetBSD__
1153d874057dimconst short*
1154d874057dimctype<char>::__classic_lower_table() _NOEXCEPT
1155d874057dim{
1156d874057dim    return _C_tolower_tab_ + 1;
1157d874057dim}
1158d874057dim
1159d874057dimconst short*
1160d874057dimctype<char>::__classic_upper_table() _NOEXCEPT
1161d874057dim{
1162d874057dim    return _C_toupper_tab_ + 1;
1163d874057dim}
1164d874057dim
1165d874057dim#elif defined(__EMSCRIPTEN__)
1166d874057dimconst int*
1167d874057dimctype<char>::__classic_lower_table() _NOEXCEPT
1168d874057dim{
1169d874057dim    return *__ctype_tolower_loc();
1170d874057dim}
1171d874057dim
1172d874057dimconst int*
1173d874057dimctype<char>::__classic_upper_table() _NOEXCEPT
1174d874057dim{
1175d874057dim    return *__ctype_toupper_loc();
1176d874057dim}
1177d874057dim#endif // __GLIBC__ || __NETBSD__ || __EMSCRIPTEN__
1178d874057dim
1179d874057dim// template <> class ctype_byname<char>
1180d874057dim
1181d874057dimctype_byname<char>::ctype_byname(const char* name, size_t refs)
1182d874057dim    : ctype<char>(0, false, refs),
1183d874057dim      __l(newlocale(LC_ALL_MASK, name, 0))
1184d874057dim{
1185d874057dim    if (__l == 0)
1186d874057dim        __throw_runtime_error("ctype_byname<char>::ctype_byname"
1187d874057dim                            " failed to construct for " + string(name));
1188d874057dim}
1189d874057dim
1190d874057dimctype_byname<char>::ctype_byname(const string& name, size_t refs)
1191d874057dim    : ctype<char>(0, false, refs),
1192d874057dim      __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
1193d874057dim{
1194d874057dim    if (__l == 0)
1195d874057dim        __throw_runtime_error("ctype_byname<char>::ctype_byname"
1196d874057dim                            " failed to construct for " + name);
1197d874057dim}
1198d874057dim
1199d874057dimctype_byname<char>::~ctype_byname()
1200d874057dim{
1201d874057dim    freelocale(__l);
1202d874057dim}
1203d874057dim
1204d874057dimchar
1205d874057dimctype_byname<char>::do_toupper(char_type c) const
1206d874057dim{
1207d874057dim    return static_cast<char>(toupper_l(static_cast<unsigned char>(c), __l));
1208d874057dim}
1209d874057dim
1210d874057dimconst char*
1211d874057dimctype_byname<char>::do_toupper(char_type* low, const char_type* high) const
1212d874057dim{
1213d874057dim    for (; low != high; ++low)
1214d874057dim        *low = static_cast<char>(toupper_l(static_cast<unsigned char>(*low), __l));
1215d874057dim    return low;
1216d874057dim}
1217d874057dim
1218d874057dimchar
1219d874057dimctype_byname<char>::do_tolower(char_type c) const
1220d874057dim{
1221d874057dim    return static_cast<char>(tolower_l(static_cast<unsigned char>(c), __l));
1222d874057dim}
1223d874057dim
1224d874057dimconst char*
1225d874057dimctype_byname<char>::do_tolower(char_type* low, const char_type* high) const
1226d874057dim{
1227d874057dim    for (; low != high; ++low)
1228d874057dim        *low = static_cast<char>(tolower_l(static_cast<unsigned char>(*low), __l));
1229d874057dim    return low;
1230d874057dim}
1231d874057dim
1232d874057dim// template <> class ctype_byname<wchar_t>
1233d874057dim
1234d874057dimctype_byname<wchar_t>::ctype_byname(const char* name, size_t refs)
1235d874057dim    : ctype<wchar_t>(refs),
1236d874057dim      __l(newlocale(LC_ALL_MASK, name, 0))
1237d874057dim{
1238d874057dim    if (__l == 0)
1239d874057dim        __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
1240d874057dim                            " failed to construct for " + string(name));
1241d874057dim}
1242d874057dim
1243d874057dimctype_byname<wchar_t>::ctype_byname(const string& name, size_t refs)
1244d874057dim    : ctype<wchar_t>(refs),
1245d874057dim      __l(newlocale(LC_ALL_MASK, name.c_str(), 0))
1246d874057dim{
1247d874057dim    if (__l == 0)
1248d874057dim        __throw_runtime_error("ctype_byname<wchar_t>::ctype_byname"
1249d874057dim                            " failed to construct for " + name);
1250d874057dim}
1251d874057dim
1252d874057dimctype_byname<wchar_t>::~ctype_byname()
1253d874057dim{
1254d874057dim    freelocale(__l);
1255d874057dim}
1256d874057dim
1257d874057dimbool
1258d874057dimctype_byname<wchar_t>::do_is(mask m, char_type c) const
1259d874057dim{
1260d874057dim#ifdef _LIBCPP_WCTYPE_IS_MASK
1261d874057dim    return static_cast<bool>(iswctype_l(c, m, __l));
1262d874057dim#else
1263d874057dim    bool result = false;
1264d874057dim    wint_t ch = static_cast<wint_t>(c);
1265d874057dim    if ((m & space) == space) result |= (iswspace_l(ch, __l) != 0);
1266d874057dim    if ((m & print) == print) result |= (iswprint_l(ch, __l) != 0);
1267d874057dim    if ((m & cntrl) == cntrl) result |= (iswcntrl_l(ch, __l) != 0);
1268d874057dim    if ((m & upper) == upper) result |= (iswupper_l(ch, __l) != 0);
1269d874057dim    if ((m & lower) == lower) result |= (iswlower_l(ch, __l) != 0);
1270d874057dim    if ((m & alpha) == alpha) result |= (iswalpha_l(ch, __l) != 0);
1271d874057dim    if ((m & digit) == digit) result |= (iswdigit_l(ch, __l) != 0);
1272d874057dim    if ((m & punct) == punct) result |= (iswpunct_l(ch, __l) != 0);
1273d874057dim    if ((m & xdigit) == xdigit) result |= (iswxdigit_l(ch, __l) != 0);
1274d874057dim    if ((m & blank) == blank) result |= (iswblank_l(ch, __l) != 0);
1275d874057dim    return result;
1276d874057dim#endif
1277d874057dim}
1278d874057dim
1279d874057dimconst wchar_t*
1280d874057dimctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
1281d874057dim{
1282d874057dim    for (; low != high; ++low, ++vec)
1283d874057dim    {
1284d874057dim        if (isascii(*low))
1285d874057dim            *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
1286d874057dim        else
1287d874057dim        {
1288d874057dim            *vec = 0;
1289d874057dim            wint_t ch = static_cast<wint_t>(*low);
1290d874057dim            if (iswspace_l(ch, __l))
1291d874057dim                *vec |= space;
1292d874057dim#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
1293d874057dim            if (iswprint_l(ch, __l))
1294d874057dim                *vec |= print;
1295d874057dim#endif
1296d874057dim            if (iswcntrl_l(ch, __l))
1297d874057dim                *vec |= cntrl;
1298d874057dim            if (iswupper_l(ch, __l))
1299d874057dim                *vec |= upper;
1300d874057dim            if (iswlower_l(ch, __l))
1301d874057dim                *vec |= lower;
1302d874057dim#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
1303d874057dim            if (iswalpha_l(ch, __l))
1304d874057dim                *vec |= alpha;
1305d874057dim#endif
1306d874057dim            if (iswdigit_l(ch, __l))
1307d874057dim                *vec |= digit;
1308d874057dim            if (iswpunct_l(ch, __l))
1309d874057dim                *vec |= punct;
1310d874057dim#ifndef _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
1311d874057dim            if (iswxdigit_l(ch, __l))
1312d874057dim                *vec |= xdigit;
1313d874057dim#endif
1314d874057dim#if !defined(__sun__)
1315d874057dim            if (iswblank_l(ch, __l))
1316d874057dim                *vec |= blank;
1317d874057dim#endif
1318d874057dim        }
1319d874057dim    }
1320d874057dim    return low;
1321d874057dim}
1322d874057dim
1323d874057dimconst wchar_t*
1324d874057dimctype_byname<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
1325d874057dim{
1326d874057dim    for (; low != high; ++low)
1327d874057dim    {
1328d874057dim#ifdef _LIBCPP_WCTYPE_IS_MASK
1329d874057dim        if (iswctype_l(*low, m, __l))
1330d874057dim            break;
1331d874057dim#else
1332d874057dim        wint_t ch = static_cast<wint_t>(*low);
1333d874057dim        if ((m & space) == space && iswspace_l(ch, __l)) break;
1334d874057dim        if ((m & print) == print && iswprint_l(ch, __l)) break;
1335d874057dim        if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) break;
1336d874057dim        if ((m & upper) == upper && iswupper_l(ch, __l)) break;
1337d874057dim        if ((m & lower) == lower && iswlower_l(ch, __l)) break;
1338d874057dim        if ((m & alpha) == alpha && iswalpha_l(ch, __l)) break;
1339d874057dim        if ((m & digit) == digit && iswdigit_l(ch, __l)) break;
1340d874057dim        if ((m & punct) == punct && iswpunct_l(ch, __l)) break;
1341d874057dim        if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) break;
1342d874057dim        if ((m & blank) == blank && iswblank_l(ch, __l)) break;
1343d874057dim#endif
1344d874057dim    }
1345d874057dim    return low;
1346d874057dim}
1347d874057dim
1348d874057dimconst wchar_t*
1349d874057dimctype_byname<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
1350d874057dim{
1351d874057dim    for (; low != high; ++low)
1352d874057dim    {
1353d874057dim#ifdef _LIBCPP_WCTYPE_IS_MASK
1354d874057dim        if (!iswctype_l(*low, m, __l))
1355d874057dim            break;
1356d874057dim#else
1357d874057dim        wint_t ch = static_cast<wint_t>(*low);
1358d874057dim        if ((m & space) == space && iswspace_l(ch, __l)) continue;
1359d874057dim        if ((m & print) == print && iswprint_l(ch, __l)) continue;
1360d874057dim        if ((m & cntrl) == cntrl && iswcntrl_l(ch, __l)) continue;
1361d874057dim        if ((m & upper) == upper && iswupper_l(ch, __l)) continue;
1362d874057dim        if ((m & lower) == lower && iswlower_l(ch, __l)) continue;
1363d874057dim        if ((m & alpha) == alpha && iswalpha_l(ch, __l)) continue;
1364d874057dim        if ((m & digit) == digit && iswdigit_l(ch, __l)) continue;
1365d874057dim        if ((m & punct) == punct && iswpunct_l(ch, __l)) continue;
1366d874057dim        if ((m & xdigit) == xdigit && iswxdigit_l(ch, __l)) continue;
1367d874057dim        if ((m & blank) == blank && iswblank_l(ch, __l)) continue;
1368d874057dim        break;
1369d874057dim#endif
1370d874057dim    }
1371d874057dim    return low;
1372d874057dim}
1373d874057dim
1374d874057dimwchar_t
1375d874057dimctype_byname<wchar_t>::do_toupper(char_type c) const
1376d874057dim{
1377d874057dim    return towupper_l(c, __l);
1378d874057dim}
1379d874057dim
1380d874057dimconst wchar_t*
1381d874057dimctype_byname<wchar_t>::do_toupper(char_type* low, const char_type* high) const
1382d874057dim{
1383d874057dim    for (; low != high; ++low)
1384d874057dim        *low = towupper_l(*low, __l);
1385d874057dim    return low;
1386d874057dim}
1387d874057dim
1388d874057dimwchar_t
1389d874057dimctype_byname<wchar_t>::do_tolower(char_type c) const
1390d874057dim{
1391d874057dim    return towlower_l(c, __l);
1392d874057dim}
1393d874057dim
1394d874057dimconst wchar_t*
1395d874057dimctype_byname<wchar_t>::do_tolower(char_type* low, const char_type* high) const
1396d874057dim{
1397d874057dim    for (; low != high; ++low)
1398d874057dim        *low = towlower_l(*low, __l);
1399d874057dim    return low;
1400d874057dim}
1401d874057dim
1402d874057dimwchar_t
1403d874057dimctype_byname<wchar_t>::do_widen(char c) const
1404d874057dim{
1405d874057dim    return __libcpp_btowc_l(c, __l);
1406d874057dim}
1407d874057dim
1408d874057dimconst char*
1409d874057dimctype_byname<wchar_t>::do_widen(const char* low, const char* high, char_type* dest) const
1410d874057dim{
1411d874057dim    for (; low != high; ++low, ++dest)
1412d874057dim        *dest = __libcpp_btowc_l(*low, __l);
1413d874057dim    return low;
1414d874057dim}
1415d874057dim
1416d874057dimchar
1417d874057dimctype_byname<wchar_t>::do_narrow(char_type c, char dfault) const
1418d874057dim{
1419d874057dim    int r = __libcpp_wctob_l(c, __l);
1420d874057dim    return r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
1421d874057dim}
1422d874057dim
1423d874057dimconst wchar_t*
1424d874057dimctype_byname<wchar_t>::do_narrow(const char_type* low, const char_type* high, char dfault, char* dest) const
1425d874057dim{
1426d874057dim    for (; low != high; ++low, ++dest)
1427d874057dim    {
1428d874057dim        int r = __libcpp_wctob_l(*low, __l);
1429d874057dim        *dest = r != static_cast<int>(WEOF) ? static_cast<char>(r) : dfault;
1430d874057dim    }
1431d874057dim    return low;
1432d874057dim}
1433d874057dim
1434d874057dim// template <> class codecvt<char, char, mbstate_t>
1435d874057dim
1436d874057dimlocale::id codecvt<char, char, mbstate_t>::id;
1437d874057dim
1438d874057dimcodecvt<char, char, mbstate_t>::~codecvt()
1439d874057dim{
1440d874057dim}
1441d874057dim
1442d874057dimcodecvt<char, char, mbstate_t>::result
1443d874057dimcodecvt<char, char, mbstate_t>::do_out(state_type&,
1444d874057dim    const intern_type* frm, const intern_type*, const intern_type*& frm_nxt,
1445d874057dim    extern_type* to, extern_type*, extern_type*& to_nxt) const
1446d874057dim{
1447d874057dim    frm_nxt = frm;
1448d874057dim    to_nxt = to;
1449d874057dim    return noconv;
1450d874057dim}
1451d874057dim
1452d874057dimcodecvt<char, char, mbstate_t>::result
1453d874057dimcodecvt<char, char, mbstate_t>::do_in(state_type&,
1454d874057dim    const extern_type* frm, const extern_type*, const extern_type*& frm_nxt,
1455d874057dim    intern_type* to, intern_type*, intern_type*& to_nxt) const
1456d874057dim{
1457d874057dim    frm_nxt = frm;
1458d874057dim    to_nxt = to;
1459d874057dim    return noconv;
1460d874057dim}
1461d874057dim
1462d874057dimcodecvt<char, char, mbstate_t>::result
1463d874057dimcodecvt<char, char, mbstate_t>::do_unshift(state_type&,
1464d874057dim    extern_type* to, extern_type*, extern_type*& to_nxt) const
1465d874057dim{
1466d874057dim    to_nxt = to;
1467d874057dim    return noconv;
1468d874057dim}
1469d874057dim
1470d874057dimint
1471d874057dimcodecvt<char, char, mbstate_t>::do_encoding() const  _NOEXCEPT
1472d874057dim{
1473d874057dim    return 1;
1474d874057dim}
1475d874057dim
1476d874057dimbool
1477d874057dimcodecvt<char, char, mbstate_t>::do_always_noconv() const  _NOEXCEPT
1478d874057dim{
1479d874057dim    return true;
1480d874057dim}
1481d874057dim
1482d874057dimint
1483d874057dimcodecvt<char, char, mbstate_t>::do_length(state_type&,
1484d874057dim    const extern_type* frm, const extern_type* end, size_t mx) const
1485d874057dim{
1486d874057dim    return static_cast<int>(min<size_t>(mx, static_cast<size_t>(end-frm)));
1487d874057dim}
1488d874057dim
1489d874057dimint
1490d874057dimcodecvt<char, char, mbstate_t>::do_max_length() const  _NOEXCEPT
1491d874057dim{
1492d874057dim    return 1;
1493d874057dim}
1494d874057dim
1495d874057dim// template <> class codecvt<wchar_t, char, mbstate_t>
1496d874057dim
1497d874057dimlocale::id codecvt<wchar_t, char, mbstate_t>::id;
1498d874057dim
1499d874057dimcodecvt<wchar_t, char, mbstate_t>::codecvt(size_t refs)
1500d874057dim    : locale::facet(refs),
1501d874057dim      __l(_LIBCPP_GET_C_LOCALE)
1502d874057dim{
1503d874057dim}
1504d874057dim
1505d874057dimcodecvt<wchar_t, char, mbstate_t>::codecvt(const char* nm, size_t refs)
1506d874057dim    : locale::facet(refs),
1507d874057dim      __l(newlocale(LC_ALL_MASK, nm, 0))
1508d874057dim{
1509d874057dim    if (__l == 0)
1510d874057dim        __throw_runtime_error("codecvt_byname<wchar_t, char, mbstate_t>::codecvt_byname"
1511d874057dim                            " failed to construct for " + string(nm));
1512d874057dim}
1513d874057dim
1514d874057dimcodecvt<wchar_t, char, mbstate_t>::~codecvt()
1515d874057dim{
1516d874057dim    if (__l != _LIBCPP_GET_C_LOCALE)
1517d874057dim        freelocale(__l);
1518d874057dim}
1519d874057dim
1520d874057dimcodecvt<wchar_t, char, mbstate_t>::result
1521d874057dimcodecvt<wchar_t, char, mbstate_t>::do_out(state_type& st,
1522d874057dim    const intern_type* frm, const intern_type* frm_end, const intern_type*& frm_nxt,
1523d874057dim    extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
1524d874057dim{
1525d874057dim    // look for first internal null in frm
1526d874057dim    const intern_type* fend = frm;
1527d874057dim    for (; fend != frm_end; ++fend)
1528d874057dim        if (*fend == 0)
1529d874057dim            break;
1530d874057dim    // loop over all null-terminated sequences in frm
1531d874057dim    to_nxt = to;
1532d874057dim    for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
1533d874057dim    {
1534d874057dim        // save state in case it is needed to recover to_nxt on error
1535d874057dim        mbstate_t save_state = st;
1536d874057dim        size_t n = __libcpp_wcsnrtombs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1537d874057dim                                     static_cast<size_t>(to_end-to), &st, __l);
1538d874057dim        if (n == size_t(-1))
1539d874057dim        {
1540d874057dim            // need to recover to_nxt
1541d874057dim            for (to_nxt = to; frm != frm_nxt; ++frm)
1542d874057dim            {
1543d874057dim                n = __libcpp_wcrtomb_l(to_nxt, *frm, &save_state, __l);
1544d874057dim                if (n == size_t(-1))
1545d874057dim                    break;
1546d874057dim                to_nxt += n;
1547d874057dim            }
1548d874057dim            frm_nxt = frm;
1549d874057dim            return error;
1550d874057dim        }
1551d874057dim        if (n == 0)
1552d874057dim            return partial;
1553d874057dim        to_nxt += n;
1554d874057dim        if (to_nxt == to_end)
1555d874057dim            break;
1556d874057dim        if (fend != frm_end)  // set up next null terminated sequence
1557d874057dim        {
1558d874057dim            // Try to write the terminating null
1559d874057dim            extern_type tmp[MB_LEN_MAX];
1560d874057dim            n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
1561d874057dim            if (n == size_t(-1))  // on error
1562d874057dim                return error;
1563d874057dim            if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
1564d874057dim                return partial;
1565d874057dim            for (extern_type* p = tmp; n; --n)  // write it
1566d874057dim                *to_nxt++ = *p++;
1567d874057dim            ++frm_nxt;
1568d874057dim            // look for next null in frm
1569d874057dim            for (fend = frm_nxt; fend != frm_end; ++fend)
1570d874057dim                if (*fend == 0)
1571d874057dim                    break;
1572d874057dim        }
1573d874057dim    }
1574d874057dim    return frm_nxt == frm_end ? ok : partial;
1575d874057dim}
1576d874057dim
1577d874057dimcodecvt<wchar_t, char, mbstate_t>::result
1578d874057dimcodecvt<wchar_t, char, mbstate_t>::do_in(state_type& st,
1579d874057dim    const extern_type* frm, const extern_type* frm_end, const extern_type*& frm_nxt,
1580d874057dim    intern_type* to, intern_type* to_end, intern_type*& to_nxt) const
1581d874057dim{
1582d874057dim    // look for first internal null in frm
1583d874057dim    const extern_type* fend = frm;
1584d874057dim    for (; fend != frm_end; ++fend)
1585d874057dim        if (*fend == 0)
1586d874057dim            break;
1587d874057dim    // loop over all null-terminated sequences in frm
1588d874057dim    to_nxt = to;
1589d874057dim    for (frm_nxt = frm; frm != frm_end && to != to_end; frm = frm_nxt, to = to_nxt)
1590d874057dim    {
1591d874057dim        // save state in case it is needed to recover to_nxt on error
1592d874057dim        mbstate_t save_state = st;
1593d874057dim        size_t n = __libcpp_mbsnrtowcs_l(to, &frm_nxt, static_cast<size_t>(fend-frm),
1594d874057dim                                     static_cast<size_t>(to_end-to), &st, __l);
1595d874057dim        if (n == size_t(-1))
1596d874057dim        {
1597d874057dim            // need to recover to_nxt
1598d874057dim            for (to_nxt = to; frm != frm_nxt; ++to_nxt)
1599d874057dim            {
1600d874057dim                n = __libcpp_mbrtowc_l(to_nxt, frm, static_cast<size_t>(fend-frm),
1601d874057dim                                   &save_state, __l);
1602d874057dim                switch (n)
1603d874057dim                {
1604d874057dim                case 0:
1605d874057dim                    ++frm;
1606d874057dim                    break;
1607d874057dim                case size_t(-1):
1608d874057dim                    frm_nxt = frm;
1609d874057dim                    return error;
1610d874057dim                case size_t(-2):
1611d874057dim                    frm_nxt = frm;
1612d874057dim                    return partial;
1613d874057dim                default:
1614d874057dim                    frm += n;
1615d874057dim                    break;
1616d874057dim                }
1617d874057dim            }
1618d874057dim            frm_nxt = frm;
1619d874057dim            return frm_nxt == frm_end ? ok : partial;
1620d874057dim        }
1621d874057dim        if (n == size_t(-1))
1622d874057dim            return error;
1623d874057dim        to_nxt += n;
1624d874057dim        if (to_nxt == to_end)
1625d874057dim            break;
1626d874057dim        if (fend != frm_end)  // set up next null terminated sequence
1627d874057dim        {
1628d874057dim            // Try to write the terminating null
1629d874057dim            n = __libcpp_mbrtowc_l(to_nxt, frm_nxt, 1, &st, __l);
1630d874057dim            if (n != 0)  // on error
1631d874057dim                return error;
1632d874057dim            ++to_nxt;
1633d874057dim            ++frm_nxt;
1634d874057dim            // look for next null in frm
1635d874057dim            for (fend = frm_nxt; fend != frm_end; ++fend)
1636d874057dim                if (*fend == 0)
1637d874057dim                    break;
1638d874057dim        }
1639d874057dim    }
1640d874057dim    return frm_nxt == frm_end ? ok : partial;
1641d874057dim}
1642d874057dim
1643d874057dimcodecvt<wchar_t, char, mbstate_t>::result
1644d874057dimcodecvt<wchar_t, char, mbstate_t>::do_unshift(state_type& st,
1645d874057dim    extern_type* to, extern_type* to_end, extern_type*& to_nxt) const
1646d874057dim{
1647d874057dim    to_nxt = to;
1648d874057dim    extern_type tmp[MB_LEN_MAX];
1649d874057dim    size_t n = __libcpp_wcrtomb_l(tmp, intern_type(), &st, __l);
1650d874057dim    if (n == size_t(-1) || n == 0)  // on error
1651d874057dim        return error;
1652d874057dim    --n;
1653d874057dim    if (n > static_cast<size_t>(to_end-to_nxt))  // is there room?
1654d874057dim        return partial;
1655d874057dim    for (extern_type* p = tmp; n; --n)  // write it
1656d874057dim        *to_nxt++ = *p++;
1657d874057dim    return ok;
1658d874057dim}
1659d874057dim
1660d874057dimint
1661d874057dimcodecvt<wchar_t, char, mbstate_t>::do_encoding() const  _NOEXCEPT
1662d874057dim{
1663d874057dim    if (__libcpp_mbtowc_l(nullptr, nullptr, MB_LEN_MAX, __l) != 0)
1664d874057dim        return -1;
1665d874057dim
1666d874057dim    // stateless encoding
1667d874057dim    if (__l == 0 || __libcpp_mb_cur_max_l(__l) == 1)  // there are no known constant length encodings
1668d874057dim        return 1;                // which take more than 1 char to form a wchar_t
1669d874057dim    return 0;
1670d874057dim}
1671d874057dim
1672d874057dimbool
1673d874057dimcodecvt<wchar_t, char, mbstate_t>::do_always_noconv() const  _NOEXCEPT
1674d874057dim{
1675d874057dim    return false;
1676d874057dim}
1677d874057dim
1678d874057dimint
1679d874057dimcodecvt<wchar_t, char, mbstate_t>::do_length(state_type& st,
1680d874057dim    const extern_type* frm, const extern_type* frm_end, size_t mx) const
1681d874057dim{
1682d874057dim    int nbytes = 0;
1683d874057dim    for (size_t nwchar_t = 0; nwchar_t < mx && frm != frm_end; ++nwchar_t)
1684d874057dim    {
1685d874057dim        size_t n = __libcpp_mbrlen_l(frm, static_cast<size_t>(frm_end-frm), &st, __l);
1686d874057dim        switch (n)
1687d874057dim        {
1688d874057dim        case 0:
1689d874057dim            ++nbytes;
1690d874057dim            ++frm;
1691d874057dim            break;
1692d874057dim        case size_t(-1):
1693d874057dim        case size_t(-2):
1694d874057dim            return nbytes;
1695d874057dim        default:
1696d874057dim            nbytes += n;
1697d874057dim            frm += n;
1698d874057dim            break;
1699d874057dim        }
1700d874057dim    }
1701d874057dim    return nbytes;
1702d874057dim}
1703d874057dim
1704d874057dimint
1705d874057dimcodecvt<wchar_t, char, mbstate_t>::do_max_length() const  _NOEXCEPT
1706d874057dim{
1707d874057dim    return __l == 0 ? 1 : static_cast<int>(__libcpp_mb_cur_max_l(__l));
1708d874057dim}
1709d874057dim
1710d874057dim//                                     Valid UTF ranges
1711d874057dim//     UTF-32               UTF-16                          UTF-8               # of code points
1712d874057dim//                     first      second       first   second    third   fourth
1713d874057dim// 000000 - 00007F  0000 - 007F               00 - 7F                                 127
1714d874057dim// 000080 - 0007FF  0080 - 07FF               C2 - DF, 80 - BF                       1920
1715d874057dim// 000800 - 000FFF  0800 - 0FFF               E0 - E0, A0 - BF, 80 - BF              2048
1716d874057dim// 001000 - 00CFFF  1000 - CFFF               E1 - EC, 80 - BF, 80 - BF             49152
1717d874057dim// 00D000 - 00D7FF  D000 - D7FF               ED - ED, 80 - 9F, 80 - BF              2048
1718d874057dim// 00D800 - 00DFFF                invalid
1719d874057dim// 00E000 - 00FFFF  E000 - FFFF               EE - EF, 80 - BF, 80 - BF              8192
1720d874057dim// 010000 - 03FFFF  D800 - D8BF, DC00 - DFFF  F0 - F0, 90 - BF, 80 - BF, 80 - BF   196608
1721d874057dim// 040000 - 0FFFFF  D8C0 - DBBF, DC00 - DFFF  F1 - F3, 80 - BF, 80 - BF, 80 - BF   786432
1722d874057dim// 100000 - 10FFFF  DBC0 - DBFF, DC00 - DFFF  F4 - F4, 80 - 8F, 80 - BF, 80 - BF    65536
1723d874057dim
1724d874057dimstatic
1725d874057dimcodecvt_base::result
1726d874057dimutf16_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
1727d874057dim              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
1728d874057dim              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1729d874057dim{
1730d874057dim    frm_nxt = frm;
1731d874057dim    to_nxt = to;
1732d874057dim    if (mode & generate_header)
1733d874057dim    {
1734d874057dim        if (to_end-to_nxt < 3)
1735d874057dim            return codecvt_base::partial;
1736d874057dim        *to_nxt++ = static_cast<uint8_t>(0xEF);
1737d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBB);
1738d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBF);
1739d874057dim    }
1740d874057dim    for (; frm_nxt < frm_end; ++frm_nxt)
1741d874057dim    {
1742d874057dim        uint16_t wc1 = *frm_nxt;
1743d874057dim        if (wc1 > Maxcode)
1744d874057dim            return codecvt_base::error;
1745d874057dim        if (wc1 < 0x0080)
1746d874057dim        {
1747d874057dim            if (to_end-to_nxt < 1)
1748d874057dim                return codecvt_base::partial;
1749d874057dim            *to_nxt++ = static_cast<uint8_t>(wc1);
1750d874057dim        }
1751d874057dim        else if (wc1 < 0x0800)
1752d874057dim        {
1753d874057dim            if (to_end-to_nxt < 2)
1754d874057dim                return codecvt_base::partial;
1755d874057dim            *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
1756d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1757d874057dim        }
1758d874057dim        else if (wc1 < 0xD800)
1759d874057dim        {
1760d874057dim            if (to_end-to_nxt < 3)
1761d874057dim                return codecvt_base::partial;
1762d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
1763d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1764d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
1765d874057dim        }
1766d874057dim        else if (wc1 < 0xDC00)
1767d874057dim        {
1768d874057dim            if (frm_end-frm_nxt < 2)
1769d874057dim                return codecvt_base::partial;
1770d874057dim            uint16_t wc2 = frm_nxt[1];
1771d874057dim            if ((wc2 & 0xFC00) != 0xDC00)
1772d874057dim                return codecvt_base::error;
1773d874057dim            if (to_end-to_nxt < 4)
1774d874057dim                return codecvt_base::partial;
1775d874057dim            if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
1776d874057dim                ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
1777d874057dim                return codecvt_base::error;
1778d874057dim            ++frm_nxt;
1779d874057dim            uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
1780d874057dim            *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
1781d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
1782d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
1783d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
1784d874057dim        }
1785d874057dim        else if (wc1 < 0xE000)
1786d874057dim        {
1787d874057dim            return codecvt_base::error;
1788d874057dim        }
1789d874057dim        else
1790d874057dim        {
1791d874057dim            if (to_end-to_nxt < 3)
1792d874057dim                return codecvt_base::partial;
1793d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
1794d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1795d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
1796d874057dim        }
1797d874057dim    }
1798d874057dim    return codecvt_base::ok;
1799d874057dim}
1800d874057dim
1801d874057dimstatic
1802d874057dimcodecvt_base::result
1803d874057dimutf16_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
1804d874057dim              uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
1805d874057dim              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1806d874057dim{
1807d874057dim    frm_nxt = frm;
1808d874057dim    to_nxt = to;
1809d874057dim    if (mode & generate_header)
1810d874057dim    {
1811d874057dim        if (to_end-to_nxt < 3)
1812d874057dim            return codecvt_base::partial;
1813d874057dim        *to_nxt++ = static_cast<uint8_t>(0xEF);
1814d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBB);
1815d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBF);
1816d874057dim    }
1817d874057dim    for (; frm_nxt < frm_end; ++frm_nxt)
1818d874057dim    {
1819d874057dim        uint16_t wc1 = static_cast<uint16_t>(*frm_nxt);
1820d874057dim        if (wc1 > Maxcode)
1821d874057dim            return codecvt_base::error;
1822d874057dim        if (wc1 < 0x0080)
1823d874057dim        {
1824d874057dim            if (to_end-to_nxt < 1)
1825d874057dim                return codecvt_base::partial;
1826d874057dim            *to_nxt++ = static_cast<uint8_t>(wc1);
1827d874057dim        }
1828d874057dim        else if (wc1 < 0x0800)
1829d874057dim        {
1830d874057dim            if (to_end-to_nxt < 2)
1831d874057dim                return codecvt_base::partial;
1832d874057dim            *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc1 >> 6));
1833d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | (wc1 & 0x03F));
1834d874057dim        }
1835d874057dim        else if (wc1 < 0xD800)
1836d874057dim        {
1837d874057dim            if (to_end-to_nxt < 3)
1838d874057dim                return codecvt_base::partial;
1839d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
1840d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1841d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
1842d874057dim        }
1843d874057dim        else if (wc1 < 0xDC00)
1844d874057dim        {
1845d874057dim            if (frm_end-frm_nxt < 2)
1846d874057dim                return codecvt_base::partial;
1847d874057dim            uint16_t wc2 = static_cast<uint16_t>(frm_nxt[1]);
1848d874057dim            if ((wc2 & 0xFC00) != 0xDC00)
1849d874057dim                return codecvt_base::error;
1850d874057dim            if (to_end-to_nxt < 4)
1851d874057dim                return codecvt_base::partial;
1852d874057dim            if (((((wc1 & 0x03C0UL) >> 6) + 1) << 16) +
1853d874057dim                ((wc1 & 0x003FUL) << 10) + (wc2 & 0x03FF) > Maxcode)
1854d874057dim                return codecvt_base::error;
1855d874057dim            ++frm_nxt;
1856d874057dim            uint8_t z = ((wc1 & 0x03C0) >> 6) + 1;
1857d874057dim            *to_nxt++ = static_cast<uint8_t>(0xF0 | (z >> 2));
1858d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((z & 0x03) << 4)     | ((wc1 & 0x003C) >> 2));
1859d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0003) << 4) | ((wc2 & 0x03C0) >> 6));
1860d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc2 & 0x003F));
1861d874057dim        }
1862d874057dim        else if (wc1 < 0xE000)
1863d874057dim        {
1864d874057dim            return codecvt_base::error;
1865d874057dim        }
1866d874057dim        else
1867d874057dim        {
1868d874057dim            if (to_end-to_nxt < 3)
1869d874057dim                return codecvt_base::partial;
1870d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc1 >> 12));
1871d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc1 & 0x0FC0) >> 6));
1872d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc1 & 0x003F));
1873d874057dim        }
1874d874057dim    }
1875d874057dim    return codecvt_base::ok;
1876d874057dim}
1877d874057dim
1878d874057dimstatic
1879d874057dimcodecvt_base::result
1880d874057dimutf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
1881d874057dim              uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
1882d874057dim              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
1883d874057dim{
1884d874057dim    frm_nxt = frm;
1885d874057dim    to_nxt = to;
1886d874057dim    if (mode & consume_header)
1887d874057dim    {
1888d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
1889d874057dim                                                          frm_nxt[2] == 0xBF)
1890d874057dim            frm_nxt += 3;
1891d874057dim    }
1892d874057dim    for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
1893d874057dim    {
1894d874057dim        uint8_t c1 = *frm_nxt;
1895d874057dim        if (c1 > Maxcode)
1896d874057dim            return codecvt_base::error;
1897d874057dim        if (c1 < 0x80)
1898d874057dim        {
1899d874057dim            *to_nxt = static_cast<uint16_t>(c1);
1900d874057dim            ++frm_nxt;
1901d874057dim        }
1902d874057dim        else if (c1 < 0xC2)
1903d874057dim        {
1904d874057dim            return codecvt_base::error;
1905d874057dim        }
1906d874057dim        else if (c1 < 0xE0)
1907d874057dim        {
1908d874057dim            if (frm_end-frm_nxt < 2)
1909d874057dim                return codecvt_base::partial;
1910d874057dim            uint8_t c2 = frm_nxt[1];
1911d874057dim            if ((c2 & 0xC0) != 0x80)
1912d874057dim                return codecvt_base::error;
1913d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
1914d874057dim            if (t > Maxcode)
1915d874057dim                return codecvt_base::error;
1916d874057dim            *to_nxt = t;
1917d874057dim            frm_nxt += 2;
1918d874057dim        }
1919d874057dim        else if (c1 < 0xF0)
1920d874057dim        {
1921d874057dim            if (frm_end-frm_nxt < 3)
1922d874057dim                return codecvt_base::partial;
1923d874057dim            uint8_t c2 = frm_nxt[1];
1924d874057dim            uint8_t c3 = frm_nxt[2];
1925d874057dim            switch (c1)
1926d874057dim            {
1927d874057dim            case 0xE0:
1928d874057dim                if ((c2 & 0xE0) != 0xA0)
1929d874057dim                    return codecvt_base::error;
1930d874057dim                 break;
1931d874057dim            case 0xED:
1932d874057dim                if ((c2 & 0xE0) != 0x80)
1933d874057dim                    return codecvt_base::error;
1934d874057dim                 break;
1935d874057dim            default:
1936d874057dim                if ((c2 & 0xC0) != 0x80)
1937d874057dim                    return codecvt_base::error;
1938d874057dim                 break;
1939d874057dim            }
1940d874057dim            if ((c3 & 0xC0) != 0x80)
1941d874057dim                return codecvt_base::error;
1942d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
1943d874057dim                                             | ((c2 & 0x3F) << 6)
1944d874057dim                                             |  (c3 & 0x3F));
1945d874057dim            if (t > Maxcode)
1946d874057dim                return codecvt_base::error;
1947d874057dim            *to_nxt = t;
1948d874057dim            frm_nxt += 3;
1949d874057dim        }
1950d874057dim        else if (c1 < 0xF5)
1951d874057dim        {
1952d874057dim            if (frm_end-frm_nxt < 4)
1953d874057dim                return codecvt_base::partial;
1954d874057dim            uint8_t c2 = frm_nxt[1];
1955d874057dim            uint8_t c3 = frm_nxt[2];
1956d874057dim            uint8_t c4 = frm_nxt[3];
1957d874057dim            switch (c1)
1958d874057dim            {
1959d874057dim            case 0xF0:
1960d874057dim                if (!(0x90 <= c2 && c2 <= 0xBF))
1961d874057dim                    return codecvt_base::error;
1962d874057dim                 break;
1963d874057dim            case 0xF4:
1964d874057dim                if ((c2 & 0xF0) != 0x80)
1965d874057dim                    return codecvt_base::error;
1966d874057dim                 break;
1967d874057dim            default:
1968d874057dim                if ((c2 & 0xC0) != 0x80)
1969d874057dim                    return codecvt_base::error;
1970d874057dim                 break;
1971d874057dim            }
1972d874057dim            if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
1973d874057dim                return codecvt_base::error;
1974d874057dim            if (to_end-to_nxt < 2)
1975d874057dim                return codecvt_base::partial;
1976d874057dim            if ((((c1 & 7UL) << 18) +
1977d874057dim                ((c2 & 0x3FUL) << 12) +
1978d874057dim                ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
1979d874057dim                return codecvt_base::error;
1980d874057dim            *to_nxt = static_cast<uint16_t>(
1981d874057dim                    0xD800
1982d874057dim                  | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
1983d874057dim                  | ((c2 & 0x0F) << 2)
1984d874057dim                  | ((c3 & 0x30) >> 4));
1985d874057dim            *++to_nxt = static_cast<uint16_t>(
1986d874057dim                    0xDC00
1987d874057dim                  | ((c3 & 0x0F) << 6)
1988d874057dim                  |  (c4 & 0x3F));
1989d874057dim            frm_nxt += 4;
1990d874057dim        }
1991d874057dim        else
1992d874057dim        {
1993d874057dim            return codecvt_base::error;
1994d874057dim        }
1995d874057dim    }
1996d874057dim    return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
1997d874057dim}
1998d874057dim
1999d874057dimstatic
2000d874057dimcodecvt_base::result
2001d874057dimutf8_to_utf16(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2002d874057dim              uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2003d874057dim              unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2004d874057dim{
2005d874057dim    frm_nxt = frm;
2006d874057dim    to_nxt = to;
2007d874057dim    if (mode & consume_header)
2008d874057dim    {
2009d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2010d874057dim                                                          frm_nxt[2] == 0xBF)
2011d874057dim            frm_nxt += 3;
2012d874057dim    }
2013d874057dim    for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2014d874057dim    {
2015d874057dim        uint8_t c1 = *frm_nxt;
2016d874057dim        if (c1 > Maxcode)
2017d874057dim            return codecvt_base::error;
2018d874057dim        if (c1 < 0x80)
2019d874057dim        {
2020d874057dim            *to_nxt = static_cast<uint32_t>(c1);
2021d874057dim            ++frm_nxt;
2022d874057dim        }
2023d874057dim        else if (c1 < 0xC2)
2024d874057dim        {
2025d874057dim            return codecvt_base::error;
2026d874057dim        }
2027d874057dim        else if (c1 < 0xE0)
2028d874057dim        {
2029d874057dim            if (frm_end-frm_nxt < 2)
2030d874057dim                return codecvt_base::partial;
2031d874057dim            uint8_t c2 = frm_nxt[1];
2032d874057dim            if ((c2 & 0xC0) != 0x80)
2033d874057dim                return codecvt_base::error;
2034d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (c2 & 0x3F));
2035d874057dim            if (t > Maxcode)
2036d874057dim                return codecvt_base::error;
2037d874057dim            *to_nxt = static_cast<uint32_t>(t);
2038d874057dim            frm_nxt += 2;
2039d874057dim        }
2040d874057dim        else if (c1 < 0xF0)
2041d874057dim        {
2042d874057dim            if (frm_end-frm_nxt < 3)
2043d874057dim                return codecvt_base::partial;
2044d874057dim            uint8_t c2 = frm_nxt[1];
2045d874057dim            uint8_t c3 = frm_nxt[2];
2046d874057dim            switch (c1)
2047d874057dim            {
2048d874057dim            case 0xE0:
2049d874057dim                if ((c2 & 0xE0) != 0xA0)
2050d874057dim                    return codecvt_base::error;
2051d874057dim                 break;
2052d874057dim            case 0xED:
2053d874057dim                if ((c2 & 0xE0) != 0x80)
2054d874057dim                    return codecvt_base::error;
2055d874057dim                 break;
2056d874057dim            default:
2057d874057dim                if ((c2 & 0xC0) != 0x80)
2058d874057dim                    return codecvt_base::error;
2059d874057dim                 break;
2060d874057dim            }
2061d874057dim            if ((c3 & 0xC0) != 0x80)
2062d874057dim                return codecvt_base::error;
2063d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
2064d874057dim                                             | ((c2 & 0x3F) << 6)
2065d874057dim                                             |  (c3 & 0x3F));
2066d874057dim            if (t > Maxcode)
2067d874057dim                return codecvt_base::error;
2068d874057dim            *to_nxt = static_cast<uint32_t>(t);
2069d874057dim            frm_nxt += 3;
2070d874057dim        }
2071d874057dim        else if (c1 < 0xF5)
2072d874057dim        {
2073d874057dim            if (frm_end-frm_nxt < 4)
2074d874057dim                return codecvt_base::partial;
2075d874057dim            uint8_t c2 = frm_nxt[1];
2076d874057dim            uint8_t c3 = frm_nxt[2];
2077d874057dim            uint8_t c4 = frm_nxt[3];
2078d874057dim            switch (c1)
2079d874057dim            {
2080d874057dim            case 0xF0:
2081d874057dim                if (!(0x90 <= c2 && c2 <= 0xBF))
2082d874057dim                    return codecvt_base::error;
2083d874057dim                 break;
2084d874057dim            case 0xF4:
2085d874057dim                if ((c2 & 0xF0) != 0x80)
2086d874057dim                    return codecvt_base::error;
2087d874057dim                 break;
2088d874057dim            default:
2089d874057dim                if ((c2 & 0xC0) != 0x80)
2090d874057dim                    return codecvt_base::error;
2091d874057dim                 break;
2092d874057dim            }
2093d874057dim            if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2094d874057dim                return codecvt_base::error;
2095d874057dim            if (to_end-to_nxt < 2)
2096d874057dim                return codecvt_base::partial;
2097d874057dim            if ((((c1 & 7UL) << 18) +
2098d874057dim                ((c2 & 0x3FUL) << 12) +
2099d874057dim                ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
2100d874057dim                return codecvt_base::error;
2101d874057dim            *to_nxt = static_cast<uint32_t>(
2102d874057dim                    0xD800
2103d874057dim                  | (((((c1 & 0x07) << 2) | ((c2 & 0x30) >> 4)) - 1) << 6)
2104d874057dim                  | ((c2 & 0x0F) << 2)
2105d874057dim                  | ((c3 & 0x30) >> 4));
2106d874057dim            *++to_nxt = static_cast<uint32_t>(
2107d874057dim                    0xDC00
2108d874057dim                  | ((c3 & 0x0F) << 6)
2109d874057dim                  |  (c4 & 0x3F));
2110d874057dim            frm_nxt += 4;
2111d874057dim        }
2112d874057dim        else
2113d874057dim        {
2114d874057dim            return codecvt_base::error;
2115d874057dim        }
2116d874057dim    }
2117d874057dim    return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2118d874057dim}
2119d874057dim
2120d874057dimstatic
2121d874057dimint
2122d874057dimutf8_to_utf16_length(const uint8_t* frm, const uint8_t* frm_end,
2123d874057dim                     size_t mx, unsigned long Maxcode = 0x10FFFF,
2124d874057dim                     codecvt_mode mode = codecvt_mode(0))
2125d874057dim{
2126d874057dim    const uint8_t* frm_nxt = frm;
2127d874057dim    if (mode & consume_header)
2128d874057dim    {
2129d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2130d874057dim                                                          frm_nxt[2] == 0xBF)
2131d874057dim            frm_nxt += 3;
2132d874057dim    }
2133d874057dim    for (size_t nchar16_t = 0; frm_nxt < frm_end && nchar16_t < mx; ++nchar16_t)
2134d874057dim    {
2135d874057dim        uint8_t c1 = *frm_nxt;
2136d874057dim        if (c1 > Maxcode)
2137d874057dim            break;
2138d874057dim        if (c1 < 0x80)
2139d874057dim        {
2140d874057dim            ++frm_nxt;
2141d874057dim        }
2142d874057dim        else if (c1 < 0xC2)
2143d874057dim        {
2144d874057dim            break;
2145d874057dim        }
2146d874057dim        else if (c1 < 0xE0)
2147d874057dim        {
2148d874057dim            if ((frm_end-frm_nxt < 2) || (frm_nxt[1] & 0xC0) != 0x80)
2149d874057dim                break;
2150d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6) | (frm_nxt[1] & 0x3F));
2151d874057dim            if (t > Maxcode)
2152d874057dim                break;
2153d874057dim            frm_nxt += 2;
2154d874057dim        }
2155d874057dim        else if (c1 < 0xF0)
2156d874057dim        {
2157d874057dim            if (frm_end-frm_nxt < 3)
2158d874057dim                break;
2159d874057dim            uint8_t c2 = frm_nxt[1];
2160d874057dim            uint8_t c3 = frm_nxt[2];
2161d874057dim            switch (c1)
2162d874057dim            {
2163d874057dim            case 0xE0:
2164d874057dim                if ((c2 & 0xE0) != 0xA0)
2165d874057dim                    return static_cast<int>(frm_nxt - frm);
2166d874057dim                break;
2167d874057dim            case 0xED:
2168d874057dim                if ((c2 & 0xE0) != 0x80)
2169d874057dim                    return static_cast<int>(frm_nxt - frm);
2170d874057dim                 break;
2171d874057dim            default:
2172d874057dim                if ((c2 & 0xC0) != 0x80)
2173d874057dim                    return static_cast<int>(frm_nxt - frm);
2174d874057dim                 break;
2175d874057dim            }
2176d874057dim            if ((c3 & 0xC0) != 0x80)
2177d874057dim                break;
2178d874057dim            if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
2179d874057dim                break;
2180d874057dim            frm_nxt += 3;
2181d874057dim        }
2182d874057dim        else if (c1 < 0xF5)
2183d874057dim        {
2184d874057dim            if (frm_end-frm_nxt < 4 || mx-nchar16_t < 2)
2185d874057dim                break;
2186d874057dim            uint8_t c2 = frm_nxt[1];
2187d874057dim            uint8_t c3 = frm_nxt[2];
2188d874057dim            uint8_t c4 = frm_nxt[3];
2189d874057dim            switch (c1)
2190d874057dim            {
2191d874057dim            case 0xF0:
2192d874057dim                if (!(0x90 <= c2 && c2 <= 0xBF))
2193d874057dim                    return static_cast<int>(frm_nxt - frm);
2194d874057dim                 break;
2195d874057dim            case 0xF4:
2196d874057dim                if ((c2 & 0xF0) != 0x80)
2197d874057dim                    return static_cast<int>(frm_nxt - frm);
2198d874057dim                 break;
2199d874057dim            default:
2200d874057dim                if ((c2 & 0xC0) != 0x80)
2201d874057dim                    return static_cast<int>(frm_nxt - frm);
2202d874057dim                 break;
2203d874057dim            }
2204d874057dim            if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2205d874057dim                break;
2206d874057dim            if ((((c1 & 7UL) << 18) +
2207d874057dim                ((c2 & 0x3FUL) << 12) +
2208d874057dim                ((c3 & 0x3FUL) << 6) + (c4 & 0x3F)) > Maxcode)
2209d874057dim                break;
2210d874057dim            ++nchar16_t;
2211d874057dim            frm_nxt += 4;
2212d874057dim        }
2213d874057dim        else
2214d874057dim        {
2215d874057dim            break;
2216d874057dim        }
2217d874057dim    }
2218d874057dim    return static_cast<int>(frm_nxt - frm);
2219d874057dim}
2220d874057dim
2221d874057dimstatic
2222d874057dimcodecvt_base::result
2223d874057dimucs4_to_utf8(const uint32_t* frm, const uint32_t* frm_end, const uint32_t*& frm_nxt,
2224d874057dim             uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2225d874057dim             unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2226d874057dim{
2227d874057dim    frm_nxt = frm;
2228d874057dim    to_nxt = to;
2229d874057dim    if (mode & generate_header)
2230d874057dim    {
2231d874057dim        if (to_end-to_nxt < 3)
2232d874057dim            return codecvt_base::partial;
2233d874057dim        *to_nxt++ = static_cast<uint8_t>(0xEF);
2234d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBB);
2235d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBF);
2236d874057dim    }
2237d874057dim    for (; frm_nxt < frm_end; ++frm_nxt)
2238d874057dim    {
2239d874057dim        uint32_t wc = *frm_nxt;
2240d874057dim        if ((wc & 0xFFFFF800) == 0x00D800 || wc > Maxcode)
2241d874057dim            return codecvt_base::error;
2242d874057dim        if (wc < 0x000080)
2243d874057dim        {
2244d874057dim            if (to_end-to_nxt < 1)
2245d874057dim                return codecvt_base::partial;
2246d874057dim            *to_nxt++ = static_cast<uint8_t>(wc);
2247d874057dim        }
2248d874057dim        else if (wc < 0x000800)
2249d874057dim        {
2250d874057dim            if (to_end-to_nxt < 2)
2251d874057dim                return codecvt_base::partial;
2252d874057dim            *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
2253d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2254d874057dim        }
2255d874057dim        else if (wc < 0x010000)
2256d874057dim        {
2257d874057dim            if (to_end-to_nxt < 3)
2258d874057dim                return codecvt_base::partial;
2259d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
2260d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
2261d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
2262d874057dim        }
2263d874057dim        else // if (wc < 0x110000)
2264d874057dim        {
2265d874057dim            if (to_end-to_nxt < 4)
2266d874057dim                return codecvt_base::partial;
2267d874057dim            *to_nxt++ = static_cast<uint8_t>(0xF0 |  (wc >> 18));
2268d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x03F000) >> 12));
2269d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x000FC0) >> 6));
2270d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x00003F));
2271d874057dim        }
2272d874057dim    }
2273d874057dim    return codecvt_base::ok;
2274d874057dim}
2275d874057dim
2276d874057dimstatic
2277d874057dimcodecvt_base::result
2278d874057dimutf8_to_ucs4(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2279d874057dim             uint32_t* to, uint32_t* to_end, uint32_t*& to_nxt,
2280d874057dim             unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2281d874057dim{
2282d874057dim    frm_nxt = frm;
2283d874057dim    to_nxt = to;
2284d874057dim    if (mode & consume_header)
2285d874057dim    {
2286d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2287d874057dim                                                          frm_nxt[2] == 0xBF)
2288d874057dim            frm_nxt += 3;
2289d874057dim    }
2290d874057dim    for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2291d874057dim    {
2292d874057dim        uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2293d874057dim        if (c1 < 0x80)
2294d874057dim        {
2295d874057dim            if (c1 > Maxcode)
2296d874057dim                return codecvt_base::error;
2297d874057dim            *to_nxt = static_cast<uint32_t>(c1);
2298d874057dim            ++frm_nxt;
2299d874057dim        }
2300d874057dim        else if (c1 < 0xC2)
2301d874057dim        {
2302d874057dim            return codecvt_base::error;
2303d874057dim        }
2304d874057dim        else if (c1 < 0xE0)
2305d874057dim        {
2306d874057dim            if (frm_end-frm_nxt < 2)
2307d874057dim                return codecvt_base::partial;
2308d874057dim            uint8_t c2 = frm_nxt[1];
2309d874057dim            if ((c2 & 0xC0) != 0x80)
2310d874057dim                return codecvt_base::error;
2311d874057dim            uint32_t t = static_cast<uint32_t>(((c1 & 0x1F) << 6)
2312d874057dim                                              | (c2 & 0x3F));
2313d874057dim            if (t > Maxcode)
2314d874057dim                return codecvt_base::error;
2315d874057dim            *to_nxt = t;
2316d874057dim            frm_nxt += 2;
2317d874057dim        }
2318d874057dim        else if (c1 < 0xF0)
2319d874057dim        {
2320d874057dim            if (frm_end-frm_nxt < 3)
2321d874057dim                return codecvt_base::partial;
2322d874057dim            uint8_t c2 = frm_nxt[1];
2323d874057dim            uint8_t c3 = frm_nxt[2];
2324d874057dim            switch (c1)
2325d874057dim            {
2326d874057dim            case 0xE0:
2327d874057dim                if ((c2 & 0xE0) != 0xA0)
2328d874057dim                    return codecvt_base::error;
2329d874057dim                 break;
2330d874057dim            case 0xED:
2331d874057dim                if ((c2 & 0xE0) != 0x80)
2332d874057dim                    return codecvt_base::error;
2333d874057dim                 break;
2334d874057dim            default:
2335d874057dim                if ((c2 & 0xC0) != 0x80)
2336d874057dim                    return codecvt_base::error;
2337d874057dim                 break;
2338d874057dim            }
2339d874057dim            if ((c3 & 0xC0) != 0x80)
2340d874057dim                return codecvt_base::error;
2341d874057dim            uint32_t t = static_cast<uint32_t>(((c1 & 0x0F) << 12)
2342d874057dim                                             | ((c2 & 0x3F) << 6)
2343d874057dim                                             |  (c3 & 0x3F));
2344d874057dim            if (t > Maxcode)
2345d874057dim                return codecvt_base::error;
2346d874057dim            *to_nxt = t;
2347d874057dim            frm_nxt += 3;
2348d874057dim        }
2349d874057dim        else if (c1 < 0xF5)
2350d874057dim        {
2351d874057dim            if (frm_end-frm_nxt < 4)
2352d874057dim                return codecvt_base::partial;
2353d874057dim            uint8_t c2 = frm_nxt[1];
2354d874057dim            uint8_t c3 = frm_nxt[2];
2355d874057dim            uint8_t c4 = frm_nxt[3];
2356d874057dim            switch (c1)
2357d874057dim            {
2358d874057dim            case 0xF0:
2359d874057dim                if (!(0x90 <= c2 && c2 <= 0xBF))
2360d874057dim                    return codecvt_base::error;
2361d874057dim                 break;
2362d874057dim            case 0xF4:
2363d874057dim                if ((c2 & 0xF0) != 0x80)
2364d874057dim                    return codecvt_base::error;
2365d874057dim                 break;
2366d874057dim            default:
2367d874057dim                if ((c2 & 0xC0) != 0x80)
2368d874057dim                    return codecvt_base::error;
2369d874057dim                 break;
2370d874057dim            }
2371d874057dim            if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2372d874057dim                return codecvt_base::error;
2373d874057dim            uint32_t t = static_cast<uint32_t>(((c1 & 0x07) << 18)
2374d874057dim                                             | ((c2 & 0x3F) << 12)
2375d874057dim                                             | ((c3 & 0x3F) << 6)
2376d874057dim                                             |  (c4 & 0x3F));
2377d874057dim            if (t > Maxcode)
2378d874057dim                return codecvt_base::error;
2379d874057dim            *to_nxt = t;
2380d874057dim            frm_nxt += 4;
2381d874057dim        }
2382d874057dim        else
2383d874057dim        {
2384d874057dim            return codecvt_base::error;
2385d874057dim        }
2386d874057dim    }
2387d874057dim    return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2388d874057dim}
2389d874057dim
2390d874057dimstatic
2391d874057dimint
2392d874057dimutf8_to_ucs4_length(const uint8_t* frm, const uint8_t* frm_end,
2393d874057dim                    size_t mx, unsigned long Maxcode = 0x10FFFF,
2394d874057dim                    codecvt_mode mode = codecvt_mode(0))
2395d874057dim{
2396d874057dim    const uint8_t* frm_nxt = frm;
2397d874057dim    if (mode & consume_header)
2398d874057dim    {
2399d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2400d874057dim                                                          frm_nxt[2] == 0xBF)
2401d874057dim            frm_nxt += 3;
2402d874057dim    }
2403d874057dim    for (size_t nchar32_t = 0; frm_nxt < frm_end && nchar32_t < mx; ++nchar32_t)
2404d874057dim    {
2405d874057dim        uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2406d874057dim        if (c1 < 0x80)
2407d874057dim        {
2408d874057dim            if (c1 > Maxcode)
2409d874057dim                break;
2410d874057dim            ++frm_nxt;
2411d874057dim        }
2412d874057dim        else if (c1 < 0xC2)
2413d874057dim        {
2414d874057dim            break;
2415d874057dim        }
2416d874057dim        else if (c1 < 0xE0)
2417d874057dim        {
2418d874057dim            if ((frm_end-frm_nxt < 2) || ((frm_nxt[1] & 0xC0) != 0x80))
2419d874057dim                break;
2420d874057dim            if ((((c1 & 0x1Fu) << 6) | (frm_nxt[1] & 0x3Fu)) > Maxcode)
2421d874057dim                break;
2422d874057dim            frm_nxt += 2;
2423d874057dim        }
2424d874057dim        else if (c1 < 0xF0)
2425d874057dim        {
2426d874057dim            if (frm_end-frm_nxt < 3)
2427d874057dim                break;
2428d874057dim            uint8_t c2 = frm_nxt[1];
2429d874057dim            uint8_t c3 = frm_nxt[2];
2430d874057dim            switch (c1)
2431d874057dim            {
2432d874057dim            case 0xE0:
2433d874057dim                if ((c2 & 0xE0) != 0xA0)
2434d874057dim                    return static_cast<int>(frm_nxt - frm);
2435d874057dim                break;
2436d874057dim            case 0xED:
2437d874057dim                if ((c2 & 0xE0) != 0x80)
2438d874057dim                    return static_cast<int>(frm_nxt - frm);
2439d874057dim                 break;
2440d874057dim            default:
2441d874057dim                if ((c2 & 0xC0) != 0x80)
2442d874057dim                    return static_cast<int>(frm_nxt - frm);
2443d874057dim                 break;
2444d874057dim            }
2445d874057dim            if ((c3 & 0xC0) != 0x80)
2446d874057dim                break;
2447d874057dim            if ((((c1 & 0x0Fu) << 12) | ((c2 & 0x3Fu) << 6) | (c3 & 0x3Fu)) > Maxcode)
2448d874057dim                break;
2449d874057dim            frm_nxt += 3;
2450d874057dim        }
2451d874057dim        else if (c1 < 0xF5)
2452d874057dim        {
2453d874057dim            if (frm_end-frm_nxt < 4)
2454d874057dim                break;
2455d874057dim            uint8_t c2 = frm_nxt[1];
2456d874057dim            uint8_t c3 = frm_nxt[2];
2457d874057dim            uint8_t c4 = frm_nxt[3];
2458d874057dim            switch (c1)
2459d874057dim            {
2460d874057dim            case 0xF0:
2461d874057dim                if (!(0x90 <= c2 && c2 <= 0xBF))
2462d874057dim                    return static_cast<int>(frm_nxt - frm);
2463d874057dim                 break;
2464d874057dim            case 0xF4:
2465d874057dim                if ((c2 & 0xF0) != 0x80)
2466d874057dim                    return static_cast<int>(frm_nxt - frm);
2467d874057dim                 break;
2468d874057dim            default:
2469d874057dim                if ((c2 & 0xC0) != 0x80)
2470d874057dim                    return static_cast<int>(frm_nxt - frm);
2471d874057dim                 break;
2472d874057dim            }
2473d874057dim            if ((c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80)
2474d874057dim                break;
2475d874057dim            if ((((c1 & 0x07u) << 18) | ((c2 & 0x3Fu) << 12) |
2476d874057dim                 ((c3 & 0x3Fu) << 6)  |  (c4 & 0x3Fu)) > Maxcode)
2477d874057dim                break;
2478d874057dim            frm_nxt += 4;
2479d874057dim        }
2480d874057dim        else
2481d874057dim        {
2482d874057dim            break;
2483d874057dim        }
2484d874057dim    }
2485d874057dim    return static_cast<int>(frm_nxt - frm);
2486d874057dim}
2487d874057dim
2488d874057dimstatic
2489d874057dimcodecvt_base::result
2490d874057dimucs2_to_utf8(const uint16_t* frm, const uint16_t* frm_end, const uint16_t*& frm_nxt,
2491d874057dim             uint8_t* to, uint8_t* to_end, uint8_t*& to_nxt,
2492d874057dim             unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2493d874057dim{
2494d874057dim    frm_nxt = frm;
2495d874057dim    to_nxt = to;
2496d874057dim    if (mode & generate_header)
2497d874057dim    {
2498d874057dim        if (to_end-to_nxt < 3)
2499d874057dim            return codecvt_base::partial;
2500d874057dim        *to_nxt++ = static_cast<uint8_t>(0xEF);
2501d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBB);
2502d874057dim        *to_nxt++ = static_cast<uint8_t>(0xBF);
2503d874057dim    }
2504d874057dim    for (; frm_nxt < frm_end; ++frm_nxt)
2505d874057dim    {
2506d874057dim        uint16_t wc = *frm_nxt;
2507d874057dim        if ((wc & 0xF800) == 0xD800 || wc > Maxcode)
2508d874057dim            return codecvt_base::error;
2509d874057dim        if (wc < 0x0080)
2510d874057dim        {
2511d874057dim            if (to_end-to_nxt < 1)
2512d874057dim                return codecvt_base::partial;
2513d874057dim            *to_nxt++ = static_cast<uint8_t>(wc);
2514d874057dim        }
2515d874057dim        else if (wc < 0x0800)
2516d874057dim        {
2517d874057dim            if (to_end-to_nxt < 2)
2518d874057dim                return codecvt_base::partial;
2519d874057dim            *to_nxt++ = static_cast<uint8_t>(0xC0 | (wc >> 6));
2520d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | (wc & 0x03F));
2521d874057dim        }
2522d874057dim        else // if (wc <= 0xFFFF)
2523d874057dim        {
2524d874057dim            if (to_end-to_nxt < 3)
2525d874057dim                return codecvt_base::partial;
2526d874057dim            *to_nxt++ = static_cast<uint8_t>(0xE0 |  (wc >> 12));
2527d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 | ((wc & 0x0FC0) >> 6));
2528d874057dim            *to_nxt++ = static_cast<uint8_t>(0x80 |  (wc & 0x003F));
2529d874057dim        }
2530d874057dim    }
2531d874057dim    return codecvt_base::ok;
2532d874057dim}
2533d874057dim
2534d874057dimstatic
2535d874057dimcodecvt_base::result
2536d874057dimutf8_to_ucs2(const uint8_t* frm, const uint8_t* frm_end, const uint8_t*& frm_nxt,
2537d874057dim             uint16_t* to, uint16_t* to_end, uint16_t*& to_nxt,
2538d874057dim             unsigned long Maxcode = 0x10FFFF, codecvt_mode mode = codecvt_mode(0))
2539d874057dim{
2540d874057dim    frm_nxt = frm;
2541d874057dim    to_nxt = to;
2542d874057dim    if (mode & consume_header)
2543d874057dim    {
2544d874057dim        if (frm_end-frm_nxt >= 3 && frm_nxt[0] == 0xEF && frm_nxt[1] == 0xBB &&
2545d874057dim                                                          frm_nxt[2] == 0xBF)
2546d874057dim            frm_nxt += 3;
2547d874057dim    }
2548d874057dim    for (; frm_nxt < frm_end && to_nxt < to_end; ++to_nxt)
2549d874057dim    {
2550d874057dim        uint8_t c1 = static_cast<uint8_t>(*frm_nxt);
2551d874057dim        if (c1 < 0x80)
2552d874057dim        {
2553d874057dim            if (c1 > Maxcode)
2554d874057dim                return codecvt_base::error;
2555d874057dim            *to_nxt = static_cast<uint16_t>(c1);
2556d874057dim            ++frm_nxt;
2557d874057dim        }
2558d874057dim        else if (c1 < 0xC2)
2559d874057dim        {
2560d874057dim            return codecvt_base::error;
2561d874057dim        }
2562d874057dim        else if (c1 < 0xE0)
2563d874057dim        {
2564d874057dim            if (frm_end-frm_nxt < 2)
2565d874057dim                return codecvt_base::partial;
2566d874057dim            uint8_t c2 = frm_nxt[1];
2567d874057dim            if ((c2 & 0xC0) != 0x80)
2568d874057dim                return codecvt_base::error;
2569d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x1F) << 6)
2570d874057dim                                              | (c2 & 0x3F));
2571d874057dim            if (t > Maxcode)
2572d874057dim                return codecvt_base::error;
2573d874057dim            *to_nxt = t;
2574d874057dim            frm_nxt += 2;
2575d874057dim        }
2576d874057dim        else if (c1 < 0xF0)
2577d874057dim        {
2578d874057dim            if (frm_end-frm_nxt < 3)
2579d874057dim                return codecvt_base::partial;
2580d874057dim            uint8_t c2 = frm_nxt[1];
2581d874057dim            uint8_t c3 = frm_nxt[2];
2582d874057dim            switch (c1)
2583d874057dim            {
2584d874057dim            case 0xE0:
2585d874057dim                if ((c2 & 0xE0) != 0xA0)
2586d874057dim                    return codecvt_base::error;
2587d874057dim                 break;
2588d874057dim            case 0xED:
2589d874057dim                if ((c2 & 0xE0) != 0x80)
2590d874057dim                    return codecvt_base::error;
2591d874057dim                 break;
2592d874057dim            default:
2593d874057dim                if ((c2 & 0xC0) != 0x80)
2594d874057dim                    return codecvt_base::error;
2595d874057dim                 break;
2596d874057dim            }
2597d874057dim            if ((c3 & 0xC0) != 0x80)
2598d874057dim                return codecvt_base::error;
2599d874057dim            uint16_t t = static_cast<uint16_t>(((c1 & 0x0F) << 12)
2600d874057dim                                             | ((c2 & 0x3F) << 6)
2601d874057dim                                             |  (c3 & 0x3F));
2602d874057dim            if (t > Maxcode)
2603d874057dim                return codecvt_base::error;
2604d874057dim            *to_nxt = t;
2605d874057dim            frm_nxt += 3;
2606d874057dim        }
2607d874057dim        else
2608d874057dim        {
2609d874057dim            return codecvt_base::error;
2610d874057dim        }
2611d874057dim    }
2612d874057dim    return frm_nxt < frm_end ? codecvt_base::partial : codecvt_base::ok;
2613d874057dim}
2614d874057dim
2615d874057dimstatic
2616d874057dimint
2617d874057dimutf8_to_ucs2_length(const uint8_t* frm, const uint8_t* frm_end,
2618d874057dim                    size_t mx, unsigned long Maxcode = 0x10FFFF,
2619d874057