Skip to content

Commit a01cab4

Browse files
fix utf16 JSC
1 parent 2e93e6f commit a01cab4

1 file changed

Lines changed: 58 additions & 4 deletions

File tree

Core/Node-API/Source/js_native_api_javascriptcore.cc

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
#include <stdexcept>
88
#include <string>
99
#include <vector>
10-
#include <locale>
11-
#include <codecvt>
10+
1211

1312
struct napi_callback_info__ {
1413
napi_value newTarget;
@@ -103,13 +102,68 @@ namespace {
103102
}
104103

105104
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+
106161
static JSStringRef CreateUTF8(const char* string, size_t length) {
107162
if (length == NAPI_AUTO_LENGTH) {
108163
return JSStringCreateWithUTF8CString(string);
109164
}
110165

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)};
113167
return JSStringCreateWithCharacters(reinterpret_cast<JSChar*>(u16str.data()), u16str.size());
114168
}
115169

0 commit comments

Comments
 (0)