|
42 | 42 |
|
43 | 43 | #include "node_i18n.h" |
44 | 44 | #include "node_external_reference.h" |
| 45 | +#include "simdutf.h" |
45 | 46 |
|
46 | 47 | #if defined(NODE_HAVE_I18N_SUPPORT) |
47 | 48 |
|
@@ -146,7 +147,6 @@ MaybeLocal<Object> Transcode(Environment* env, |
146 | 147 | const char* source, |
147 | 148 | const size_t source_length, |
148 | 149 | UErrorCode* status) { |
149 | | - *status = U_ZERO_ERROR; |
150 | 150 | MaybeLocal<Object> ret; |
151 | 151 | MaybeStackBuffer<char> result; |
152 | 152 | Converter to(toEncoding); |
@@ -169,22 +169,21 @@ MaybeLocal<Object> Transcode(Environment* env, |
169 | 169 | return ret; |
170 | 170 | } |
171 | 171 |
|
172 | | -MaybeLocal<Object> TranscodeToUcs2(Environment* env, |
173 | | - const char* fromEncoding, |
174 | | - const char* toEncoding, |
175 | | - const char* source, |
176 | | - const size_t source_length, |
177 | | - UErrorCode* status) { |
178 | | - *status = U_ZERO_ERROR; |
179 | | - MaybeLocal<Object> ret; |
| 172 | +MaybeLocal<Object> TranscodeLatin1ToUcs2(Environment* env, |
| 173 | + const char* fromEncoding, |
| 174 | + const char* toEncoding, |
| 175 | + const char* source, |
| 176 | + const size_t source_length, |
| 177 | + UErrorCode* status) { |
180 | 178 | MaybeStackBuffer<UChar> destbuf(source_length); |
181 | | - Converter from(fromEncoding); |
182 | | - const size_t length_in_chars = source_length * sizeof(UChar); |
183 | | - ucnv_toUChars(from.conv(), *destbuf, length_in_chars, |
184 | | - source, source_length, status); |
185 | | - if (U_SUCCESS(*status)) |
186 | | - ret = ToBufferEndian(env, &destbuf); |
187 | | - return ret; |
| 179 | + auto actual_length = |
| 180 | + simdutf::convert_latin1_to_utf16le(source, source_length, destbuf.out()); |
| 181 | + if (actual_length == 0) { |
| 182 | + *status = U_INVALID_CHAR_FOUND; |
| 183 | + return {}; |
| 184 | + } |
| 185 | + |
| 186 | + return Buffer::New(env, &destbuf); |
188 | 187 | } |
189 | 188 |
|
190 | 189 | MaybeLocal<Object> TranscodeFromUcs2(Environment* env, |
@@ -193,13 +192,11 @@ MaybeLocal<Object> TranscodeFromUcs2(Environment* env, |
193 | 192 | const char* source, |
194 | 193 | const size_t source_length, |
195 | 194 | UErrorCode* status) { |
196 | | - *status = U_ZERO_ERROR; |
197 | 195 | MaybeStackBuffer<UChar> sourcebuf; |
198 | 196 | MaybeLocal<Object> ret; |
199 | 197 | Converter to(toEncoding); |
200 | 198 |
|
201 | | - size_t sublen = ucnv_getMinCharSize(to.conv()); |
202 | | - std::string sub(sublen, '?'); |
| 199 | + std::string sub(to.min_char_size(), '?'); |
203 | 200 | to.set_subst_chars(sub.c_str()); |
204 | 201 |
|
205 | 202 | const size_t length_in_chars = source_length / sizeof(UChar); |
@@ -220,26 +217,18 @@ MaybeLocal<Object> TranscodeUcs2FromUtf8(Environment* env, |
220 | 217 | const char* source, |
221 | 218 | const size_t source_length, |
222 | 219 | UErrorCode* status) { |
223 | | - *status = U_ZERO_ERROR; |
224 | | - MaybeStackBuffer<UChar> destbuf; |
225 | | - int32_t result_length; |
226 | | - u_strFromUTF8(*destbuf, destbuf.capacity(), &result_length, |
227 | | - source, source_length, status); |
228 | | - MaybeLocal<Object> ret; |
229 | | - if (U_SUCCESS(*status)) { |
230 | | - destbuf.SetLength(result_length); |
231 | | - ret = ToBufferEndian(env, &destbuf); |
232 | | - } else if (*status == U_BUFFER_OVERFLOW_ERROR) { |
233 | | - *status = U_ZERO_ERROR; |
234 | | - destbuf.AllocateSufficientStorage(result_length); |
235 | | - u_strFromUTF8(*destbuf, result_length, &result_length, |
236 | | - source, source_length, status); |
237 | | - if (U_SUCCESS(*status)) { |
238 | | - destbuf.SetLength(result_length); |
239 | | - ret = ToBufferEndian(env, &destbuf); |
240 | | - } |
| 220 | + size_t expected_utf16_length = |
| 221 | + simdutf::utf16_length_from_utf8(source, source_length); |
| 222 | + MaybeStackBuffer<UChar> destbuf(expected_utf16_length); |
| 223 | + auto actual_length = |
| 224 | + simdutf::convert_utf8_to_utf16le(source, source_length, destbuf.out()); |
| 225 | + |
| 226 | + if (actual_length == 0) { |
| 227 | + *status = U_INVALID_CHAR_FOUND; |
| 228 | + return {}; |
241 | 229 | } |
242 | | - return ret; |
| 230 | + |
| 231 | + return Buffer::New(env, &destbuf); |
243 | 232 | } |
244 | 233 |
|
245 | 234 | MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env, |
@@ -248,32 +237,25 @@ MaybeLocal<Object> TranscodeUtf8FromUcs2(Environment* env, |
248 | 237 | const char* source, |
249 | 238 | const size_t source_length, |
250 | 239 | UErrorCode* status) { |
251 | | - *status = U_ZERO_ERROR; |
252 | | - MaybeLocal<Object> ret; |
253 | 240 | const size_t length_in_chars = source_length / sizeof(UChar); |
254 | | - int32_t result_length; |
255 | | - MaybeStackBuffer<UChar> sourcebuf; |
256 | | - MaybeStackBuffer<char> destbuf; |
257 | | - CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars); |
258 | | - u_strToUTF8(*destbuf, destbuf.capacity(), &result_length, |
259 | | - *sourcebuf, length_in_chars, status); |
260 | | - if (U_SUCCESS(*status)) { |
261 | | - destbuf.SetLength(result_length); |
262 | | - ret = ToBufferEndian(env, &destbuf); |
263 | | - } else if (*status == U_BUFFER_OVERFLOW_ERROR) { |
264 | | - *status = U_ZERO_ERROR; |
265 | | - destbuf.AllocateSufficientStorage(result_length); |
266 | | - u_strToUTF8(*destbuf, result_length, &result_length, *sourcebuf, |
267 | | - length_in_chars, status); |
268 | | - if (U_SUCCESS(*status)) { |
269 | | - destbuf.SetLength(result_length); |
270 | | - ret = ToBufferEndian(env, &destbuf); |
271 | | - } |
| 241 | + size_t expected_utf8_length = simdutf::utf8_length_from_utf16le( |
| 242 | + reinterpret_cast<const char16_t*>(source), length_in_chars); |
| 243 | + |
| 244 | + MaybeStackBuffer<char> destbuf(expected_utf8_length); |
| 245 | + auto actual_length = simdutf::convert_utf16le_to_utf8( |
| 246 | + reinterpret_cast<const char16_t*>(source), |
| 247 | + length_in_chars, |
| 248 | + destbuf.out()); |
| 249 | + |
| 250 | + if (actual_length == 0) { |
| 251 | + *status = U_INVALID_CHAR_FOUND; |
| 252 | + return {}; |
272 | 253 | } |
273 | | - return ret; |
| 254 | + |
| 255 | + return Buffer::New(env, &destbuf); |
274 | 256 | } |
275 | 257 |
|
276 | | -const char* EncodingName(const enum encoding encoding) { |
| 258 | +constexpr const char* EncodingName(const enum encoding encoding) { |
277 | 259 | switch (encoding) { |
278 | 260 | case ASCII: return "us-ascii"; |
279 | 261 | case LATIN1: return "iso8859-1"; |
@@ -283,7 +265,7 @@ const char* EncodingName(const enum encoding encoding) { |
283 | 265 | } |
284 | 266 | } |
285 | 267 |
|
286 | | -bool SupportedEncoding(const enum encoding encoding) { |
| 268 | +constexpr bool SupportedEncoding(const enum encoding encoding) { |
287 | 269 | switch (encoding) { |
288 | 270 | case ASCII: |
289 | 271 | case LATIN1: |
@@ -308,8 +290,7 @@ void Transcode(const FunctionCallbackInfo<Value>&args) { |
308 | 290 | switch (fromEncoding) { |
309 | 291 | case ASCII: |
310 | 292 | case LATIN1: |
311 | | - if (toEncoding == UCS2) |
312 | | - tfn = &TranscodeToUcs2; |
| 293 | + if (toEncoding == UCS2) tfn = &TranscodeLatin1ToUcs2; |
313 | 294 | break; |
314 | 295 | case UTF8: |
315 | 296 | if (toEncoding == UCS2) |
|