From 7294992465837419fa14d8f1c91bfba800760e89 Mon Sep 17 00:00:00 2001 From: Trevor Norris Date: Wed, 17 Jun 2015 10:43:13 -0600 Subject: [PATCH] buffer: allow ArrayBuffer as Buffer argument Buffer now uses the ArrayBuffer as the backing store if passed to the constructor. Fixes: https://github.com/nodejs/io.js/issues/106 --- lib/internal/buffer_new.js | 5 ++- src/node_buffer.cc | 15 ++++++++ test/parallel/test-buffer-arraybuffer.js | 46 ++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-buffer-arraybuffer.js diff --git a/lib/internal/buffer_new.js b/lib/internal/buffer_new.js index 3b3a2006146663..8a30fc5c3ac744 100644 --- a/lib/internal/buffer_new.js +++ b/lib/internal/buffer_new.js @@ -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) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 95d454d9f803ec..c03a90fcc3b9db 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -522,6 +522,20 @@ void CreateFromString(const FunctionCallbackInfo& args) { } +void CreateFromArrayBuffer(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + if (!args[0]->IsArrayBuffer()) + return env->ThrowTypeError("argument is not an ArrayBuffer"); + Local ab = args[0].As(); + Local ui = Uint8Array::New(ab, 0, ab->ByteLength()); + Maybe 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& args) { CHECK(args[0]->IsUint8Array()); CHECK(args[1]->IsNumber()); @@ -1139,6 +1153,7 @@ void Initialize(Handle 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); diff --git a/test/parallel/test-buffer-arraybuffer.js b/test/parallel/test-buffer-arraybuffer.js new file mode 100644 index 00000000000000..c13d0ba4118aad --- /dev/null +++ b/test/parallel/test-buffer-arraybuffer.js @@ -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);