buffer: support boxed strings and toPrimitive
Add support for `Buffer.from(new String('...'))` and `Buffer.from({[Symbol.toPrimitive]() { return '...'; }})` PR-URL: https://github.com/nodejs/node/pull/13725 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
d3c668cead
commit
22cf25cf2d
@ -908,6 +908,44 @@ console.log(buf2.toString());
|
|||||||
|
|
||||||
A `TypeError` will be thrown if `str` is not a string.
|
A `TypeError` will be thrown if `str` is not a string.
|
||||||
|
|
||||||
|
### Class Method: Buffer.from(object[, offsetOrEncoding[, length]])
|
||||||
|
<!-- YAML
|
||||||
|
added: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
* `object` {Object} An object supporting `Symbol.toPrimitive` or `valueOf()`
|
||||||
|
* `offsetOrEncoding` {number|string} A byte-offset or encoding, depending on
|
||||||
|
the value returned either by `object.valueOf()` or
|
||||||
|
`object[Symbol.toPrimitive]()`.
|
||||||
|
* `length` {number} A length, depending on the value returned either by
|
||||||
|
`object.valueOf()` or `object[Symbol.toPrimitive]()`.
|
||||||
|
|
||||||
|
For objects whose `valueOf()` function returns a value not strictly equal to
|
||||||
|
`object`, returns `Buffer.from(object.valueOf(), offsetOrEncoding, length)`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const buf = Buffer.from(new String('this is a test'));
|
||||||
|
// <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
|
||||||
|
```
|
||||||
|
|
||||||
|
For objects that support `Symbol.toPrimitive`, returns
|
||||||
|
`Buffer.from(object[Symbol.toPrimitive](), offsetOrEncoding, length)`.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class Foo {
|
||||||
|
[Symbol.toPrimitive]() {
|
||||||
|
return 'this is a test';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const buf = Buffer.from(new Foo(), 'utf8');
|
||||||
|
// <Buffer 74 68 69 73 20 69 73 20 61 20 74 65 73 74>
|
||||||
|
```
|
||||||
|
|
||||||
### Class Method: Buffer.isBuffer(obj)
|
### Class Method: Buffer.isBuffer(obj)
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.101
|
added: v0.1.101
|
||||||
|
@ -176,12 +176,26 @@ Buffer.from = function(value, encodingOrOffset, length) {
|
|||||||
if (isAnyArrayBuffer(value))
|
if (isAnyArrayBuffer(value))
|
||||||
return fromArrayBuffer(value, encodingOrOffset, length);
|
return fromArrayBuffer(value, encodingOrOffset, length);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
throw new TypeError(kFromErrorMsg);
|
||||||
|
|
||||||
|
if (typeof value === 'number')
|
||||||
|
throw new TypeError('"value" argument must not be a number');
|
||||||
|
|
||||||
|
const valueOf = value.valueOf && value.valueOf();
|
||||||
|
if (valueOf != null && valueOf !== value)
|
||||||
|
return Buffer.from(valueOf, encodingOrOffset, length);
|
||||||
|
|
||||||
var b = fromObject(value);
|
var b = fromObject(value);
|
||||||
if (b)
|
if (b)
|
||||||
return b;
|
return b;
|
||||||
|
|
||||||
if (typeof value === 'number')
|
if (typeof value[Symbol.toPrimitive] === 'function') {
|
||||||
throw new TypeError('"value" argument must not be a number');
|
return Buffer.from(value[Symbol.toPrimitive]('string'),
|
||||||
|
encodingOrOffset,
|
||||||
|
length);
|
||||||
|
}
|
||||||
|
|
||||||
throw new TypeError(kFromErrorMsg);
|
throw new TypeError(kFromErrorMsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
57
test/parallel/test-buffer-from.js
Normal file
57
test/parallel/test-buffer-from.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('../common');
|
||||||
|
const { deepStrictEqual, throws } = require('assert');
|
||||||
|
const { Buffer } = require('buffer');
|
||||||
|
const { runInNewContext } = require('vm');
|
||||||
|
|
||||||
|
const checkString = 'test';
|
||||||
|
|
||||||
|
const check = Buffer.from(checkString);
|
||||||
|
|
||||||
|
class MyString extends String {
|
||||||
|
constructor() {
|
||||||
|
super(checkString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyPrimitive {
|
||||||
|
[Symbol.toPrimitive]() {
|
||||||
|
return checkString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyBadPrimitive {
|
||||||
|
[Symbol.toPrimitive]() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deepStrictEqual(Buffer.from(new String(checkString)), check);
|
||||||
|
deepStrictEqual(Buffer.from(new MyString()), check);
|
||||||
|
deepStrictEqual(Buffer.from(new MyPrimitive()), check);
|
||||||
|
deepStrictEqual(Buffer.from(
|
||||||
|
runInNewContext('new String(checkString)', {checkString})),
|
||||||
|
check);
|
||||||
|
|
||||||
|
const err = new RegExp('^TypeError: First argument must be a string, Buffer, ' +
|
||||||
|
'ArrayBuffer, Array, or array-like object\\.$');
|
||||||
|
|
||||||
|
[
|
||||||
|
{},
|
||||||
|
new Boolean(true),
|
||||||
|
{ valueOf() { return null; } },
|
||||||
|
{ valueOf() { return undefined; } },
|
||||||
|
{ valueOf: null },
|
||||||
|
Object.create(null)
|
||||||
|
].forEach((input) => {
|
||||||
|
throws(() => Buffer.from(input), err);
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
new Number(true),
|
||||||
|
new MyBadPrimitive()
|
||||||
|
].forEach((input) => {
|
||||||
|
throws(() => Buffer.from(input),
|
||||||
|
/^TypeError: "value" argument must not be a number$/);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user