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
  • Loading branch information
trevnorris committed Jun 17, 2015
1 parent f115dfc commit 7294992
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 @@ -522,6 +522,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 @@ -1139,6 +1153,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 7294992

Please sign in to comment.