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