Skip to content

Commit

Permalink
buffer: allow ArrayBuffer as Buffer argument
Browse files Browse the repository at this point in the history
Buffer now uses the ArrayBuffer as the backing store if passed to the
constructor.

Fixes: #106
PR-URL: #2002
Reviewed-By: Domenic Denicola <d@domenic.me>
  • Loading branch information
trevnorris authored and rvagg committed Aug 4, 2015
1 parent e5ada11 commit 4643b8b
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
5 changes: 4 additions & 1 deletion lib/internal/buffer_new.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ function fromObject(obj) {
return b;
}

// TODO(trevnorris): This will fail for an actual ArrayBuffer.
if (obj instanceof ArrayBuffer) {
return binding.createFromArrayBuffer(obj);
}

if (obj.buffer instanceof ArrayBuffer || obj.length) {
var length;
if (typeof obj.length !== 'number' || obj.length !== obj.length)
Expand Down
15 changes: 15 additions & 0 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,20 @@ void CreateFromString(const FunctionCallbackInfo<Value>& args) {
}


void CreateFromArrayBuffer(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
if (!args[0]->IsArrayBuffer())
return env->ThrowTypeError("argument is not an ArrayBuffer");
Local<ArrayBuffer> ab = args[0].As<ArrayBuffer>();
Local<Uint8Array> ui = Uint8Array::New(ab, 0, ab->ByteLength());
Maybe<bool> mb =
ui->SetPrototype(env->context(), env->buffer_prototype_object());
if (!mb.FromMaybe(false))
return env->ThrowError("Unable to set Object prototype");
args.GetReturnValue().Set(ui);
}


void Slice(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsUint8Array());
CHECK(args[1]->IsNumber());
Expand Down Expand Up @@ -1171,6 +1185,7 @@ void Initialize(Handle<Object> target,
env->SetMethod(target, "setupBufferJS", SetupBufferJS);
env->SetMethod(target, "create", Create);
env->SetMethod(target, "createFromString", CreateFromString);
env->SetMethod(target, "createFromArrayBuffer", CreateFromArrayBuffer);

env->SetMethod(target, "slice", Slice);
env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
Expand Down
46 changes: 46 additions & 0 deletions test/parallel/test-buffer-arraybuffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

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

const Buffer = require('buffer').Buffer;
const LENGTH = 16;

const ab = new ArrayBuffer(LENGTH);
const dv = new DataView(ab);
const ui = new Uint8Array(ab);
const buf = new Buffer(ab);


assert.ok(buf instanceof Buffer);
// For backwards compatibility of old .parent property test that if buf is not
// a slice then .parent should be undefined.
assert.equal(buf.parent, undefined);
assert.equal(buf.buffer, ab);
assert.equal(buf.length, ab.byteLength);


buf.fill(0xC);
for (let i = 0; i < LENGTH; i++) {
assert.equal(ui[i], 0xC);
ui[i] = 0xF;
assert.equal(buf[i], 0xF);
}

buf.writeUInt32LE(0xF00, 0);
buf.writeUInt32BE(0xB47, 4);
buf.writeDoubleLE(3.1415, 8);

assert.equal(dv.getUint32(0, true), 0xF00);
assert.equal(dv.getUint32(4), 0xB47);
assert.equal(dv.getFloat64(8, true), 3.1415);


// Now test protecting users from doing stupid things

assert.throws(function() {
function AB() { }
AB.__proto__ = ArrayBuffer;
AB.prototype.__proto__ = ArrayBuffer.prototype;
new Buffer(new AB());
}, TypeError);

0 comments on commit 4643b8b

Please sign in to comment.