Skip to content

Commit

Permalink
buffer: add asString static method
Browse files Browse the repository at this point in the history
  • Loading branch information
anonrig committed Nov 10, 2022
1 parent d55a7c3 commit 4907312
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
37 changes: 37 additions & 0 deletions doc/api/buffer.md
Expand Up @@ -888,6 +888,43 @@ socket.on('readable', () => {

A `TypeError` will be thrown if `size` is not a number.

### Static method: `Buffer.asString(list[, encoding])`

<!-- YAML
added: REPLACEME
-->

* `list` {ArrayBufferView|ArrayBuffer|SharedArrayBuffer} Resource
* `encoding` {string} If `string` is a string, this is its encoding.
**Default** `'utf8'`
* Returns: {string} The encoded string representation of `list`

```mjs
import { Buffer } from 'node:buffer';

const buf = new Uint8Array([
104, 101, 108, 108,
111, 32, 119, 111,
114, 108, 100,
]);

console.log(Buffer.asString(buf));
// Prints: 'hello world'
```

```cjs
const { Buffer } = require('node:buffer');

const buf = new Uint8Array([
104, 101, 108, 108,
111, 32, 119, 111,
114, 108, 100,
]);

console.log(Buffer.asString(buf));
// Prints: 'hello world'
```

### Static method: `Buffer.byteLength(string[, encoding])`

<!-- YAML
Expand Down
11 changes: 11 additions & 0 deletions lib/buffer.js
Expand Up @@ -52,6 +52,7 @@ const {
} = primordials;

const {
asString: _asString,
byteLengthUtf8,
compare: _compare,
compareOffset,
Expand Down Expand Up @@ -538,6 +539,16 @@ Buffer.isEncoding = function isEncoding(encoding) {
};
Buffer[kIsEncodingSymbol] = Buffer.isEncoding;

Buffer.asString = function asString(list, encoding = 'utf8') {
const normalizedEncoding = normalizeEncoding(encoding);
if (normalizedEncoding === undefined) {
validateString(encoding, 'encoding');
throw new ERR_UNKNOWN_ENCODING(encoding);
}

return _asString(list, encoding);
};

Buffer.concat = function concat(list, length) {
validateArray(list, 'list');

Expand Down
32 changes: 32 additions & 0 deletions src/node_buffer.cc
Expand Up @@ -565,6 +565,36 @@ void StringSlice(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(ret);
}

// Convert the input into a encoded string
void AsString(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args); // list, encoding

if (!(args[0]->IsArrayBuffer() || args[0]->IsSharedArrayBuffer() ||
args[0]->IsArrayBufferView())) {
return node::THROW_ERR_INVALID_ARG_TYPE(
env->isolate(),
"The \"list\" argument must be an instance of SharedArrayBuffer, "
"ArrayBuffer or ArrayBufferView.");
}

CHECK(args[1]->IsString());

ArrayBufferViewContents<char> buffer(args[0]);
enum encoding enc = ParseEncoding(env->isolate(), args[1], UTF8);

if (buffer.length() == 0) return args.GetReturnValue().SetEmptyString();

Local<Value> error;
MaybeLocal<Value> maybe_ret = StringBytes::Encode(
env->isolate(), buffer.data(), buffer.length(), enc, &error);
Local<Value> ret;
if (!maybe_ret.ToLocal(&ret)) {
CHECK(!error.IsEmpty());
env->isolate()->ThrowException(error);
return;
}
args.GetReturnValue().Set(ret);
}

// bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd])
void Copy(const FunctionCallbackInfo<Value> &args) {
Expand Down Expand Up @@ -1282,6 +1312,7 @@ void Initialize(Local<Object> target,

SetMethod(context, target, "setBufferPrototype", SetBufferPrototype);
SetMethodNoSideEffect(context, target, "createFromString", CreateFromString);
SetMethodNoSideEffect(context, target, "asString", AsString);

SetMethodNoSideEffect(context, target, "byteLengthUtf8", ByteLengthUtf8);
SetMethod(context, target, "copy", Copy);
Expand Down Expand Up @@ -1339,6 +1370,7 @@ void Initialize(Local<Object> target,
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(SetBufferPrototype);
registry->Register(CreateFromString);
registry->Register(AsString);

registry->Register(ByteLengthUtf8);
registry->Register(Copy);
Expand Down
52 changes: 52 additions & 0 deletions test/parallel/test-buffer-asstring.js
@@ -0,0 +1,52 @@
'use strict';

const common = require('../common');
const assert = require('assert');

// utf8, ucs2, ascii, latin1, utf16le
const encodings = ['utf8', 'utf-8', 'ucs2', 'ucs-2', 'ascii', 'latin1',
'binary', 'utf16le', 'utf-16le'];

[
{},
new Boolean(true),
{ valueOf() { return null; } },
{ valueOf() { return undefined; } },
{ valueOf: null },
Object.create(null),
new Number(true),
Symbol(),
5n,
(one, two, three) => {},
undefined,
null,
].forEach((input) => {
const errObj = {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
};
assert.throws(() => Buffer.asString(input), errObj);
assert.throws(() => Buffer.asString(input, 'hex'), errObj);
});

{
const value = Buffer.from('hello world');
encodings
.reduce((es, e) => es.concat(e, e.toUpperCase()), [])
.forEach((encoding) => {
assert.strictEqual(Buffer.asString(value, encoding), value.toString(encoding));
});
}


// Invalid encodings
for (let i = 1; i < 10; i++) {
const encoding = String(i).repeat(i);
const error = common.expectsError({
code: 'ERR_UNKNOWN_ENCODING',
name: 'TypeError',
message: `Unknown encoding: ${encoding}`
});
assert.ok(!Buffer.isEncoding(encoding));
assert.throws(() => Buffer.asString([], encoding), error);
}

0 comments on commit 4907312

Please sign in to comment.