1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22#include "string_bytes.h" 23 24#include "base64-inl.h" 25#include "env-inl.h" 26#include "node_buffer.h" 27#include "node_errors.h" 28#include "simdutf.h" 29#include "util.h" 30 31#include <climits> 32#include <cstring> // memcpy 33 34#include <algorithm> 35 36// When creating strings >= this length v8's gc spins up and consumes 37// most of the execution time. For these cases it's more performant to 38// use external string resources. 39#define EXTERN_APEX 0xFBEE9 40 41namespace node { 42 43using v8::HandleScope; 44using v8::Isolate; 45using v8::Just; 46using v8::Local; 47using v8::Maybe; 48using v8::MaybeLocal; 49using v8::Nothing; 50using v8::String; 51using v8::Value; 52 53namespace { 54 55template <typename ResourceType, typename TypeName> 56class ExternString: public ResourceType { 57 public: 58 ~ExternString() override { 59 free(const_cast<TypeName*>(data_)); 60 isolate()->AdjustAmountOfExternalAllocatedMemory(-byte_length()); 61 } 62 63 const TypeName* data() const override { 64 return data_; 65 } 66 67 size_t length() const override { 68 return length_; 69 } 70 71 int64_t byte_length() const { 72 return length() * sizeof(*data()); 73 } 74 75 static MaybeLocal<Value> NewFromCopy(Isolate* isolate, 76 const TypeName* data, 77 size_t length, 78 Local<Value>* error) { 79 if (length == 0) 80 return String::Empty(isolate); 81 82 if (length < EXTERN_APEX) 83 return NewSimpleFromCopy(isolate, data, length, error); 84 85 TypeName* new_data = node::UncheckedMalloc<TypeName>(length); 86 if (new_data == nullptr) { 87 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 88 return MaybeLocal<Value>(); 89 } 90 memcpy(new_data, data, length * sizeof(*new_data)); 91 92 return ExternString<ResourceType, TypeName>::New(isolate, 93 new_data, 94 length, 95 error); 96 } 97 98 // uses "data" for external resource, and will be free'd on gc 99 static MaybeLocal<Value> New(Isolate* isolate, 100 TypeName* data, 101 size_t length, 102 Local<Value>* error) { 103 if (length == 0) 104 return String::Empty(isolate); 105 106 if (length < EXTERN_APEX) { 107 MaybeLocal<Value> str = NewSimpleFromCopy(isolate, data, length, error); 108 free(data); 109 return str; 110 } 111 112 ExternString* h_str = new ExternString<ResourceType, TypeName>(isolate, 113 data, 114 length); 115 MaybeLocal<Value> str = NewExternal(isolate, h_str); 116 isolate->AdjustAmountOfExternalAllocatedMemory(h_str->byte_length()); 117 118 if (str.IsEmpty()) { 119 delete h_str; 120 *error = node::ERR_STRING_TOO_LONG(isolate); 121 return MaybeLocal<Value>(); 122 } 123 124 return str.ToLocalChecked(); 125 } 126 127 inline Isolate* isolate() const { return isolate_; } 128 129 private: 130 ExternString(Isolate* isolate, const TypeName* data, size_t length) 131 : isolate_(isolate), data_(data), length_(length) { } 132 static MaybeLocal<Value> NewExternal(Isolate* isolate, 133 ExternString* h_str); 134 135 // This method does not actually create ExternString instances. 136 static MaybeLocal<Value> NewSimpleFromCopy(Isolate* isolate, 137 const TypeName* data, 138 size_t length, 139 Local<Value>* error); 140 141 Isolate* isolate_; 142 const TypeName* data_; 143 size_t length_; 144}; 145 146 147typedef ExternString<String::ExternalOneByteStringResource, 148 char> ExternOneByteString; 149typedef ExternString<String::ExternalStringResource, 150 uint16_t> ExternTwoByteString; 151 152 153template <> 154MaybeLocal<Value> ExternOneByteString::NewExternal( 155 Isolate* isolate, ExternOneByteString* h_str) { 156 return String::NewExternalOneByte(isolate, h_str).FromMaybe(Local<Value>()); 157} 158 159 160template <> 161MaybeLocal<Value> ExternTwoByteString::NewExternal( 162 Isolate* isolate, ExternTwoByteString* h_str) { 163 return String::NewExternalTwoByte(isolate, h_str).FromMaybe(Local<Value>()); 164} 165 166template <> 167MaybeLocal<Value> ExternOneByteString::NewSimpleFromCopy(Isolate* isolate, 168 const char* data, 169 size_t length, 170 Local<Value>* error) { 171 MaybeLocal<String> str = 172 String::NewFromOneByte(isolate, 173 reinterpret_cast<const uint8_t*>(data), 174 v8::NewStringType::kNormal, 175 length); 176 if (str.IsEmpty()) { 177 *error = node::ERR_STRING_TOO_LONG(isolate); 178 return MaybeLocal<Value>(); 179 } 180 return str.ToLocalChecked(); 181} 182 183 184template <> 185MaybeLocal<Value> ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate, 186 const uint16_t* data, 187 size_t length, 188 Local<Value>* error) { 189 MaybeLocal<String> str = 190 String::NewFromTwoByte(isolate, 191 data, 192 v8::NewStringType::kNormal, 193 length); 194 if (str.IsEmpty()) { 195 *error = node::ERR_STRING_TOO_LONG(isolate); 196 return MaybeLocal<Value>(); 197 } 198 return str.ToLocalChecked(); 199} 200 201} // anonymous namespace 202 203// supports regular and URL-safe base64 204const int8_t unbase64_table[256] = 205 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1, 206 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 207 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 208 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, 209 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 210 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, 211 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 212 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 213 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 214 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 215 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 216 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 217 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 218 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 219 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 220 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 221 }; 222 223 224static const int8_t unhex_table[256] = 225 { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 226 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 227 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 228 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, 229 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 230 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 231 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 232 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 233 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 234 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 235 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 236 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 237 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 238 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 239 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 240 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 241 }; 242 243static inline unsigned unhex(uint8_t x) { 244 return unhex_table[x]; 245} 246 247template <typename TypeName> 248static size_t hex_decode(char* buf, 249 size_t len, 250 const TypeName* src, 251 const size_t srcLen) { 252 size_t i; 253 for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) { 254 unsigned a = unhex(static_cast<uint8_t>(src[i * 2 + 0])); 255 unsigned b = unhex(static_cast<uint8_t>(src[i * 2 + 1])); 256 if (!~a || !~b) 257 return i; 258 buf[i] = (a << 4) | b; 259 } 260 261 return i; 262} 263 264size_t StringBytes::WriteUCS2( 265 Isolate* isolate, char* buf, size_t buflen, Local<String> str, int flags) { 266 uint16_t* const dst = reinterpret_cast<uint16_t*>(buf); 267 268 size_t max_chars = buflen / sizeof(*dst); 269 if (max_chars == 0) { 270 return 0; 271 } 272 273 uint16_t* const aligned_dst = AlignUp(dst, sizeof(*dst)); 274 size_t nchars; 275 if (aligned_dst == dst) { 276 nchars = str->Write(isolate, dst, 0, max_chars, flags); 277 return nchars * sizeof(*dst); 278 } 279 280 CHECK_EQ(reinterpret_cast<uintptr_t>(aligned_dst) % sizeof(*dst), 0); 281 282 // Write all but the last char 283 max_chars = std::min(max_chars, static_cast<size_t>(str->Length())); 284 if (max_chars == 0) { 285 return 0; 286 } 287 nchars = str->Write(isolate, aligned_dst, 0, max_chars - 1, flags); 288 CHECK_EQ(nchars, max_chars - 1); 289 290 // Shift everything to unaligned-left 291 memmove(dst, aligned_dst, nchars * sizeof(*dst)); 292 293 // One more char to be written 294 uint16_t last; 295 CHECK_EQ(str->Write(isolate, &last, nchars, 1, flags), 1); 296 memcpy(buf + nchars * sizeof(*dst), &last, sizeof(last)); 297 nchars++; 298 299 return nchars * sizeof(*dst); 300} 301 302size_t StringBytes::Write(Isolate* isolate, 303 char* buf, 304 size_t buflen, 305 Local<Value> val, 306 enum encoding encoding) { 307 HandleScope scope(isolate); 308 size_t nbytes; 309 310 CHECK(val->IsString() == true); 311 Local<String> str = val.As<String>(); 312 313 int flags = String::HINT_MANY_WRITES_EXPECTED | 314 String::NO_NULL_TERMINATION | 315 String::REPLACE_INVALID_UTF8; 316 317 switch (encoding) { 318 case ASCII: 319 case LATIN1: 320 if (str->IsExternalOneByte()) { 321 auto ext = str->GetExternalOneByteStringResource(); 322 nbytes = std::min(buflen, ext->length()); 323 memcpy(buf, ext->data(), nbytes); 324 } else { 325 uint8_t* const dst = reinterpret_cast<uint8_t*>(buf); 326 nbytes = str->WriteOneByte(isolate, dst, 0, buflen, flags); 327 } 328 break; 329 330 case BUFFER: 331 case UTF8: 332 nbytes = str->WriteUtf8(isolate, buf, buflen, nullptr, flags); 333 break; 334 335 case UCS2: { 336 nbytes = WriteUCS2(isolate, buf, buflen, str, flags); 337 338 // Node's "ucs2" encoding wants LE character data stored in 339 // the Buffer, so we need to reorder on BE platforms. See 340 // https://nodejs.org/api/buffer.html regarding Node's "ucs2" 341 // encoding specification 342 if (IsBigEndian()) 343 SwapBytes16(buf, nbytes); 344 345 break; 346 } 347 348 case BASE64URL: 349 // Fall through 350 case BASE64: 351 if (str->IsExternalOneByte()) { 352 auto ext = str->GetExternalOneByteStringResource(); 353 nbytes = base64_decode(buf, buflen, ext->data(), ext->length()); 354 } else { 355 String::Value value(isolate, str); 356 nbytes = base64_decode(buf, buflen, *value, value.length()); 357 } 358 break; 359 360 case HEX: 361 if (str->IsExternalOneByte()) { 362 auto ext = str->GetExternalOneByteStringResource(); 363 nbytes = hex_decode(buf, buflen, ext->data(), ext->length()); 364 } else { 365 String::Value value(isolate, str); 366 nbytes = hex_decode(buf, buflen, *value, value.length()); 367 } 368 break; 369 370 default: 371 UNREACHABLE("unknown encoding"); 372 } 373 374 return nbytes; 375} 376 377// Quick and dirty size calculation 378// Will always be at least big enough, but may have some extra 379// UTF8 can be as much as 3x the size, Base64 can have 1-2 extra bytes 380Maybe<size_t> StringBytes::StorageSize(Isolate* isolate, 381 Local<Value> val, 382 enum encoding encoding) { 383 HandleScope scope(isolate); 384 size_t data_size = 0; 385 bool is_buffer = Buffer::HasInstance(val); 386 387 if (is_buffer && (encoding == BUFFER || encoding == LATIN1)) { 388 return Just(Buffer::Length(val)); 389 } 390 391 Local<String> str; 392 if (!val->ToString(isolate->GetCurrentContext()).ToLocal(&str)) 393 return Nothing<size_t>(); 394 395 switch (encoding) { 396 case ASCII: 397 case LATIN1: 398 data_size = str->Length(); 399 break; 400 401 case BUFFER: 402 case UTF8: 403 // A single UCS2 codepoint never takes up more than 3 utf8 bytes. 404 // It is an exercise for the caller to decide when a string is 405 // long enough to justify calling Size() instead of StorageSize() 406 data_size = 3 * str->Length(); 407 break; 408 409 case UCS2: 410 data_size = str->Length() * sizeof(uint16_t); 411 break; 412 413 case BASE64URL: 414 // Fall through 415 case BASE64: 416 data_size = base64_decoded_size_fast(str->Length()); 417 break; 418 419 case HEX: 420 CHECK(str->Length() % 2 == 0 && "invalid hex string length"); 421 data_size = str->Length() / 2; 422 break; 423 424 default: 425 UNREACHABLE("unknown encoding"); 426 } 427 428 return Just(data_size); 429} 430 431Maybe<size_t> StringBytes::Size(Isolate* isolate, 432 Local<Value> val, 433 enum encoding encoding) { 434 HandleScope scope(isolate); 435 436 if (Buffer::HasInstance(val) && (encoding == BUFFER || encoding == LATIN1)) 437 return Just(Buffer::Length(val)); 438 439 Local<String> str; 440 if (!val->ToString(isolate->GetCurrentContext()).ToLocal(&str)) 441 return Nothing<size_t>(); 442 443 switch (encoding) { 444 case ASCII: 445 case LATIN1: 446 return Just<size_t>(str->Length()); 447 448 case BUFFER: 449 case UTF8: 450 return Just<size_t>(str->Utf8Length(isolate)); 451 452 case UCS2: 453 return Just(str->Length() * sizeof(uint16_t)); 454 455 case BASE64URL: 456 // Fall through 457 case BASE64: { 458 String::Value value(isolate, str); 459 return Just(base64_decoded_size(*value, value.length())); 460 } 461 462 case HEX: 463 return Just<size_t>(str->Length() / 2); 464 } 465 466 UNREACHABLE(); 467} 468 469static void force_ascii_slow(const char* src, char* dst, size_t len) { 470 for (size_t i = 0; i < len; ++i) { 471 dst[i] = src[i] & 0x7f; 472 } 473} 474 475 476static void force_ascii(const char* src, char* dst, size_t len) { 477 if (len < 16) { 478 force_ascii_slow(src, dst, len); 479 return; 480 } 481 482 const unsigned bytes_per_word = sizeof(uintptr_t); 483 const unsigned align_mask = bytes_per_word - 1; 484 const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask; 485 const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask; 486 487 if (src_unalign > 0) { 488 if (src_unalign == dst_unalign) { 489 const unsigned unalign = bytes_per_word - src_unalign; 490 force_ascii_slow(src, dst, unalign); 491 src += unalign; 492 dst += unalign; 493 len -= src_unalign; 494 } else { 495 force_ascii_slow(src, dst, len); 496 return; 497 } 498 } 499 500#if defined(_WIN64) || defined(_LP64) 501 const uintptr_t mask = ~0x8080808080808080ll; 502#else 503 const uintptr_t mask = ~0x80808080l; 504#endif 505 506 const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src); 507 uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst); 508 509 for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) { 510 dstw[i] = srcw[i] & mask; 511 } 512 513 const unsigned remainder = len & align_mask; 514 if (remainder > 0) { 515 const size_t offset = len - remainder; 516 force_ascii_slow(src + offset, dst + offset, remainder); 517 } 518} 519 520 521size_t StringBytes::hex_encode( 522 const char* src, 523 size_t slen, 524 char* dst, 525 size_t dlen) { 526 // We know how much we'll write, just make sure that there's space. 527 CHECK(dlen >= slen * 2 && 528 "not enough space provided for hex encode"); 529 530 dlen = slen * 2; 531 for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) { 532 static const char hex[] = "0123456789abcdef"; 533 uint8_t val = static_cast<uint8_t>(src[i]); 534 dst[k + 0] = hex[val >> 4]; 535 dst[k + 1] = hex[val & 15]; 536 } 537 538 return dlen; 539} 540 541std::string StringBytes::hex_encode(const char* src, size_t slen) { 542 size_t dlen = slen * 2; 543 std::string dst(dlen, '\0'); 544 hex_encode(src, slen, dst.data(), dlen); 545 return dst; 546} 547 548#define CHECK_BUFLEN_IN_RANGE(len) \ 549 do { \ 550 if ((len) > Buffer::kMaxLength) { \ 551 *error = node::ERR_BUFFER_TOO_LARGE(isolate); \ 552 return MaybeLocal<Value>(); \ 553 } \ 554 } while (0) 555 556 557MaybeLocal<Value> StringBytes::Encode(Isolate* isolate, 558 const char* buf, 559 size_t buflen, 560 enum encoding encoding, 561 Local<Value>* error) { 562 CHECK_BUFLEN_IN_RANGE(buflen); 563 564 if (!buflen && encoding != BUFFER) { 565 return String::Empty(isolate); 566 } 567 568 MaybeLocal<String> val; 569 570 switch (encoding) { 571 case BUFFER: 572 { 573 auto maybe_buf = Buffer::Copy(isolate, buf, buflen); 574 Local<v8::Object> buf; 575 if (!maybe_buf.ToLocal(&buf)) { 576 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 577 } 578 return buf; 579 } 580 581 case ASCII: 582 if (simdutf::validate_ascii_with_errors(buf, buflen).error) { 583 // The input contains non-ASCII bytes. 584 char* out = node::UncheckedMalloc(buflen); 585 if (out == nullptr) { 586 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 587 return MaybeLocal<Value>(); 588 } 589 force_ascii(buf, out, buflen); 590 return ExternOneByteString::New(isolate, out, buflen, error); 591 } else { 592 return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error); 593 } 594 595 case UTF8: 596 { 597 val = String::NewFromUtf8(isolate, 598 buf, 599 v8::NewStringType::kNormal, 600 buflen); 601 Local<String> str; 602 if (!val.ToLocal(&str)) { 603 *error = node::ERR_STRING_TOO_LONG(isolate); 604 } 605 return str; 606 } 607 608 case LATIN1: 609 return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error); 610 611 case BASE64: { 612 size_t dlen = base64_encoded_size(buflen); 613 char* dst = node::UncheckedMalloc(dlen); 614 if (dst == nullptr) { 615 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 616 return MaybeLocal<Value>(); 617 } 618 619 size_t written = base64_encode(buf, buflen, dst, dlen); 620 CHECK_EQ(written, dlen); 621 622 return ExternOneByteString::New(isolate, dst, dlen, error); 623 } 624 625 case BASE64URL: { 626 size_t dlen = base64_encoded_size(buflen, Base64Mode::URL); 627 char* dst = node::UncheckedMalloc(dlen); 628 if (dst == nullptr) { 629 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 630 return MaybeLocal<Value>(); 631 } 632 633 size_t written = base64_encode(buf, buflen, dst, dlen, Base64Mode::URL); 634 CHECK_EQ(written, dlen); 635 636 return ExternOneByteString::New(isolate, dst, dlen, error); 637 } 638 639 case HEX: { 640 size_t dlen = buflen * 2; 641 char* dst = node::UncheckedMalloc(dlen); 642 if (dst == nullptr) { 643 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 644 return MaybeLocal<Value>(); 645 } 646 size_t written = hex_encode(buf, buflen, dst, dlen); 647 CHECK_EQ(written, dlen); 648 649 return ExternOneByteString::New(isolate, dst, dlen, error); 650 } 651 652 case UCS2: { 653 size_t str_len = buflen / 2; 654 if (IsBigEndian()) { 655 uint16_t* dst = node::UncheckedMalloc<uint16_t>(str_len); 656 if (str_len != 0 && dst == nullptr) { 657 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 658 return MaybeLocal<Value>(); 659 } 660 for (size_t i = 0, k = 0; k < str_len; i += 2, k += 1) { 661 // The input is in *little endian*, because that's what Node.js 662 // expects, so the high byte comes after the low byte. 663 const uint8_t hi = static_cast<uint8_t>(buf[i + 1]); 664 const uint8_t lo = static_cast<uint8_t>(buf[i + 0]); 665 dst[k] = static_cast<uint16_t>(hi) << 8 | lo; 666 } 667 return ExternTwoByteString::New(isolate, dst, str_len, error); 668 } 669 if (reinterpret_cast<uintptr_t>(buf) % 2 != 0) { 670 // Unaligned data still means we can't directly pass it to V8. 671 char* dst = node::UncheckedMalloc(buflen); 672 if (dst == nullptr) { 673 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 674 return MaybeLocal<Value>(); 675 } 676 memcpy(dst, buf, buflen); 677 return ExternTwoByteString::New( 678 isolate, reinterpret_cast<uint16_t*>(dst), str_len, error); 679 } 680 return ExternTwoByteString::NewFromCopy( 681 isolate, reinterpret_cast<const uint16_t*>(buf), str_len, error); 682 } 683 684 default: 685 UNREACHABLE("unknown encoding"); 686 } 687} 688 689 690MaybeLocal<Value> StringBytes::Encode(Isolate* isolate, 691 const uint16_t* buf, 692 size_t buflen, 693 Local<Value>* error) { 694 if (buflen == 0) return String::Empty(isolate); 695 CHECK_BUFLEN_IN_RANGE(buflen); 696 697 // Node's "ucs2" encoding expects LE character data inside a 698 // Buffer, so we need to reorder on BE platforms. See 699 // https://nodejs.org/api/buffer.html regarding Node's "ucs2" 700 // encoding specification 701 if (IsBigEndian()) { 702 uint16_t* dst = node::UncheckedMalloc<uint16_t>(buflen); 703 if (dst == nullptr) { 704 *error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate); 705 return MaybeLocal<Value>(); 706 } 707 size_t nbytes = buflen * sizeof(uint16_t); 708 memcpy(dst, buf, nbytes); 709 SwapBytes16(reinterpret_cast<char*>(dst), nbytes); 710 return ExternTwoByteString::New(isolate, dst, buflen, error); 711 } else { 712 return ExternTwoByteString::NewFromCopy(isolate, buf, buflen, error); 713 } 714} 715 716MaybeLocal<Value> StringBytes::Encode(Isolate* isolate, 717 const char* buf, 718 enum encoding encoding, 719 Local<Value>* error) { 720 const size_t len = strlen(buf); 721 return Encode(isolate, buf, len, encoding, error); 722} 723 724} // namespace node 725