| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4063cdc commit 16ee02f
7 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5126,6 +5126,17 @@ For code running using Node.js APIs, converting between base64-encoded strings | |||
| 5126 | 5126 | and binary data should be performed using `Buffer.from(str, 'base64')` and | |
| 5127 | 5127 | `buf.toString('base64')`.** | |
| 5128 | 5128 | ||
| 5129 | + ### `buffer.isUtf8(input)` | ||
| 5130 | + | ||
| 5131 | + <!-- YAML | ||
| 5132 | + added: REPLACEME | ||
| 5133 | + --> | ||
| 5134 | + | ||
| 5135 | + * input {Buffer | ArrayBuffer | TypedArray} The input to validate. | ||
| 5136 | + * Returns: {boolean} Returns `true` if and only if the input is valid UTF-8. | ||
| 5137 | + | ||
| 5138 | + This function is used to check if input contains UTF-8 code points (characters). | ||
| 5139 | + | ||
| 5129 | 5140 | ### `buffer.INSPECT_MAX_BYTES` | |
| 5130 | 5141 | ||
| 5131 | 5142 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -57,6 +57,7 @@ const { | |||
| 57 | 57 | compareOffset, | |
| 58 | 58 | createFromString, | |
| 59 | 59 | fill: bindingFill, | |
| 60 | + isUtf8: bindingIsUtf8, | ||
| 60 | 61 | indexOfBuffer, | |
| 61 | 62 | indexOfNumber, | |
| 62 | 63 | indexOfString, | |
@@ -83,7 +84,8 @@ const { | |||
| 83 | 84 | const { | |
| 84 | 85 | isAnyArrayBuffer, | |
| 85 | 86 | isArrayBufferView, | |
| 86 | - isUint8Array | ||
| 87 | + isUint8Array, | ||
| 88 | + isTypedArray, | ||
| 87 | 89 | } = require('internal/util/types'); | |
| 88 | 90 | const { | |
| 89 | 91 | inspect: utilInspect | |
@@ -1322,13 +1324,22 @@ function atob(input) { | |||
| 1322 | 1324 | return Buffer.from(input, 'base64').toString('latin1'); | |
| 1323 | 1325 | } | |
| 1324 | 1326 | ||
| 1327 | + function isUtf8(input) { | ||
| 1328 | + if (isTypedArray(input) || isAnyArrayBuffer(input)) { | ||
| 1329 | + return bindingIsUtf8(input); | ||
| 1330 | + } | ||
| 1331 | + | ||
| 1332 | + throw new ERR_INVALID_ARG_TYPE('input', ['TypedArray', 'Buffer'], input); | ||
| 1333 | + } | ||
| 1334 | + | ||
| 1325 | 1335 | module.exports = { | |
| 1326 | 1336 | Blob, | |
| 1327 | 1337 | File, | |
| 1328 | 1338 | resolveObjectURL, | |
| 1329 | 1339 | Buffer, | |
| 1330 | 1340 | SlowBuffer, | |
| 1331 | 1341 | transcode, | |
| 1342 | + isUtf8, | ||
| 1332 | 1343 | ||
| 1333 | 1344 | // Legacy | |
| 1334 | 1345 | kMaxLength, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1223,6 +1223,20 @@ static void EncodeInto(const FunctionCallbackInfo<Value>& args) { | |||
| 1223 | 1223 | results[1] = written; | |
| 1224 | 1224 | } | |
| 1225 | 1225 | ||
| 1226 | + static void IsUtf8(const FunctionCallbackInfo<Value>& args) { | ||
| 1227 | + Environment* env = Environment::GetCurrent(args); | ||
| 1228 | + CHECK_EQ(args.Length(), 1); | ||
| 1229 | + CHECK(args[0]->IsTypedArray() || args[0]->IsArrayBuffer() || | ||
| 1230 | + args[0]->IsSharedArrayBuffer()); | ||
| 1231 | + ArrayBufferViewContents<char> abv(args[0]); | ||
| 1232 | + | ||
| 1233 | + if (abv.WasDetached()) { | ||
| 1234 | + return node::THROW_ERR_INVALID_STATE( | ||
| 1235 | + env, "Cannot validate on a detached buffer"); | ||
| 1236 | + } | ||
| 1237 | + | ||
| 1238 | + args.GetReturnValue().Set(simdutf::validate_utf8(abv.data(), abv.length())); | ||
| 1239 | + } | ||
| 1226 | 1240 | ||
| 1227 | 1241 | void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) { | |
| 1228 | 1242 | Environment* env = Environment::GetCurrent(args); | |
@@ -1358,6 +1372,8 @@ void Initialize(Local<Object> target, | |||
| 1358 | 1372 | SetMethod(context, target, "encodeInto", EncodeInto); | |
| 1359 | 1373 | SetMethodNoSideEffect(context, target, "encodeUtf8String", EncodeUtf8String); | |
| 1360 | 1374 | ||
| 1375 | + SetMethodNoSideEffect(context, target, "isUtf8", IsUtf8); | ||
| 1376 | + | ||
| 1361 | 1377 | target | |
| 1362 | 1378 | ->Set(context, | |
| 1363 | 1379 | FIXED_ONE_BYTE_STRING(isolate, "kMaxLength"), | |
@@ -1413,6 +1429,8 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { | |||
| 1413 | 1429 | registry->Register(EncodeInto); | |
| 1414 | 1430 | registry->Register(EncodeUtf8String); | |
| 1415 | 1431 | ||
| 1432 | + registry->Register(IsUtf8); | ||
| 1433 | + | ||
| 1416 | 1434 | registry->Register(StringSlice<ASCII>); | |
| 1417 | 1435 | registry->Register(StringSlice<BASE64>); | |
| 1418 | 1436 | registry->Register(StringSlice<BASE64URL>); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -68,6 +68,7 @@ void OOMErrorHandler(const char* location, bool is_heap_oom); | |||
| 68 | 68 | V(ERR_INVALID_ARG_TYPE, TypeError) \ | |
| 69 | 69 | V(ERR_INVALID_OBJECT_DEFINE_PROPERTY, TypeError) \ | |
| 70 | 70 | V(ERR_INVALID_MODULE, Error) \ | |
| 71 | + V(ERR_INVALID_STATE, Error) \ | ||
| 71 | 72 | V(ERR_INVALID_THIS, TypeError) \ | |
| 72 | 73 | V(ERR_INVALID_TRANSFER_OBJECT, TypeError) \ | |
| 73 | 74 | V(ERR_MEMORY_ALLOCATION_FAILED, Error) \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -555,6 +555,7 @@ void ArrayBufferViewContents<T, S>::ReadValue(v8::Local<v8::Value> buf) { | |||
| 555 | 555 | auto ab = buf.As<v8::ArrayBuffer>(); | |
| 556 | 556 | length_ = ab->ByteLength(); | |
| 557 | 557 | data_ = static_cast<T*>(ab->Data()); | |
| 558 | + was_detached_ = ab->WasDetached(); | ||
| 558 | 559 | } else { | |
| 559 | 560 | CHECK(buf->IsSharedArrayBuffer()); | |
| 560 | 561 | auto sab = buf.As<v8::SharedArrayBuffer>(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -510,6 +510,7 @@ class ArrayBufferViewContents { | |||
| 510 | 510 | inline void Read(v8::Local<v8::ArrayBufferView> abv); | |
| 511 | 511 | inline void ReadValue(v8::Local<v8::Value> buf); | |
| 512 | 512 | ||
| 513 | + inline bool WasDetached() const { return was_detached_; } | ||
| 513 | 514 | inline const T* data() const { return data_; } | |
| 514 | 515 | inline size_t length() const { return length_; } | |
| 515 | 516 | ||
@@ -524,6 +525,7 @@ class ArrayBufferViewContents { | |||
| 524 | 525 | T stack_storage_[kStackStorageSize]; | |
| 525 | 526 | T* data_ = nullptr; | |
| 526 | 527 | size_t length_ = 0; | |
| 528 | + bool was_detached_ = false; | ||
| 527 | 529 | }; | |
| 528 | 530 | ||
| 529 | 531 | class Utf8Value : public MaybeStackBuffer<char> { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,86 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + require('../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + const { isUtf8, Buffer } = require('buffer'); | ||
| 6 | + const { TextEncoder } = require('util'); | ||
| 7 | + | ||
| 8 | + const encoder = new TextEncoder(); | ||
| 9 | + | ||
| 10 | + assert.strictEqual(isUtf8(encoder.encode('hello')), true); | ||
| 11 | + assert.strictEqual(isUtf8(encoder.encode('ğ')), true); | ||
| 12 | + assert.strictEqual(isUtf8(Buffer.from([])), true); | ||
| 13 | + | ||
| 14 | + // Taken from test/fixtures/wpt/encoding/textdecoder-fatal.any.js | ||
| 15 | + [ | ||
| 16 | + [0xFF], // 'invalid code' | ||
| 17 | + [0xC0], // 'ends early' | ||
| 18 | + [0xE0], // 'ends early 2' | ||
| 19 | + [0xC0, 0x00], // 'invalid trail' | ||
| 20 | + [0xC0, 0xC0], // 'invalid trail 2' | ||
| 21 | + [0xE0, 0x00], // 'invalid trail 3' | ||
| 22 | + [0xE0, 0xC0], // 'invalid trail 4' | ||
| 23 | + [0xE0, 0x80, 0x00], // 'invalid trail 5' | ||
| 24 | + [0xE0, 0x80, 0xC0], // 'invalid trail 6' | ||
| 25 | + [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], // '> 0x10FFFF' | ||
| 26 | + [0xFE, 0x80, 0x80, 0x80, 0x80, 0x80], // 'obsolete lead byte' | ||
| 27 | + | ||
| 28 | + // Overlong encodings | ||
| 29 | + [0xC0, 0x80], // 'overlong U+0000 - 2 bytes' | ||
| 30 | + [0xE0, 0x80, 0x80], // 'overlong U+0000 - 3 bytes' | ||
| 31 | + [0xF0, 0x80, 0x80, 0x80], // 'overlong U+0000 - 4 bytes' | ||
| 32 | + [0xF8, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 5 bytes' | ||
| 33 | + [0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], // 'overlong U+0000 - 6 bytes' | ||
| 34 | + | ||
| 35 | + [0xC1, 0xBF], // 'overlong U+007F - 2 bytes' | ||
| 36 | + [0xE0, 0x81, 0xBF], // 'overlong U+007F - 3 bytes' | ||
| 37 | + [0xF0, 0x80, 0x81, 0xBF], // 'overlong U+007F - 4 bytes' | ||
| 38 | + [0xF8, 0x80, 0x80, 0x81, 0xBF], // 'overlong U+007F - 5 bytes' | ||
| 39 | + [0xFC, 0x80, 0x80, 0x80, 0x81, 0xBF], // 'overlong U+007F - 6 bytes' | ||
| 40 | + | ||
| 41 | + [0xE0, 0x9F, 0xBF], // 'overlong U+07FF - 3 bytes' | ||
| 42 | + [0xF0, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 4 bytes' | ||
| 43 | + [0xF8, 0x80, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 5 bytes' | ||
| 44 | + [0xFC, 0x80, 0x80, 0x80, 0x9F, 0xBF], // 'overlong U+07FF - 6 bytes' | ||
| 45 | + | ||
| 46 | + [0xF0, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 4 bytes' | ||
| 47 | + [0xF8, 0x80, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 5 bytes' | ||
| 48 | + [0xFC, 0x80, 0x80, 0x8F, 0xBF, 0xBF], // 'overlong U+FFFF - 6 bytes' | ||
| 49 | + | ||
| 50 | + [0xF8, 0x84, 0x8F, 0xBF, 0xBF], // 'overlong U+10FFFF - 5 bytes' | ||
| 51 | + [0xFC, 0x80, 0x84, 0x8F, 0xBF, 0xBF], // 'overlong U+10FFFF - 6 bytes' | ||
| 52 | + | ||
| 53 | + // UTF-16 surrogates encoded as code points in UTF-8 | ||
| 54 | + [0xED, 0xA0, 0x80], // 'lead surrogate' | ||
| 55 | + [0xED, 0xB0, 0x80], // 'trail surrogate' | ||
| 56 | + [0xED, 0xA0, 0x80, 0xED, 0xB0, 0x80], // 'surrogate pair' | ||
| 57 | + ].forEach((input) => { | ||
| 58 | + assert.strictEqual(isUtf8(Buffer.from(input)), false); | ||
| 59 | + }); | ||
| 60 | + | ||
| 61 | + [ | ||
| 62 | + null, | ||
| 63 | + undefined, | ||
| 64 | + 'hello', | ||
| 65 | + true, | ||
| 66 | + false, | ||
| 67 | + ].forEach((input) => { | ||
| 68 | + assert.throws( | ||
| 69 | + () => { isUtf8(input); }, | ||
| 70 | + { | ||
| 71 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 72 | + }, | ||
| 73 | + ); | ||
| 74 | + }); | ||
| 75 | + | ||
| 76 | + { | ||
| 77 | + // Test with detached array buffers | ||
| 78 | + const arrayBuffer = new ArrayBuffer(1024); | ||
| 79 | + structuredClone(arrayBuffer, { transfer: [arrayBuffer] }); | ||
| 80 | + assert.throws( | ||
| 81 | + () => { isUtf8(arrayBuffer); }, | ||
| 82 | + { | ||
| 83 | + code: 'ERR_INVALID_STATE' | ||
| 84 | + } | ||
| 85 | + ); | ||
| 86 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments