| 
24 | 24 | #include "node_blob.h"  | 
25 | 25 | #include "node_errors.h"  | 
26 | 26 | #include "node_external_reference.h"  | 
 | 27 | +#include "node_i18n.h"  | 
27 | 28 | #include "node_internals.h"  | 
28 | 29 | 
 
  | 
29 | 30 | #include "env-inl.h"  | 
@@ -565,6 +566,53 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {  | 
565 | 566 |   args.GetReturnValue().Set(ret);  | 
566 | 567 | }  | 
567 | 568 | 
 
  | 
 | 569 | +// Convert the input into an encoded string  | 
 | 570 | +void DecodeUTF8(const FunctionCallbackInfo<Value>& args) {  | 
 | 571 | +  Environment* env = Environment::GetCurrent(args);  // list, flags  | 
 | 572 | + | 
 | 573 | +  if (!(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() ||  | 
 | 574 | +        args[0]->IsArrayBufferView())) {  | 
 | 575 | +    return node::THROW_ERR_INVALID_ARG_TYPE(  | 
 | 576 | +        env->isolate(),  | 
 | 577 | +        "The \"list\" argument must be an instance of SharedArrayBuffer, "  | 
 | 578 | +        "ArrayBuffer or ArrayBufferView.");  | 
 | 579 | +  }  | 
 | 580 | + | 
 | 581 | +  ArrayBufferViewContents<char> buffer(args[0]);  | 
 | 582 | + | 
 | 583 | +  CHECK(args[1]->IsBoolean());  | 
 | 584 | +  bool ignore_bom = args[1]->BooleanValue(env->isolate());  | 
 | 585 | + | 
 | 586 | +  const char* data = buffer.data();  | 
 | 587 | +  size_t beginning = 0;  | 
 | 588 | +  size_t length = buffer.length();  | 
 | 589 | + | 
 | 590 | +  if (length == 0) return args.GetReturnValue().SetEmptyString();  | 
 | 591 | + | 
 | 592 | +  if (!ignore_bom) {  | 
 | 593 | +    char bom[] = "\xEF\xBB\xBF";  | 
 | 594 | + | 
 | 595 | +    if (strncmp(data, bom, 3) == 0) {  | 
 | 596 | +      beginning += 3;  | 
 | 597 | +      length -= 3;  | 
 | 598 | +    }  | 
 | 599 | +  }  | 
 | 600 | + | 
 | 601 | +  auto output = data + beginning;  | 
 | 602 | + | 
 | 603 | +  Local<Value> error;  | 
 | 604 | +  MaybeLocal<Value> maybe_ret =  | 
 | 605 | +      StringBytes::Encode(env->isolate(), output, length, UTF8, &error);  | 
 | 606 | +  Local<Value> ret;  | 
 | 607 | + | 
 | 608 | +  if (!maybe_ret.ToLocal(&ret)) {  | 
 | 609 | +    CHECK(!error.IsEmpty());  | 
 | 610 | +    env->isolate()->ThrowException(error);  | 
 | 611 | +    return;  | 
 | 612 | +  }  | 
 | 613 | + | 
 | 614 | +  args.GetReturnValue().Set(ret);  | 
 | 615 | +}  | 
568 | 616 | 
 
  | 
569 | 617 | // bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd])  | 
570 | 618 | void Copy(const FunctionCallbackInfo<Value> &args) {  | 
@@ -1282,6 +1330,7 @@ void Initialize(Local<Object> target,  | 
1282 | 1330 | 
 
  | 
1283 | 1331 |   SetMethod(context, target, "setBufferPrototype", SetBufferPrototype);  | 
1284 | 1332 |   SetMethodNoSideEffect(context, target, "createFromString", CreateFromString);  | 
 | 1333 | +  SetMethodNoSideEffect(context, target, "decodeUTF8", DecodeUTF8);  | 
1285 | 1334 | 
 
  | 
1286 | 1335 |   SetMethodNoSideEffect(context, target, "byteLengthUtf8", ByteLengthUtf8);  | 
1287 | 1336 |   SetMethod(context, target, "copy", Copy);  | 
@@ -1339,6 +1388,7 @@ void Initialize(Local<Object> target,  | 
1339 | 1388 | void RegisterExternalReferences(ExternalReferenceRegistry* registry) {  | 
1340 | 1389 |   registry->Register(SetBufferPrototype);  | 
1341 | 1390 |   registry->Register(CreateFromString);  | 
 | 1391 | +  registry->Register(DecodeUTF8);  | 
1342 | 1392 | 
 
  | 
1343 | 1393 |   registry->Register(ByteLengthUtf8);  | 
1344 | 1394 |   registry->Register(Copy);  | 
 | 
0 commit comments