From 356a0f684bc98cbce3051e4a18d8acdd428661c9 Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Sat, 16 Jul 2022 00:32:30 +0800 Subject: [PATCH 1/3] buffer: add from(ArrayBufferView) support --- doc/api/buffer.md | 12 ++++-- lib/buffer.js | 12 +++++- test/parallel/test-buffer-alloc.js | 66 ++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 13 deletions(-) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 5757e93e314c78..7cbcc34ff47b08 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -1207,10 +1207,14 @@ console.log(buf); -* `buffer` {Buffer|Uint8Array} An existing `Buffer` or [`Uint8Array`][] from - which to copy data. +* `buffer` {Buffer|ArrayBufferView} An existing `Buffer`, [`TypedArray`][], + or [`DataView`][] from which to copy data. Copies the passed `buffer` data onto a new `Buffer` instance. @@ -1242,8 +1246,8 @@ console.log(buf2.toString()); // Prints: buffer ``` -A `TypeError` will be thrown if `buffer` is not a `Buffer` or another type -appropriate for `Buffer.from()` variants. +A `TypeError` will be thrown if `buffer` is not an `ArrayBufferView` +or another type appropriate for `Buffer.from()` variants. ### Static method: `Buffer.from(object[, offsetOrEncoding[, length]])` diff --git a/lib/buffer.js b/lib/buffer.js index d5fde6debc2f74..d61c4f967f02aa 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -83,7 +83,8 @@ const { const { isAnyArrayBuffer, isArrayBufferView, - isUint8Array + isTypedArray, + isUint8Array, } = require('internal/util/types'); const { inspect: utilInspect @@ -306,6 +307,15 @@ Buffer.from = function from(value, encodingOrOffset, length) { if (isAnyArrayBuffer(value)) return fromArrayBuffer(value, encodingOrOffset, length); + if (isArrayBufferView(value) && !isUint8Array(value)) { + if (!isTypedArray(value)) { + // DataView is not a TypedArray + return fromArrayBuffer(value.buffer.slice(value.byteOffset, + value.byteOffset + value.byteLength)); + } + return fromArrayBuffer(value.slice().buffer); + } + const valueOf = value.valueOf && value.valueOf(); if (valueOf != null && valueOf !== value && diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index d2085d11802aee..ffe7bbf48427d0 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -59,22 +59,72 @@ assert.strictEqual(d.length, 0); } // Test creating a Buffer from a Uint32Array -// Note: it is implicitly interpreted as Array of integers modulo 256 { const ui32 = new Uint32Array(4).fill(42); const e = Buffer.from(ui32); - for (const [index, value] of e.entries()) { - assert.strictEqual(value, ui32[index]); - } + assert.deepStrictEqual(e, Buffer.from([ + 42, 0, 0, 0, + 42, 0, 0, 0, + 42, 0, 0, 0, + 42, 0, 0, 0, + ])); } // Test creating a Buffer from a Uint32Array (old constructor) -// Note: it is implicitly interpreted as Array of integers modulo 256 { const ui32 = new Uint32Array(4).fill(42); const e = Buffer(ui32); - for (const [key, value] of e.entries()) { - assert.strictEqual(value, ui32[key]); - } + assert.deepStrictEqual(e, Buffer.from([ + 42, 0, 0, 0, + 42, 0, 0, 0, + 42, 0, 0, 0, + 42, 0, 0, 0, + ])); +} + +// Test creating a Buffer from a BigUint64Array +{ + const bui64 = new BigUint64Array(4).fill(42n); + const e = Buffer.from(bui64); + assert.deepStrictEqual(e, Buffer.from([ + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + ])); +} +// Test creating a Buffer from a BigUint64Array (old constructor) +{ + const bui64 = new BigUint64Array(4).fill(42n); + const e = Buffer(bui64); + assert.deepStrictEqual(e, Buffer.from([ + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + 42, 0, 0, 0, 0, 0, 0, 0, + ])); +} + +// Test creating a Buffer from a Float64Array +{ + const f64 = new Float64Array(4).fill(42); + const e = Buffer.from(f64); + assert.deepStrictEqual(e, Buffer.from([ + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + ])); +} +// Test creating a Buffer from a Float64Array (old constructor) +{ + const f64 = new Float64Array(4).fill(42); + const e = Buffer(f64); + assert.deepStrictEqual(e, Buffer.from([ + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + 0, 0, 0, 0, 0, 0, 69, 64, + ])); } // Test invalid encoding for Buffer.toString From 4ac40d60442f171b8110c7653f0bcca13f7b69b1 Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Sun, 17 Jul 2022 17:11:24 +0800 Subject: [PATCH 2/3] squash: test when endianness is big --- test/parallel/test-buffer-alloc.js | 45 ++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index ffe7bbf48427d0..747a312988eede 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -3,9 +3,12 @@ const common = require('../common'); const assert = require('assert'); const vm = require('vm'); +const os = require('os'); const SlowBuffer = require('buffer').SlowBuffer; +const isBigEnd = os.endianness() === 'BE'; + // Verify the maximum Uint8Array size. There is no concrete limit by spec. The // internal limits should be updated if this fails. assert.throws( @@ -62,7 +65,12 @@ assert.strictEqual(d.length, 0); { const ui32 = new Uint32Array(4).fill(42); const e = Buffer.from(ui32); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 0, 0, 0, 42, + 0, 0, 0, 42, + 0, 0, 0, 42, + 0, 0, 0, 42, + ] : [ 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, @@ -73,7 +81,12 @@ assert.strictEqual(d.length, 0); { const ui32 = new Uint32Array(4).fill(42); const e = Buffer(ui32); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 0, 0, 0, 42, + 0, 0, 0, 42, + 0, 0, 0, 42, + 0, 0, 0, 42, + ] : [ 42, 0, 0, 0, 42, 0, 0, 0, 42, 0, 0, 0, @@ -85,7 +98,12 @@ assert.strictEqual(d.length, 0); { const bui64 = new BigUint64Array(4).fill(42n); const e = Buffer.from(bui64); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + ] : [ 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, @@ -96,7 +114,12 @@ assert.strictEqual(d.length, 0); { const bui64 = new BigUint64Array(4).fill(42n); const e = Buffer(bui64); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + 0, 0, 0, 0, 0, 0, 0, 42, + ] : [ 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, @@ -108,7 +131,12 @@ assert.strictEqual(d.length, 0); { const f64 = new Float64Array(4).fill(42); const e = Buffer.from(f64); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + ] : [ 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64, @@ -119,7 +147,12 @@ assert.strictEqual(d.length, 0); { const f64 = new Float64Array(4).fill(42); const e = Buffer(f64); - assert.deepStrictEqual(e, Buffer.from([ + assert.deepStrictEqual(e, Buffer.from(isBigEnd ? [ + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + 64, 69, 0, 0, 0, 0, 0, 0, + ] : [ 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64, 0, 0, 0, 0, 0, 0, 69, 64, From ed85f0a35e539fe96af6c78f7e8f4a872c0a94f3 Mon Sep 17 00:00:00 2001 From: LiviaMedeiros Date: Mon, 18 Jul 2022 21:03:57 +0800 Subject: [PATCH 3/3] squash: add test --- .../test-buffer-from-arraybufferview.js | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 test/parallel/test-buffer-from-arraybufferview.js diff --git a/test/parallel/test-buffer-from-arraybufferview.js b/test/parallel/test-buffer-from-arraybufferview.js new file mode 100644 index 00000000000000..303c9ddcfc892a --- /dev/null +++ b/test/parallel/test-buffer-from-arraybufferview.js @@ -0,0 +1,72 @@ +'use strict'; +const common = require('../common'); + +// Test Buffer.from(ArrayBufferView) + +const assert = require('assert'); + +// The buffer contains numbers from 27 * 0 to 27 * 127, modulo 256 +const full = Uint8Array.from({ length: 128 }, (_, i) => 27 * i); + +{ + const expected = Buffer.from(full.buffer); + + assert.deepStrictEqual( + Buffer.from(Buffer.from(full.buffer)), + expected); + + for (const abv of common.getArrayBufferViews(full)) { + assert.deepStrictEqual( + Buffer.from(abv), + expected); + } +} + +{ + const expected = Buffer.from(full.buffer.slice(48, 96)); + + assert.deepStrictEqual( + Buffer.from(Buffer.from(full.buffer, 48, 48)), + expected); + + assert.deepStrictEqual( + Buffer.from(new Int8Array(full.buffer, 48, 48)), + expected); + assert.deepStrictEqual( + Buffer.from(new Uint8Array(full.buffer, 48, 48)), + expected); + assert.deepStrictEqual( + Buffer.from(new Uint8ClampedArray(full.buffer, 48, 48)), + expected); + + assert.deepStrictEqual( + Buffer.from(new Int16Array(full.buffer, 48, 24)), + expected); + assert.deepStrictEqual( + Buffer.from(new Uint16Array(full.buffer, 48, 24)), + expected); + + assert.deepStrictEqual( + Buffer.from(new Int32Array(full.buffer, 48, 12)), + expected); + assert.deepStrictEqual( + Buffer.from(new Uint32Array(full.buffer, 48, 12)), + expected); + assert.deepStrictEqual( + Buffer.from(new Float32Array(full.buffer, 48, 12)), + expected); + + assert.deepStrictEqual( + Buffer.from(new Float64Array(full.buffer, 48, 6)), + expected); + assert.deepStrictEqual( + Buffer.from(new BigInt64Array(full.buffer, 48, 6)), + expected); + assert.deepStrictEqual( + Buffer.from(new BigUint64Array(full.buffer, 48, 6)), + expected); + + assert.deepStrictEqual( + Buffer.from(new DataView(full.buffer, 48, 48)), + expected); +}