Skip to content

Commit

Permalink
Implement Buffer.copyBytesFrom
Browse files Browse the repository at this point in the history
  • Loading branch information
chjj committed Feb 3, 2024
1 parent 54885d4 commit 61e39c4
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 3 deletions.
46 changes: 44 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,41 @@ Buffer.allocUnsafeSlow = function (size) {
return allocUnsafe(size)
}

/**
* Copies the underlying memory of `view` into a new `Buffer`.
*/
Buffer.copyBytesFrom = function copyBytesFrom (view, offset, length) {
if (!ArrayBuffer.isView(view) || !view.subarray) {
throw new errors.ERR_INVALID_ARG_TYPE('view', 'TypedArray', view)
}

if (view.length === 0) return createBuffer(0)

if (offset !== undefined || length !== undefined) {
if (offset !== undefined) {
validateInteger(offset, 'offset')
if (offset >= view.length) return createBuffer(0)
} else {
offset = 0
}

let end

if (length !== undefined) {
validateInteger(length, 'length')
end = offset + length
} else {
end = view.length
}

view = view.subarray(offset, end)
}

view = new Uint8Array(view.buffer, view.byteOffset, view.byteLength)

return fromArrayView(view)
}

function fromString (string, encoding) {
if (typeof encoding !== 'string' || encoding === '') {
encoding = 'utf8'
Expand Down Expand Up @@ -1878,8 +1913,8 @@ E('ERR_BUFFER_OUT_OF_BOUNDS',
return 'Attempt to access memory outside buffer bounds'
}, RangeError)
E('ERR_INVALID_ARG_TYPE',
function (name, actual) {
return `The "${name}" argument must be of type number. Received type ${typeof actual}`
function (name, type, actual) {
return `The "${name}" argument must be of type ${type}. Received type ${typeof actual}`
}, TypeError)
E('ERR_OUT_OF_RANGE',
function (str, range, input) {
Expand Down Expand Up @@ -1943,6 +1978,13 @@ function validateNumber (value, name) {
}
}

function validateInteger (value, name) {
validateNumber(value, name)
if ((value >>> 0) !== value) {
throw new errors.ERR_BUFFER_OUT_OF_BOUNDS(name)
}
}

function boundsError (value, length, type) {
if (Math.floor(value) !== value) {
validateNumber(value, type)
Expand Down
73 changes: 72 additions & 1 deletion test/node/test-buffer-from.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
var Buffer = require('../../').Buffer;

const common = require('./common');
const { deepStrictEqual, throws } = require('assert');
const assert = require('assert');
const { deepStrictEqual, throws } = assert;
const { runInNewContext } = require('vm');

const checkString = 'test';
Expand Down Expand Up @@ -66,3 +67,73 @@ deepStrictEqual(
throws(() => Buffer.from(input), errMsg);
});

{
const u16 = new Uint16Array([0xffff]);
const b16 = Buffer.copyBytesFrom(u16);
u16[0] = 0;
assert.strictEqual(b16.length, 2);
assert.strictEqual(b16[0], 255);
assert.strictEqual(b16[1], 255);
}

{
const u16 = new Uint16Array([0, 0xffff]);
const b16 = Buffer.copyBytesFrom(u16, 1, 5);
u16[0] = 0xffff;
u16[1] = 0;
assert.strictEqual(b16.length, 2);
assert.strictEqual(b16[0], 255);
assert.strictEqual(b16[1], 255);
}

{
const u32 = new Uint32Array([0xffffffff]);
const b32 = Buffer.copyBytesFrom(u32);
u32[0] = 0;
assert.strictEqual(b32.length, 4);
assert.strictEqual(b32[0], 255);
assert.strictEqual(b32[1], 255);
assert.strictEqual(b32[2], 255);
assert.strictEqual(b32[3], 255);
}

assert.throws(() => {
Buffer.copyBytesFrom();
}, TypeError);

{
const dv = new DataView(new ArrayBuffer(1));
assert.throws(() => {
Buffer.copyBytesFrom(dv);
}, TypeError);
}

['', Symbol(), true, false, {}, [], () => {}, 1, 1n, null, undefined].forEach(
notTypedArray => assert.throws(() => {
Buffer.copyBytesFrom(notTypedArray);
}, TypeError)
);

['', Symbol(), true, false, {}, [], () => {}, 1n].forEach(notANumber =>
assert.throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), notANumber);
}, TypeError)
);

[-1, NaN, 1.1, -Infinity].forEach(outOfRange =>
assert.throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), outOfRange);
}, RangeError)
);

['', Symbol(), true, false, {}, [], () => {}, 1n].forEach(notANumber =>
assert.throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), 0, notANumber);
}, TypeError)
);

[-1, NaN, 1.1, -Infinity].forEach(outOfRange =>
assert.throws(() => {
Buffer.copyBytesFrom(new Uint8Array(1), 0, outOfRange);
}, RangeError)
);

0 comments on commit 61e39c4

Please sign in to comment.