diff --git a/lib/buffer.js b/lib/buffer.js index 898bc5032e5f8d..48b8518fd13d87 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -53,6 +53,7 @@ const { const { byteLengthUtf8, + bufferToString, compare: _compare, compareOffset, createFromString, @@ -1237,8 +1238,7 @@ function btoa(input) { if (input[n].charCodeAt(0) > 0xff) throw lazyDOMException('Invalid character', 'InvalidCharacterError'); } - const buf = Buffer.from(input, 'latin1'); - return buf.toString('base64'); + return bufferToString(input, 'latin1', 'base64'); } // Refs: https://infra.spec.whatwg.org/#forgiving-base64-decode diff --git a/src/node_buffer.cc b/src/node_buffer.cc index acec3c420ce1d2..d5592b25086768 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -520,6 +520,42 @@ MaybeLocal New(Environment* env, namespace { +// TODO(kiliczsh): Buffer.from(buf, fromEnc).toString(buf, toEnc) +void BufferToString(const FunctionCallbackInfo& args) { + CHECK_GE(args.Length(), 3); + CHECK(args[0]->IsString() || args[0]->IsArrayBuffer() || + args[0]->IsSharedArrayBuffer() || args[0]->IsArrayBufferView()); + CHECK(args[1]->IsString()); + CHECK(args[2]->IsString()); + + Environment* env = Environment::GetCurrent(args); + Isolate* isolate = env->isolate(); + + enum encoding from_encoding = ParseEncoding(isolate, args[1], UTF8); + enum encoding to_encoding = ParseEncoding(isolate, args[2], UTF8); + + Local error; + Local ret; + MaybeLocal maybe_ret; + + if (args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() || + args[0]->IsArrayBufferView()) { + ArrayBufferViewContents buffer(args[0]); + if (buffer.length() == 0) { return args.GetReturnValue().SetEmptyString(); } + maybe_ret = StringBytes::Encode(isolate, buffer.data(), buffer.length(), from_encoding, &error); + } else if (args[0]->IsString()) { + String::Utf8Value value(isolate, args[0].As()); + char* str(*value); + maybe_ret = StringBytes::Encode(isolate, str, to_encoding, &error); + } + if (!maybe_ret.ToLocal(&ret)) { + CHECK(!error.IsEmpty()); + isolate->ThrowException(error); + return; + } + args.GetReturnValue().Set(ret); +} + void CreateFromString(const FunctionCallbackInfo& args) { CHECK(args[0]->IsString()); CHECK(args[1]->IsInt32()); @@ -1325,6 +1361,7 @@ void Initialize(Local target, SetMethod(context, target, "setBufferPrototype", SetBufferPrototype); SetMethodNoSideEffect(context, target, "createFromString", CreateFromString); + SetMethodNoSideEffect(context, target, "bufferToString", BufferToString); SetMethodNoSideEffect(context, target, "decodeUTF8", DecodeUTF8); SetMethodNoSideEffect(context, target, "byteLengthUtf8", ByteLengthUtf8); @@ -1382,6 +1419,7 @@ void Initialize(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(SetBufferPrototype); + registry->Register(BufferToString); registry->Register(CreateFromString); registry->Register(DecodeUTF8);