diff --git a/deps/v8/test/unittests/heap/encoding_binding_test.cc b/deps/v8/test/unittests/heap/encoding_binding_test.cc new file mode 100644 index 000000000000000..eab6d40c106ee35 --- /dev/null +++ b/deps/v8/test/unittests/heap/encoding_binding_test.cc @@ -0,0 +1,73 @@ +#include "encoding_binding.h" +#include "node_test_fixture.h" +#include "env-inl.h" +#include "v8.h" +#include "gtest/gtest.h" + +namespace node { +namespace encoding_binding { + +bool RunDecodeLatin1(Environment* env, Local args[], Local* result) { + Isolate* isolate = env->isolate(); + TryCatch try_catch(isolate); + + BindingData::DecodeLatin1(FunctionCallbackInfo(args)); + + if (try_catch.HasCaught()) { + return false; + } + + *result = try_catch.Exception(); + return true; +} + +class EncodingBindingTest : public NodeTestFixture {}; + +TEST_F(EncodingBindingTest, DecodeLatin1_ValidInput) { + Environment* env = CreateEnvironment(); + Isolate* isolate = env->isolate(); + HandleScope handle_scope(isolate); + + const uint8_t latin1_data[] = {0xC1, 0xE9, 0xF3}; + Local ab = ArrayBuffer::New(isolate, sizeof(latin1_data)); + memcpy(ab->GetBackingStore()->Data(), latin1_data, sizeof(latin1_data)); + + Local array = Uint8Array::New(ab, 0, sizeof(latin1_data)); + Local args[] = { array }; + + Local result; + EXPECT_TRUE(RunDecodeLatin1(env, args, &result)); + + String::Utf8Value utf8_result(isolate, result); + EXPECT_STREQ(*utf8_result, "Áéó"); +} + +TEST_F(EncodingBindingTest, DecodeLatin1_EmptyInput) { + Environment* env = CreateEnvironment(); + Isolate* isolate = env->isolate(); + HandleScope handle_scope(isolate); + + Local ab = ArrayBuffer::New(isolate, 0); + Local array = Uint8Array::New(ab, 0, 0); + Local args[] = { array }; + + Local result; + EXPECT_TRUE(RunDecodeLatin1(env, args, &result)); + + String::Utf8Value utf8_result(isolate, result); + EXPECT_STREQ(*utf8_result, ""); +} + +TEST_F(EncodingBindingTest, DecodeLatin1_InvalidInput) { + Environment* env = CreateEnvironment(); + Isolate* isolate = env->isolate(); + HandleScope handle_scope(isolate); + + Local args[] = { String::NewFromUtf8Literal(isolate, "Invalid input") }; + + Local result; + EXPECT_FALSE(RunDecodeLatin1(env, args, &result)); +} + +} // namespace encoding_binding +} // namespace node diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js index 252eaa75fac22b5..92329040ff167e3 100644 --- a/lib/internal/encoding.js +++ b/lib/internal/encoding.js @@ -55,6 +55,7 @@ const { encodeIntoResults, encodeUtf8String, decodeUTF8, + decodeLatin1, } = binding; const { Buffer } = require('buffer'); @@ -443,6 +444,10 @@ function makeTextDecoderICU() { return decodeUTF8(input, this[kIgnoreBOM], this[kFatal]); } + if (this[kEncoding] === 'windows-1252') { + return decodeLatin1(input); + } + this.#prepareConverter(); validateObject(options, 'options', kValidateObjectAllowObjectsAndNull); diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc index 97ddd59fb661c84..ced4fbaf103141e 100644 --- a/src/encoding_binding.cc +++ b/src/encoding_binding.cc @@ -1,6 +1,7 @@ #include "encoding_binding.h" #include "ada.h" #include "env-inl.h" +#include "node_buffer.h" #include "node_errors.h" #include "node_external_reference.h" #include "simdutf.h" @@ -226,6 +227,7 @@ void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data, SetMethodNoSideEffect(isolate, target, "decodeUTF8", DecodeUTF8); SetMethodNoSideEffect(isolate, target, "toASCII", ToASCII); SetMethodNoSideEffect(isolate, target, "toUnicode", ToUnicode); + SetMethodNoSideEffect(isolate, target, "decodeLatin1", DecodeLatin1); } void BindingData::CreatePerContextProperties(Local target, @@ -243,6 +245,44 @@ void BindingData::RegisterTimerExternalReferences( registry->Register(DecodeUTF8); registry->Register(ToASCII); registry->Register(ToUnicode); + registry->Register(DecodeLatin1); +} + +void BindingData::DecodeLatin1(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + + CHECK_GE(args.Length(), 1); + if (!(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() || + args[0]->IsArrayBufferView())) { + return node::THROW_ERR_INVALID_ARG_TYPE( + env->isolate(), + "The \"input\" argument must be an instance of ArrayBuffer, " + "SharedArrayBuffer, or ArrayBufferView."); + } + + ArrayBufferViewContents buffer(args[0]); + const uint8_t* data = buffer.data(); + size_t length = buffer.length(); + + if (length == 0) { + return args.GetReturnValue().SetEmptyString(); + } + + std::string result(length * 2, '\0'); + + size_t written = simdutf::convert_latin1_to_utf8( + reinterpret_cast(data), length, &result[0]); + + if (written == 0) { + return node::THROW_ERR_ENCODING_INVALID_ENCODED_DATA( + env->isolate(), "The encoded data was not valid for encoding latin1"); + } + + result.resize(written); + + Local buffer_result = + node::Buffer::Copy(env, result.c_str(), result.length()).ToLocalChecked(); + args.GetReturnValue().Set(buffer_result); } } // namespace encoding_binding diff --git a/src/encoding_binding.h b/src/encoding_binding.h index 2690cb74f8a05bf..97f55394d27641c 100644 --- a/src/encoding_binding.h +++ b/src/encoding_binding.h @@ -31,6 +31,7 @@ class BindingData : public SnapshotableObject { static void EncodeInto(const v8::FunctionCallbackInfo& args); static void EncodeUtf8String(const v8::FunctionCallbackInfo& args); static void DecodeUTF8(const v8::FunctionCallbackInfo& args); + static void DecodeLatin1(const v8::FunctionCallbackInfo& args); static void ToASCII(const v8::FunctionCallbackInfo& args); static void ToUnicode(const v8::FunctionCallbackInfo& args);