xref: /reactos/sdk/lib/ucrt/convert/c16rtomb.cpp (revision fe93a3f9)
1 //
2 // c16rtomb.cpp
3 //
4 //      Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 
7 #include <corecrt_internal_mbstring.h>
8 #include <corecrt_internal_ptd_propagation.h>
9 #include <uchar.h>
10 
11 using namespace __crt_mbstring;
12 
13 namespace
14 {
15     inline void store_first_surrogate(char16_t c16, mbstate_t* ps)
16     {
17         // Store the first (high) surrogate masked and shifted, so that all that's left to do
18         // is to add the maksed second surrogate.
19         // Note: _Wchar is the only field used in mbstate_t for this function
20         const char32_t c32 = ((c16 & ~0xd800) << 10) + 0x10000;
21         ps->_Wchar = c32;
22     }
23 
24     inline char32_t combine_second_surrogate(char16_t c16, mbstate_t* ps)
25     {
26         return ps->_Wchar + (c16 & ~0xdc00);
27     }
28 
29     inline constexpr bool has_surrogate(mbstate_t* ps)
30     {
31         return ps->_Wchar != 0;
32     }
33 
34     inline constexpr bool is_first_surrogate(char16_t c16)
35     {
36         // UTF-16 high surrogate
37         return 0xd800 <= c16 && c16 <= 0xdbff;
38     }
39 
40     inline constexpr bool is_second_surrogate(char16_t c16)
41     {
42         // UTF-16 low surrogate
43         return 0xdc00 <= c16 && c16 <= 0xdfff;
44     }
45 }
46 
47 extern "C" size_t __cdecl c16rtomb(char* s, char16_t c16, mbstate_t* ps)
48 {
49     // TODO: Bug 13307590 says this is always assuming UTF-8.
50     __crt_cached_ptd_host ptd;
51     return __c16rtomb_utf8(s, c16, ps, ptd);
52 }
53 
54 size_t __cdecl __crt_mbstring::__c16rtomb_utf8(char* s, char16_t c16, mbstate_t* ps, __crt_cached_ptd_host& ptd)
55 {
56     static mbstate_t internal_pst{};
57     if (ps == nullptr)
58     {
59         ps = &internal_pst;
60     }
61 
62     if (!has_surrogate(ps))
63     {
64         if (is_second_surrogate(c16))
65         {
66             return return_illegal_sequence(ps, ptd);
67         }
68         else if (is_first_surrogate(c16))
69         {
70             store_first_surrogate(c16, ps);
71             return 0;
72         }
73         else
74         {
75             return __c32rtomb_utf8(s, static_cast<char32_t>(c16), ps, ptd);
76         }
77     }
78     else
79     {
80         // We've already seen the first (high) surrogate, so we're
81         // expecting to complete this code point with its other half
82         // in the second (low) surrogate
83         if (!is_second_surrogate(c16))
84         {
85             return return_illegal_sequence(ps, ptd);
86         }
87         const char32_t c32 = combine_second_surrogate(c16, ps);
88 
89         mbstate_t temp{};
90         const size_t retval = __c32rtomb_utf8(s, c32, &temp, ptd);
91         return reset_and_return(retval, ps);
92     }
93 }
94 
95