|
7 | 7 | #include <stdexcept> |
8 | 8 | #include <string> |
9 | 9 | #include <vector> |
10 | | -#include <locale> |
11 | | -#include <codecvt> |
| 10 | + |
12 | 11 |
|
13 | 12 | struct napi_callback_info__ { |
14 | 13 | napi_value newTarget; |
@@ -103,13 +102,68 @@ namespace { |
103 | 102 | } |
104 | 103 |
|
105 | 104 | private: |
| 105 | + // Decode UTF-8 to UTF-16, replacing invalid sequences with U+FFFD. |
| 106 | + static std::u16string Utf8ToUtf16(const char* str, size_t len) { |
| 107 | + std::u16string result; |
| 108 | + result.reserve(len); |
| 109 | + const auto* s = reinterpret_cast<const unsigned char*>(str); |
| 110 | + const auto* end = s + len; |
| 111 | + while (s < end) { |
| 112 | + uint32_t cp; |
| 113 | + int trail; |
| 114 | + unsigned char lead = *s++; |
| 115 | + if (lead < 0x80) { |
| 116 | + cp = lead; trail = 0; |
| 117 | + } else if ((lead >> 5) == 0x6) { |
| 118 | + cp = lead & 0x1F; trail = 1; |
| 119 | + } else if ((lead >> 4) == 0xE) { |
| 120 | + cp = lead & 0x0F; trail = 2; |
| 121 | + } else if ((lead >> 3) == 0x1E) { |
| 122 | + cp = lead & 0x07; trail = 3; |
| 123 | + } else { |
| 124 | + result.push_back(0xFFFD); |
| 125 | + continue; |
| 126 | + } |
| 127 | + if (s + trail > end) { |
| 128 | + result.push_back(0xFFFD); |
| 129 | + break; |
| 130 | + } |
| 131 | + bool valid = true; |
| 132 | + for (int i = 0; i < trail; ++i) { |
| 133 | + if ((s[i] & 0xC0) != 0x80) { valid = false; break; } |
| 134 | + cp = (cp << 6) | (s[i] & 0x3F); |
| 135 | + } |
| 136 | + if (!valid) { |
| 137 | + result.push_back(0xFFFD); |
| 138 | + continue; |
| 139 | + } |
| 140 | + s += trail; |
| 141 | + // Reject overlong encodings, surrogates, and out-of-range values. |
| 142 | + if ((trail == 1 && cp < 0x80) || |
| 143 | + (trail == 2 && cp < 0x800) || |
| 144 | + (trail == 3 && cp < 0x10000) || |
| 145 | + (cp >= 0xD800 && cp <= 0xDFFF) || |
| 146 | + cp > 0x10FFFF) { |
| 147 | + result.push_back(0xFFFD); |
| 148 | + continue; |
| 149 | + } |
| 150 | + if (cp <= 0xFFFF) { |
| 151 | + result.push_back(static_cast<char16_t>(cp)); |
| 152 | + } else { |
| 153 | + cp -= 0x10000; |
| 154 | + result.push_back(static_cast<char16_t>(0xD800 + (cp >> 10))); |
| 155 | + result.push_back(static_cast<char16_t>(0xDC00 + (cp & 0x3FF))); |
| 156 | + } |
| 157 | + } |
| 158 | + return result; |
| 159 | + } |
| 160 | + |
106 | 161 | static JSStringRef CreateUTF8(const char* string, size_t length) { |
107 | 162 | if (length == NAPI_AUTO_LENGTH) { |
108 | 163 | return JSStringCreateWithUTF8CString(string); |
109 | 164 | } |
110 | 165 |
|
111 | | - std::u16string u16str{std::wstring_convert< |
112 | | - std::codecvt_utf8_utf16<char16_t>, char16_t>{}.from_bytes(string, string + length)}; |
| 166 | + std::u16string u16str{Utf8ToUtf16(string, length)}; |
113 | 167 | return JSStringCreateWithCharacters(reinterpret_cast<JSChar*>(u16str.data()), u16str.size()); |
114 | 168 | } |
115 | 169 |
|
|
0 commit comments