diff --git a/doc/api/buffer.md b/doc/api/buffer.md index f9fd729b98aaea..e7e3340a838db2 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -415,6 +415,21 @@ function: * [`Buffer.from(arrayBuffer[, byteOffset[, length]])`][`Buffer.from(arrayBuf)`] * [`Buffer.from(string[, encoding])`][`Buffer.from(string)`] +### Buffer methods are callable with `Uint8Array` instances + +All methods on the Buffer prototype are callable with a `Uint8Array` instance. + +```js +const { toString, write } = Buffer.prototype; + +const uint8array = new Uint8Array(5); + +write.call(uint8array, 'hello', 0, 5, 'utf8'); // 5 +// + +toString.call(uint8array, 'utf8'); // 'hello' +``` + ## Buffers and iteration `Buffer` instances can be iterated over using `for..of` syntax: @@ -2058,6 +2073,10 @@ console.log(buf.fill('zz', 'hex')); * `value` {string|Buffer|Uint8Array|integer} What to search for. @@ -2945,10 +2964,14 @@ console.log(buf.readInt32LE(1)); * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -2992,10 +3015,14 @@ console.log(buf.readIntBE(1, 0).toString(16)); * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -3269,6 +3296,9 @@ console.log(buf.readUInt32LE(1).toString(16)); * `encoding` {string} The character encoding to use. **Default:** `'utf8'`. @@ -3909,6 +3946,10 @@ for (const value of buf) { * `string` {string} String to write to `buf`. diff --git a/lib/buffer.js b/lib/buffer.js index 22bbb95eaf79e6..93dab085e23d09 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -73,6 +73,17 @@ const { kStringMaxLength, atob: _atob, btoa: _btoa, + asciiSlice, + base64Slice, + base64urlSlice, + latin1Slice, + hexSlice, + ucs2Slice, + utf8Slice, + base64Write, + base64urlWrite, + hexWrite, + ucs2Write, } = internalBinding('buffer'); const { constants: { @@ -129,6 +140,9 @@ const { markAsUntransferable, addBufferPrototypeMethods, createUnsafeBuffer, + asciiWrite, + latin1Write, + utf8Write, } = require('internal/buffer'); FastBuffer.prototype.constructor = Buffer; @@ -633,8 +647,8 @@ const encodingOps = { encoding: 'utf8', encodingVal: encodingsMap.utf8, byteLength: byteLengthUtf8, - write: (buf, string, offset, len) => buf.utf8Write(string, offset, len), - slice: (buf, start, end) => buf.utf8Slice(start, end), + write: utf8Write, + slice: utf8Slice, indexOf: (buf, val, byteOffset, dir) => indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir), }, @@ -642,8 +656,8 @@ const encodingOps = { encoding: 'ucs2', encodingVal: encodingsMap.utf16le, byteLength: (string) => string.length * 2, - write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), - slice: (buf, start, end) => buf.ucs2Slice(start, end), + write: ucs2Write, + slice: ucs2Slice, indexOf: (buf, val, byteOffset, dir) => indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), }, @@ -651,8 +665,8 @@ const encodingOps = { encoding: 'utf16le', encodingVal: encodingsMap.utf16le, byteLength: (string) => string.length * 2, - write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len), - slice: (buf, start, end) => buf.ucs2Slice(start, end), + write: ucs2Write, + slice: ucs2Slice, indexOf: (buf, val, byteOffset, dir) => indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir), }, @@ -660,8 +674,8 @@ const encodingOps = { encoding: 'latin1', encodingVal: encodingsMap.latin1, byteLength: (string) => string.length, - write: (buf, string, offset, len) => buf.latin1Write(string, offset, len), - slice: (buf, start, end) => buf.latin1Slice(start, end), + write: latin1Write, + slice: latin1Slice, indexOf: (buf, val, byteOffset, dir) => indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir), }, @@ -669,8 +683,8 @@ const encodingOps = { encoding: 'ascii', encodingVal: encodingsMap.ascii, byteLength: (string) => string.length, - write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len), - slice: (buf, start, end) => buf.asciiSlice(start, end), + write: asciiWrite, + slice: asciiSlice, indexOf: (buf, val, byteOffset, dir) => indexOfBuffer(buf, fromStringFast(val, encodingOps.ascii), @@ -682,8 +696,8 @@ const encodingOps = { encoding: 'base64', encodingVal: encodingsMap.base64, byteLength: (string) => base64ByteLength(string, string.length), - write: (buf, string, offset, len) => buf.base64Write(string, offset, len), - slice: (buf, start, end) => buf.base64Slice(start, end), + write: base64Write, + slice: base64Slice, indexOf: (buf, val, byteOffset, dir) => indexOfBuffer(buf, fromStringFast(val, encodingOps.base64), @@ -695,9 +709,8 @@ const encodingOps = { encoding: 'base64url', encodingVal: encodingsMap.base64url, byteLength: (string) => base64ByteLength(string, string.length), - write: (buf, string, offset, len) => - buf.base64urlWrite(string, offset, len), - slice: (buf, start, end) => buf.base64urlSlice(start, end), + write: base64urlWrite, + slice: base64urlSlice, indexOf: (buf, val, byteOffset, dir) => indexOfBuffer(buf, fromStringFast(val, encodingOps.base64url), @@ -709,8 +722,8 @@ const encodingOps = { encoding: 'hex', encodingVal: encodingsMap.hex, byteLength: (string) => string.length >>> 1, - write: (buf, string, offset, len) => buf.hexWrite(string, offset, len), - slice: (buf, start, end) => buf.hexSlice(start, end), + write: hexWrite, + slice: hexSlice, indexOf: (buf, val, byteOffset, dir) => indexOfBuffer(buf, fromStringFast(val, encodingOps.hex), @@ -835,7 +848,7 @@ Buffer.prototype.copy = // to their upper/lower bounds if the value passed is out of range. Buffer.prototype.toString = function toString(encoding, start, end) { if (arguments.length === 0) { - return this.utf8Slice(0, this.length); + return utf8Slice(this, 0, this.length); } const len = this.length; @@ -856,7 +869,7 @@ Buffer.prototype.toString = function toString(encoding, start, end) { return ''; if (encoding === undefined) - return this.utf8Slice(start, end); + return utf8Slice(this, start, end); const ops = getEncodingOps(encoding); if (ops === undefined) @@ -887,7 +900,7 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) { const actualMax = MathMin(max, this.length); const remaining = this.length - max; let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace( - /(.{2})/g, this.hexSlice(0, actualMax), '$1 ')); + /(.{2})/g, hexSlice(this, 0, actualMax), '$1 ')); if (remaining > 0) str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`; // Inspect special properties as well, if possible. @@ -1026,7 +1039,7 @@ Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) { }; Buffer.prototype.includes = function includes(val, byteOffset, encoding) { - return this.indexOf(val, byteOffset, encoding) !== -1; + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) !== -1; }; // Usage: @@ -1111,7 +1124,7 @@ function _fill(buf, value, offset, end, encoding) { Buffer.prototype.write = function write(string, offset, length, encoding) { // Buffer#write(string); if (offset === undefined) { - return this.utf8Write(string, 0, this.length); + return utf8Write(this, string, 0, this.length); } // Buffer#write(string, encoding) if (length === undefined && typeof offset === 'string') { @@ -1138,9 +1151,9 @@ Buffer.prototype.write = function write(string, offset, length, encoding) { } if (!encoding || encoding === 'utf8') - return this.utf8Write(string, offset, length); + return utf8Write(this, string, offset, length); if (encoding === 'ascii') - return this.asciiWrite(string, offset, length); + return asciiWrite(this, string, offset, length); const ops = getEncodingOps(encoding); if (ops === undefined) diff --git a/lib/internal/buffer.js b/lib/internal/buffer.js index 9707af66dff860..969765325ef8b5 100644 --- a/lib/internal/buffer.js +++ b/lib/internal/buffer.js @@ -184,11 +184,11 @@ function readUIntLE(offset, byteLength) { if (byteLength === 3) return readUInt24LE(this, offset); if (byteLength === 4) - return this.readUInt32LE(offset); + return readUInt32LE(this, offset); if (byteLength === 2) - return this.readUInt16LE(offset); + return readUInt16LE(this, offset); if (byteLength === 1) - return this.readUInt8(offset); + return readUInt8(this, offset); boundsError(byteLength, 6, 'byteLength'); } @@ -221,16 +221,16 @@ function readUInt40LE(buf, offset = 0) { last * 2 ** 32; } -function readUInt32LE(offset = 0) { +function readUInt32LE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 3]; + const first = buf[offset]; + const last = buf[offset + 3]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 4); + boundsError(offset, buf.length - 4); return first + - this[++offset] * 2 ** 8 + - this[++offset] * 2 ** 16 + + buf[++offset] * 2 ** 8 + + buf[++offset] * 2 ** 16 + last * 2 ** 24; } @@ -244,21 +244,21 @@ function readUInt24LE(buf, offset = 0) { return first + buf[++offset] * 2 ** 8 + last * 2 ** 16; } -function readUInt16LE(offset = 0) { +function readUInt16LE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 1]; + const first = buf[offset]; + const last = buf[offset + 1]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 2); + boundsError(offset, buf.length - 2); return first + last * 2 ** 8; } -function readUInt8(offset = 0) { +function readUInt8(buf, offset = 0) { validateNumber(offset, 'offset'); - const val = this[offset]; + const val = buf[offset]; if (val === undefined) - boundsError(offset, this.length - 1); + boundsError(offset, buf.length - 1); return val; } @@ -273,11 +273,11 @@ function readUIntBE(offset, byteLength) { if (byteLength === 3) return readUInt24BE(this, offset); if (byteLength === 4) - return this.readUInt32BE(offset); + return readUInt32BE(this, offset); if (byteLength === 2) - return this.readUInt16BE(offset); + return readUInt16BE(this, offset); if (byteLength === 1) - return this.readUInt8(offset); + return readUInt8(this, offset); boundsError(byteLength, 6, 'byteLength'); } @@ -310,16 +310,16 @@ function readUInt40BE(buf, offset = 0) { last; } -function readUInt32BE(offset = 0) { +function readUInt32BE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 3]; + const first = buf[offset]; + const last = buf[offset + 3]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 4); + boundsError(offset, buf.length - 4); return first * 2 ** 24 + - this[++offset] * 2 ** 16 + - this[++offset] * 2 ** 8 + + buf[++offset] * 2 ** 16 + + buf[++offset] * 2 ** 8 + last; } @@ -333,12 +333,12 @@ function readUInt24BE(buf, offset = 0) { return first * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } -function readUInt16BE(offset = 0) { +function readUInt16BE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 1]; + const first = buf[offset]; + const last = buf[offset + 1]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 2); + boundsError(offset, buf.length - 2); return first * 2 ** 8 + last; } @@ -353,11 +353,11 @@ function readIntLE(offset, byteLength) { if (byteLength === 3) return readInt24LE(this, offset); if (byteLength === 4) - return this.readInt32LE(offset); + return readInt32LE(this, offset); if (byteLength === 2) - return this.readInt16LE(offset); + return readInt16LE(this, offset); if (byteLength === 1) - return this.readInt8(offset); + return readInt8(this, offset); boundsError(byteLength, 6, 'byteLength'); } @@ -391,16 +391,16 @@ function readInt40LE(buf, offset = 0) { buf[++offset] * 2 ** 24; } -function readInt32LE(offset = 0) { +function readInt32LE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 3]; + const first = buf[offset]; + const last = buf[offset + 3]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 4); + boundsError(offset, buf.length - 4); return first + - this[++offset] * 2 ** 8 + - this[++offset] * 2 ** 16 + + buf[++offset] * 2 ** 8 + + buf[++offset] * 2 ** 16 + (last << 24); // Overflow } @@ -415,22 +415,22 @@ function readInt24LE(buf, offset = 0) { return val | (val & 2 ** 23) * 0x1fe; } -function readInt16LE(offset = 0) { +function readInt16LE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 1]; + const first = buf[offset]; + const last = buf[offset + 1]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 2); + boundsError(offset, buf.length - 2); const val = first + last * 2 ** 8; return val | (val & 2 ** 15) * 0x1fffe; } -function readInt8(offset = 0) { +function readInt8(buf, offset = 0) { validateNumber(offset, 'offset'); - const val = this[offset]; + const val = buf[offset]; if (val === undefined) - boundsError(offset, this.length - 1); + boundsError(offset, buf.length - 1); return val | (val & 2 ** 7) * 0x1fffffe; } @@ -445,11 +445,11 @@ function readIntBE(offset, byteLength) { if (byteLength === 3) return readInt24BE(this, offset); if (byteLength === 4) - return this.readInt32BE(offset); + return readInt32BE(this, offset); if (byteLength === 2) - return this.readInt16BE(offset); + return readInt16BE(this, offset); if (byteLength === 1) - return this.readInt8(offset); + return readInt8(this, offset); boundsError(byteLength, 6, 'byteLength'); } @@ -483,16 +483,16 @@ function readInt40BE(buf, offset = 0) { last; } -function readInt32BE(offset = 0) { +function readInt32BE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 3]; + const first = buf[offset]; + const last = buf[offset + 3]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 4); + boundsError(offset, buf.length - 4); return (first << 24) + // Overflow - this[++offset] * 2 ** 16 + - this[++offset] * 2 ** 8 + + buf[++offset] * 2 ** 16 + + buf[++offset] * 2 ** 8 + last; } @@ -507,12 +507,12 @@ function readInt24BE(buf, offset = 0) { return val | (val & 2 ** 23) * 0x1fe; } -function readInt16BE(offset = 0) { +function readInt16BE(buf, offset = 0) { validateNumber(offset, 'offset'); - const first = this[offset]; - const last = this[offset + 1]; + const first = buf[offset]; + const last = buf[offset + 1]; if (first === undefined || last === undefined) - boundsError(offset, this.length - 2); + boundsError(offset, buf.length - 2); const val = first * 2 ** 8 + last; return val | (val & 2 ** 15) * 0x1fffe; @@ -969,6 +969,36 @@ class FastBuffer extends Uint8Array { } } +function asciiWrite(buf, string, offset = 0, length = buf.byteLength - offset) { + if (offset < 0 || offset > buf.byteLength) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + } + if (length < 0 || length > buf.byteLength - offset) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } + return asciiWriteStatic(buf, string, offset, length); +} + +function latin1Write(buf, string, offset = 0, length = buf.byteLength - offset) { + if (offset < 0 || offset > buf.byteLength) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + } + if (length < 0 || length > buf.byteLength - offset) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } + return latin1WriteStatic(buf, string, offset, length); +} + +function utf8Write(buf, string, offset = 0, length = buf.byteLength - offset) { + if (offset < 0 || offset > buf.byteLength) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); + } + if (length < 0 || length > buf.byteLength - offset) { + throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); + } + return utf8WriteStatic(buf, string, offset, length); +} + function addBufferPrototypeMethods(proto) { proto.readBigUInt64LE = readBigUInt64LE; proto.readBigUInt64BE = readBigUInt64BE; @@ -984,26 +1014,26 @@ function addBufferPrototypeMethods(proto) { proto.writeBigInt64BE = writeBigInt64BE; proto.readUIntLE = readUIntLE; - proto.readUInt32LE = readUInt32LE; - proto.readUInt16LE = readUInt16LE; - proto.readUInt8 = readUInt8; + proto.readUInt32LE = function(offset) { return readUInt32LE(this, offset); }; + proto.readUInt16LE = function(offset) { return readUInt16LE(this, offset); }; + proto.readUInt8 = function(offset) { return readUInt8(this, offset); }; proto.readUIntBE = readUIntBE; - proto.readUInt32BE = readUInt32BE; - proto.readUInt16BE = readUInt16BE; + proto.readUInt32BE = function(offset) { return readUInt32BE(this, offset); }; + proto.readUInt16BE = function(offset) { return readUInt16BE(this, offset); }; proto.readUintLE = readUIntLE; - proto.readUint32LE = readUInt32LE; - proto.readUint16LE = readUInt16LE; - proto.readUint8 = readUInt8; + proto.readUint32LE = proto.readUInt32LE; + proto.readUint16LE = proto.readUInt16LE; + proto.readUint8 = proto.readUInt8; proto.readUintBE = readUIntBE; - proto.readUint32BE = readUInt32BE; - proto.readUint16BE = readUInt16BE; + proto.readUint32BE = proto.readUInt32BE; + proto.readUint16BE = proto.readUInt16BE; proto.readIntLE = readIntLE; - proto.readInt32LE = readInt32LE; - proto.readInt16LE = readInt16LE; - proto.readInt8 = readInt8; + proto.readInt32LE = function(offset) { return readInt32LE(this, offset); }; + proto.readInt16LE = function(offset) { return readInt16LE(this, offset); }; + proto.readInt8 = function(offset) { return readInt8(this, offset); }; proto.readIntBE = readIntBE; - proto.readInt32BE = readInt32BE; - proto.readInt16BE = readInt16BE; + proto.readInt32BE = function(offset) { return readInt32BE(this, offset); }; + proto.readInt16BE = function(offset) { return readInt16BE(this, offset); }; proto.writeUIntLE = writeUIntLE; proto.writeUInt32LE = writeUInt32LE; @@ -1036,44 +1066,20 @@ function addBufferPrototypeMethods(proto) { proto.writeDoubleLE = bigEndian ? writeDoubleBackwards : writeDoubleForwards; proto.writeDoubleBE = bigEndian ? writeDoubleForwards : writeDoubleBackwards; - proto.asciiSlice = asciiSlice; - proto.base64Slice = base64Slice; - proto.base64urlSlice = base64urlSlice; - proto.latin1Slice = latin1Slice; - proto.hexSlice = hexSlice; - proto.ucs2Slice = ucs2Slice; - proto.utf8Slice = utf8Slice; - proto.asciiWrite = function(string, offset = 0, length = this.byteLength - offset) { - if (offset < 0 || offset > this.byteLength) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); - } - if (length < 0 || length > this.byteLength - offset) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); - } - return asciiWriteStatic(this, string, offset, length); - }; - proto.base64Write = base64Write; - proto.base64urlWrite = base64urlWrite; - proto.latin1Write = function(string, offset = 0, length = this.byteLength - offset) { - if (offset < 0 || offset > this.byteLength) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); - } - if (length < 0 || length > this.byteLength - offset) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); - } - return latin1WriteStatic(this, string, offset, length); - }; - proto.hexWrite = hexWrite; - proto.ucs2Write = ucs2Write; - proto.utf8Write = function(string, offset = 0, length = this.byteLength - offset) { - if (offset < 0 || offset > this.byteLength) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('offset'); - } - if (length < 0 || length > this.byteLength - offset) { - throw new ERR_BUFFER_OUT_OF_BOUNDS('length'); - } - return utf8WriteStatic(this, string, offset, length); - }; + proto.asciiSlice = function(start, end) { return asciiSlice(this, start, end); }; + proto.base64Slice = function(start, end) { return base64Slice(this, start, end); }; + proto.base64urlSlice = function(start, end) { return base64urlSlice(this, start, end); }; + proto.latin1Slice = function(start, end) { return latin1Slice(this, start, end); }; + proto.hexSlice = function(start, end) { return hexSlice(this, start, end); }; + proto.ucs2Slice = function(start, end) { return ucs2Slice(this, start, end); }; + proto.utf8Slice = function(start, end) { return utf8Slice(this, start, end); }; + proto.asciiWrite = function(string, offset, length) { return asciiWrite(this, string, offset, length); }; + proto.base64Write = function(string, offset, length) { return base64Write(this, string, offset, length); }; + proto.base64urlWrite = function(string, offset, length) { return base64urlWrite(this, string, offset, length); }; + proto.latin1Write = function(string, offset, length) { return latin1Write(this, string, offset, length); }; + proto.hexWrite = function(string, offset, length) { return hexWrite(this, string, offset, length); }; + proto.ucs2Write = function(string, offset, length) { return ucs2Write(this, string, offset, length); }; + proto.utf8Write = function(string, offset, length) { return utf8Write(this, string, offset, length); }; } // This would better be placed in internal/worker/io.js, but that doesn't work @@ -1125,4 +1131,7 @@ module.exports = { createUnsafeBuffer, readUInt16BE, readUInt32BE, + asciiWrite, + latin1Write, + utf8Write, }; diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 8f14780739d72c..fa40eabb4722b3 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -3449,9 +3449,9 @@ function getUnpackedSettings(buf, options = kEmptyObject) { const settings = {}; let offset = 0; while (offset < buf.length) { - const id = ReflectApply(readUInt16BE, buf, [offset]); + const id = readUInt16BE(buf, offset); offset += 2; - const value = ReflectApply(readUInt32BE, buf, [offset]); + const value = readUInt32BE(buf, offset); switch (id) { case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: settings.headerTableSize = value; diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 3507f5e3e2943a..2c59a668664313 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -528,16 +528,16 @@ void StringSlice(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); Isolate* isolate = env->isolate(); - THROW_AND_RETURN_UNLESS_BUFFER(env, args.This()); - ArrayBufferViewContents buffer(args.This()); + THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); + ArrayBufferViewContents buffer(args[0]); if (buffer.length() == 0) return args.GetReturnValue().SetEmptyString(); size_t start = 0; size_t end = 0; - THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[0], 0, &start)); - THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], buffer.length(), &end)); + THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], 0, &start)); + THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], buffer.length(), &end)); if (end < start) end = start; THROW_AND_RETURN_IF_OOB(Just(end <= buffer.length())); size_t length = end - start; @@ -688,27 +688,27 @@ template void StringWrite(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - THROW_AND_RETURN_UNLESS_BUFFER(env, args.This()); - SPREAD_BUFFER_ARG(args.This(), ts_obj); + THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]); + SPREAD_BUFFER_ARG(args[0], ts_obj); - THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "argument"); + THROW_AND_RETURN_IF_NOT_STRING(env, args[1], "argument"); Local str; - if (!args[0]->ToString(env->context()).ToLocal(&str)) { + if (!args[1]->ToString(env->context()).ToLocal(&str)) { return; } size_t offset = 0; size_t max_length = 0; - THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], 0, &offset)); + THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], 0, &offset)); if (offset > ts_obj_length) { return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS( env, "\"offset\" is outside of buffer bounds"); } - THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], ts_obj_length - offset, - &max_length)); + THROW_AND_RETURN_IF_OOB( + ParseArrayIndex(env, args[3], ts_obj_length - offset, &max_length)); max_length = std::min(ts_obj_length - offset, max_length); diff --git a/test/fixtures/permission/fs-traversal.js b/test/fixtures/permission/fs-traversal.js index 764ae6692522da..d92d3286f75e96 100644 --- a/test/fixtures/permission/fs-traversal.js +++ b/test/fixtures/permission/fs-traversal.js @@ -98,11 +98,6 @@ const uint8ArrayTraversalPath = new TextEncoder().encode(traversalPath); return w.apply(this, [traversalPath, ...args]); })(Buffer.prototype.utf8Write); - // Sanity check (remove if the internals of Buffer.from change): - // The custom implementation of utf8Write should cause Buffer.from() to encode - // traversalPath instead of the sanitized output of resolve(). - assert.strictEqual(Buffer.from(resolve(traversalPathWithExtraChars)).toString(), traversalPath); - assert.throws(() => { fs.readFileSync(traversalPathWithExtraBytes); }, common.expectsError({ @@ -125,4 +120,4 @@ const uint8ArrayTraversalPath = new TextEncoder().encode(traversalPath); assert.ok(!process.permission.has('fs.write', traversalPath)); assert.ok(!process.permission.has('fs.read', traversalFolderPath)); assert.ok(!process.permission.has('fs.write', traversalFolderPath)); -} \ No newline at end of file +} diff --git a/test/parallel/test-buffer-generic-methods.js b/test/parallel/test-buffer-generic-methods.js new file mode 100644 index 00000000000000..7efba7a1f7597b --- /dev/null +++ b/test/parallel/test-buffer-generic-methods.js @@ -0,0 +1,1119 @@ +'use strict'; +require('../common'); +const assert = require('assert'); + +function arrayOfNumbers(length) { + return Array.from({ length }, (_, i) => i); +} + +const customInspectSymbol = Symbol.for('nodejs.util.inspect.custom'); + +// Methods that are either internal or do not make sense to be generic. +const ignoredMethods = [ + 'constructor', + 'asciiSlice', + 'base64Slice', + 'base64urlSlice', + 'latin1Slice', + 'hexSlice', + 'ucs2Slice', + 'utf8Slice', + 'asciiWrite', + 'base64Write', + 'base64urlWrite', + 'latin1Write', + 'hexWrite', + 'ucs2Write', + 'utf8Write', + 'inspect', +]; + +// Tested methods +const testedMethods = [ + 'compare', + 'copy', + 'equals', + 'fill', + 'includes', + 'indexOf', + 'lastIndexOf', + 'readBigInt64BE', + 'readBigInt64LE', + 'readBigUInt64BE', + 'readBigUInt64LE', + 'readDoubleBE', + 'readDoubleLE', + 'readFloatBE', + 'readFloatLE', + 'readInt8', + 'readInt16BE', + 'readInt16LE', + 'readInt32BE', + 'readInt32LE', + 'readIntBE', + 'readIntLE', + 'readUInt8', + 'readUInt16BE', + 'readUInt16LE', + 'readUInt32BE', + 'readUInt32LE', + 'readUIntBE', + 'readUIntLE', + 'subarray', + 'slice', + 'swap16', + 'swap32', + 'swap64', + 'toJSON', + 'toString', + 'toLocaleString', + 'write', + 'writeBigInt64BE', + 'writeBigInt64LE', + 'writeBigUInt64BE', + 'writeBigUInt64LE', + 'writeDoubleBE', + 'writeDoubleLE', + 'writeFloatBE', + 'writeFloatLE', + 'writeInt8', + 'writeInt16BE', + 'writeInt16LE', + 'writeInt32BE', + 'writeInt32LE', + 'writeIntBE', + 'writeIntLE', + 'writeUInt8', + 'writeUInt16BE', + 'writeUInt16LE', + 'writeUInt32BE', + 'writeUInt32LE', + 'writeUIntBE', + 'writeUIntLE', + customInspectSymbol, +]; + +const expectedMethods = [ + ...ignoredMethods, + ...testedMethods, +]; + +const isMethod = (method) => typeof Buffer.prototype[method] === 'function'; +const addUnique = (names, newName) => { + const nameMatches = (name) => name.toLowerCase() === newName.toLowerCase(); + if (!names.some(nameMatches)) names.push(newName); + return names; +}; +const actualMethods = [ + // The readXInt methods are provided as both upper & lower case names; reducing to only consider each once. + ...Object.getOwnPropertyNames(Buffer.prototype).filter(isMethod).reduce(addUnique, []), + ...Object.getOwnPropertySymbols(Buffer.prototype).filter(isMethod), +]; + +// These methods are not accounted for in the generic tests. +assert.deepStrictEqual(actualMethods.filter((v) => !expectedMethods.includes(v)), []); +// These methods have been removed, please update the table in this file. +assert.deepStrictEqual(expectedMethods.filter((v) => !actualMethods.includes(v)), []); + +const { + compare, + copy, + equals, + fill, + includes, + indexOf, + lastIndexOf, + readBigInt64BE, + readBigInt64LE, + readBigUInt64BE, + readBigUInt64LE, + readDoubleBE, + readDoubleLE, + readFloatBE, + readFloatLE, + readInt8, + readInt16BE, + readInt16LE, + readInt32BE, + readInt32LE, + readIntBE, + readIntLE, + readUInt8, + readUInt16BE, + readUInt16LE, + readUInt32BE, + readUInt32LE, + readUIntBE, + readUIntLE, + subarray, + slice, + swap16, + swap32, + swap64, + toJSON, + toString, + write, + writeBigInt64BE, + writeBigInt64LE, + writeBigUInt64BE, + writeBigUInt64LE, + writeDoubleBE, + writeDoubleLE, + writeFloatBE, + writeFloatLE, + writeInt8, + writeInt16BE, + writeInt16LE, + writeInt32BE, + writeInt32LE, + writeIntBE, + writeIntLE, + writeUInt8, + writeUInt16BE, + writeUInt16LE, + writeUInt32BE, + writeUInt32LE, + writeUIntBE, + writeUIntLE, + [customInspectSymbol]: customInspect, +} = Buffer.prototype; + +/** + * Assert the Uint8Array is not converted to a Buffer + * in the process of calling a Buffer method on it. + */ +function assertContentEqual(actualUint8Array, expectedBuffer) { + assert.ok(!Buffer.isBuffer(actualUint8Array)); + assert.ok(Buffer.isBuffer(expectedBuffer)); + assert.strictEqual(actualUint8Array.length, expectedBuffer.length); + for (let i = 0; i < actualUint8Array.length; i++) { + assert.strictEqual(actualUint8Array[i], expectedBuffer[i], `Uint8Array and Buffer differ at ${i}`); + } +} + +// Buffer Methods: + +{ + // buf.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]]) + + const buf = Uint8Array.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + const target = Uint8Array.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + + assert.strictEqual(compare.call(buf, target, 0, 4, 0, 4), 0); + assert.strictEqual(compare.call(buf, target, 0, 4, 1, 5), 1); + assert.strictEqual(compare.call(buf, target, 1, 5, 0, 4), -1); +} + +{ + // buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]]) + + const sourceUint8Array = Uint8Array.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + + const destination = new Uint8Array(4); + + copy.call(sourceUint8Array, destination, 1, 7, 10); + assertContentEqual(destination, Buffer.of(0, 7, 8, 9)); +} + +{ + // buf.equals(otherBufferLike) + + const emptyUint8Array = new Uint8Array(0); + const emptyBuffer = Buffer.alloc(0); + + assert.ok(equals.call(emptyUint8Array, emptyBuffer)); + assert.ok(equals.call(emptyUint8Array, emptyUint8Array)); + assert.ok(equals.call(emptyUint8Array, new Uint8Array(0))); + + const largeUint8Array = new Uint8Array(arrayOfNumbers(9000)); + const largeBuffer = Buffer.from(arrayOfNumbers(9000)); + + assert.ok(equals.call(largeUint8Array, largeBuffer)); + assert.ok(equals.call(largeUint8Array, largeUint8Array)); + assert.ok(equals.call(largeUint8Array, new Uint8Array(arrayOfNumbers(9000)))); +} + +{ + // buf.fill(value[, byteOffset][, encoding]) + + const uint8array = new Uint8Array(10); + const buffer = Buffer.alloc(10); + + assertContentEqual( + fill.call(uint8array, '\u03a3', 0, 'utf16le'), + buffer.fill('\u03a3', 0, 'utf16le') + ); +} + +{ + // buf.includes(value[, byteOffset][, encoding]) + + const uint8array = Uint8Array.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + const buffer = Buffer.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + + assert.strictEqual( + includes.call(uint8array, '\u03a3', 0, 'utf16le'), + buffer.includes('\u03a3', 0, 'utf16le') + ); +} + + +{ + // buf.indexOf(value[, byteOffset][, encoding]) + + const uint8array = Uint8Array.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + const buffer = Buffer.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + + assert.strictEqual( + indexOf.call(uint8array, '\u03a3', 0, 'utf16le'), + buffer.indexOf('\u03a3', 0, 'utf16le') + ); +} + +{ + // buf.lastIndexOf(value[, byteOffset][, encoding]) + + const uint8array = Uint8Array.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + const buffer = Buffer.of(154, 3, 145, 3, 163, 3, 163, 3, 149, 3); + + assert.strictEqual( + lastIndexOf.call(uint8array, '\u03a3', -5, 'utf16le'), + buffer.lastIndexOf('\u03a3', -5, 'utf16le') + ); +} + + +{ + // buf.readBigInt64BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readBigInt64BE.call(uint8array, 0), + buffer.readBigInt64BE(0) + ); +} + +{ + // buf.readBigInt64LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readBigInt64LE.call(uint8array, 0), + buffer.readBigInt64LE(0) + ); +} + +{ + // buf.readBigUInt64BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readBigUInt64BE.call(uint8array, 0), + buffer.readBigUInt64BE(0) + ); +} + +{ + // buf.readBigUInt64LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readBigUInt64LE.call(uint8array, 0), + buffer.readBigUInt64LE(0) + ); +} + +{ + // buf.readDoubleBE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readDoubleBE.call(uint8array, 0), + buffer.readDoubleBE(0) + ); +} + +{ + // buf.readDoubleLE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0, 0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0, 0, 0, 1, 0); + + assert.strictEqual( + readDoubleLE.call(uint8array, 0), + buffer.readDoubleLE(0) + ); +} + +{ + // buf.readFloatBE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readFloatBE.call(uint8array, 0), + buffer.readFloatBE(0) + ); +} + +{ + // buf.readFloatLE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readFloatLE.call(uint8array, 0), + buffer.readFloatLE(0) + ); +} + +{ + // buf.readInt8([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readInt8.call(uint8array, 2), + buffer.readInt8(2) + ); +} + +{ + // buf.readInt16BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readInt16BE.call(uint8array, 2), + buffer.readInt16BE(2) + ); +} + +{ + // buf.readInt16LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readInt16LE.call(uint8array, 2), + buffer.readInt16LE(2) + ); +} + +{ + // buf.readInt32BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readInt32BE.call(uint8array, 0), + buffer.readInt32BE(0) + ); +} + +{ + // buf.readInt32LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readInt32LE.call(uint8array, 0), + buffer.readInt32LE(0) + ); +} + +{ + // buf.readIntBE(offset, byteLength) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readIntBE.call(uint8array, 2, 2), + buffer.readIntBE(2, 2) + ); +} + +{ + // buf.readIntLE(offset, byteLength) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readIntLE.call(uint8array, 2, 2), + buffer.readIntLE(2, 2) + ); +} + +{ + // buf.readUInt8([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUInt8.call(uint8array, 2), + buffer.readUInt8(2) + ); +} + +{ + // buf.readUInt16BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUInt16BE.call(uint8array, 2), + buffer.readUInt16BE(2) + ); +} + +{ + // buf.readUInt16LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUInt16LE.call(uint8array, 2), + buffer.readUInt16LE(2) + ); +} + +{ + // buf.readUInt32BE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUInt32BE.call(uint8array, 0), + buffer.readUInt32BE(0) + ); +} + +{ + // buf.readUInt32LE([offset]) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUInt32LE.call(uint8array, 0), + buffer.readUInt32LE(0) + ); +} + +{ + // buf.readUIntBE(offset, byteLength) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUIntBE.call(uint8array, 2, 2), + buffer.readUIntBE(2, 2) + ); +} + +{ + // buf.readUIntLE(offset, byteLength) + + const uint8array = Uint8Array.of(0, 0, 1, 0); + const buffer = Buffer.of(0, 0, 1, 0); + + assert.strictEqual( + readUIntLE.call(uint8array, 2, 2), + buffer.readUIntLE(2, 2) + ); +} + +{ + // buf.subarray() + + const uint8array = new Uint8Array(arrayOfNumbers(8)); + const buffer = Buffer.from(arrayOfNumbers(8)); + + const array = subarray.call(uint8array, 2, 5); + assert.ok(Buffer.isBuffer(array)); // Does convert the output type because it makes a new FastBuffer + assert.deepStrictEqual( + array, + buffer.subarray(2, 5) + ); +} + +{ + // buf.slice() + + const uint8array = new Uint8Array(arrayOfNumbers(8)); + const buffer = Buffer.from(arrayOfNumbers(8)); + + assertContentEqual( + slice.call(uint8array, 2, 5), // Does not convert the output type because it uses "this.subarray" internally + buffer.slice(2, 5) + ); +} + +{ + // buf.swap16() + + const smallUint8array = new Uint8Array(arrayOfNumbers(2)); + const smallBuffer = Buffer.from(arrayOfNumbers(2)); + + assertContentEqual( + swap16.call(smallUint8array), + smallBuffer.swap16() + ); + + const largeUint8array = new Uint8Array(arrayOfNumbers(2 * 500)); + const largeBuffer = Buffer.from(arrayOfNumbers(2 * 500)); + + assertContentEqual( + swap16.call(largeUint8array), + largeBuffer.swap16() + ); +} + +{ + // buf.swap32() + + const smallUint8array = new Uint8Array(arrayOfNumbers(4)); + const smallBuffer = Buffer.from(arrayOfNumbers(4)); + + assertContentEqual( + swap32.call(smallUint8array), + smallBuffer.swap32() + ); + + const largeUint8array = new Uint8Array(arrayOfNumbers(4 * 500)); + const largeBuffer = Buffer.from(arrayOfNumbers(4 * 500)); + + assertContentEqual( + swap32.call(largeUint8array), + largeBuffer.swap32() + ); +} + +{ + // buf.swap64() + + const smallUint8array = new Uint8Array(arrayOfNumbers(8)); + const smallBuffer = Buffer.from(arrayOfNumbers(8)); + + assertContentEqual( + swap64.call(smallUint8array), + smallBuffer.swap64() + ); + + const largeUint8array = new Uint8Array(arrayOfNumbers(8 * 500)); + const largeBuffer = Buffer.from(arrayOfNumbers(8 * 500)); + + assertContentEqual( + swap64.call(largeUint8array), + largeBuffer.swap64() + ); +} + +{ + // buf.toJSON() + + const uint8array = Uint8Array.of(1, 2, 3, 4); + const buffer = Buffer.of(1, 2, 3, 4); + + assert.deepStrictEqual( + toJSON.call(uint8array), + buffer.toJSON() + ); +} + +{ + // buf.toString([encoding[, start[, end]]]) + assert.strictEqual(Buffer.prototype.toLocaleString, toString); + + const uint8array = Uint8Array.of(1, 2, 3, 4); + const buffer = Buffer.of(1, 2, 3, 4); + + assert.deepStrictEqual( + toString.call(uint8array), + buffer.toString() + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'utf8'), + buffer.toString('utf8') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'utf16le'), + buffer.toString('utf16le') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'latin1'), + buffer.toString('latin1') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'base64'), + buffer.toString('base64') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'base64url'), + buffer.toString('base64url') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'hex'), + buffer.toString('hex') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'ascii'), + buffer.toString('ascii') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'binary'), + buffer.toString('binary') + ); + + assert.deepStrictEqual( + toString.call(uint8array, 'ucs2'), + buffer.toString('ucs2') + ); +} + +{ + // buf.write(string[, offset[, length]][, encoding]) + const bufferSize = 16; + // UTF-8 encoding + { + const testString = 'Hello, world!'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'utf8'); + const expectedReturnValue = buffer.write(testString, 0, 'utf8'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Hex encoding + { + const testString = 'a1b2c3d4e5'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'hex'); + const expectedReturnValue = buffer.write(testString, 0, 'hex'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Base64 encoding + { + const testString = 'SGVsbG8gd29ybGQ='; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'base64'); + const expectedReturnValue = buffer.write(testString, 0, 'base64'); + + assertContentEqual(uint8array, buffer); + assert.strictEqual(returnValue, expectedReturnValue); + } + + // Latin1 encoding + { + const testString = '¡Hola!'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'latin1'); + const expectedReturnValue = buffer.write(testString, 0, 'latin1'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Utf16le encoding + { + const testString = '\uD835\uDC9C\uD835\uDCB7\uD835\uDCB8'; // Unicode string + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'utf16le'); + const expectedReturnValue = buffer.write(testString, 0, 'utf16le'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Binary encoding + { + const testString = '\x00\x01\x02\x03'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'binary'); + const expectedReturnValue = buffer.write(testString, 0, 'binary'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Base64url encoding + { + const testString = 'SGVsbG9fV29ybGQ'; // Valid base64url string + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'base64url'); + const expectedReturnValue = buffer.write(testString, 0, 'base64url'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Ascii encoding + { + const testString = 'ASCII!'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'ascii'); + const expectedReturnValue = buffer.write(testString, 0, 'ascii'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + + // Ucs2 encoding + { + const testString = 'A\uD83D\uDC96B'; + const uint8array = new Uint8Array(bufferSize); + const buffer = Buffer.alloc(bufferSize); + + const returnValue = write.call(uint8array, testString, 0, 'ucs2'); + const expectedReturnValue = buffer.write(testString, 0, 'ucs2'); + + assert.strictEqual(returnValue, expectedReturnValue); + assertContentEqual(uint8array, buffer); + } + +} + +{ + // buf.writeBigInt64BE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeBigInt64BE.call(uint8array, 1234567890123456789n, 0); + buffer.writeBigInt64BE(1234567890123456789n, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeBigInt64LE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeBigInt64LE.call(uint8array, 1234567890123456789n, 0); + buffer.writeBigInt64LE(1234567890123456789n, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeBigUInt64BE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeBigUInt64BE.call(uint8array, 12345678901234567890n, 0); + buffer.writeBigUInt64BE(12345678901234567890n, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeBigUInt64LE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeBigUInt64LE.call(uint8array, 12345678901234567890n, 0); + buffer.writeBigUInt64LE(12345678901234567890n, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeDoubleBE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeDoubleBE.call(uint8array, 12345.6789, 0); + buffer.writeDoubleBE(12345.6789, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeDoubleLE(value[, offset]) + + const uint8array = new Uint8Array(8); + const buffer = Buffer.alloc(8); + + writeDoubleLE.call(uint8array, 12345.6789, 0); + buffer.writeDoubleLE(12345.6789, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeFloatBE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeFloatBE.call(uint8array, 12345.67, 0); + buffer.writeFloatBE(12345.67, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeFloatLE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeFloatLE.call(uint8array, 12345.67, 0); + buffer.writeFloatLE(12345.67, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeInt8(value[, offset]) + + const uint8array = new Uint8Array(1); + const buffer = Buffer.alloc(1); + + writeInt8.call(uint8array, -123, 0); + buffer.writeInt8(-123, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeInt16BE(value[, offset]) + + const uint8array = new Uint8Array(2); + const buffer = Buffer.alloc(2); + + writeInt16BE.call(uint8array, -12345, 0); + buffer.writeInt16BE(-12345, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeInt16LE(value[, offset]) + + const uint8array = new Uint8Array(2); + const buffer = Buffer.alloc(2); + + writeInt16LE.call(uint8array, -12345, 0); + buffer.writeInt16LE(-12345, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeInt32BE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeInt32BE.call(uint8array, -123456789, 0); + buffer.writeInt32BE(-123456789, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeInt32LE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeInt32LE.call(uint8array, -123456789, 0); + buffer.writeInt32LE(-123456789, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeIntBE(value, offset, byteLength) + + const uint8array = new Uint8Array(3); + const buffer = Buffer.alloc(3); + + writeIntBE.call(uint8array, -1234567, 0, 3); + buffer.writeIntBE(-1234567, 0, 3); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeIntLE(value, offset, byteLength) + + const uint8array = new Uint8Array(3); + const buffer = Buffer.alloc(3); + + writeIntLE.call(uint8array, -1234567, 0, 3); + buffer.writeIntLE(-1234567, 0, 3); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUInt8(value[, offset]) + + const uint8array = new Uint8Array(1); + const buffer = Buffer.alloc(1); + + writeUInt8.call(uint8array, 255, 0); + buffer.writeUInt8(255, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUInt16BE(value[, offset]) + + const uint8array = new Uint8Array(2); + const buffer = Buffer.alloc(2); + + writeUInt16BE.call(uint8array, 65535, 0); + buffer.writeUInt16BE(65535, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUInt16LE(value[, offset]) + + const uint8array = new Uint8Array(2); + const buffer = Buffer.alloc(2); + + writeUInt16LE.call(uint8array, 65535, 0); + buffer.writeUInt16LE(65535, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUInt32BE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeUInt32BE.call(uint8array, 4294967295, 0); + buffer.writeUInt32BE(4294967295, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUInt32LE(value[, offset]) + + const uint8array = new Uint8Array(4); + const buffer = Buffer.alloc(4); + + writeUInt32LE.call(uint8array, 4294967295, 0); + buffer.writeUInt32LE(4294967295, 0); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUIntBE(value, offset, byteLength) + + const uint8array = new Uint8Array(3); + const buffer = Buffer.alloc(3); + + writeUIntBE.call(uint8array, 1234567, 0, 3); + buffer.writeUIntBE(1234567, 0, 3); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf.writeUIntLE(value, offset, byteLength) + + const uint8array = new Uint8Array(3); + const buffer = Buffer.alloc(3); + + writeUIntLE.call(uint8array, 1234567, 0, 3); + buffer.writeUIntLE(1234567, 0, 3); + + assertContentEqual(uint8array, buffer); +} + +{ + // buf[Symbol.for('nodejs.util.inspect.custom')]() + assert.strictEqual(Buffer.prototype.inspect, customInspect); // Ensure these methods are exactly the same. + + const emptyUint8Array = new Uint8Array(0); + const emptyBuffer = Buffer.alloc(0); + + assert.strictEqual( + customInspect.call(emptyUint8Array), + emptyBuffer[customInspectSymbol]().replace('Buffer', 'Uint8Array') + ); + + const smallUint8Array = Uint8Array.of(1, 2, 3, 4, 5, 6, 7, 8); + const smallBuffer = Buffer.of(1, 2, 3, 4, 5, 6, 7, 8); + + assert.strictEqual( + customInspect.call(smallUint8Array), + smallBuffer[customInspectSymbol]().replace('Buffer', 'Uint8Array') + ); + + const largeUint8Array = new Uint8Array(arrayOfNumbers(9000)); + const largeBuffer = Buffer.from(arrayOfNumbers(9000)); + + assert.strictEqual( + customInspect.call(largeUint8Array), + largeBuffer[customInspectSymbol]().replace('Buffer', 'Uint8Array') + ); +}