Skip to content
This repository was archived by the owner on Jul 25, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions templates/helperHeader.dot
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,63 @@
#define EXTRACT_v8_String(x) EXTRACT_v8_string(x)
#define EXTRACT_v8_float(x) EXTRACT_v8_double(x)

struct ArrayBuffer {
char* data;
uint32_t size;
class ArrayBufferHelper {
public:
ArrayBufferHelper(void* data, uint32_t length) {
Set(data, length);
}

ArrayBufferHelper(const ArrayBufferHelper& rhs) {
CopyFrom(rhs);
}

~ArrayBufferHelper() {}

ArrayBufferHelper& operator = (const ArrayBufferHelper& rhs) {
CopyFrom(rhs);
return *this;
}

void Set(void* data, uint32_t length, bool external = true) {
data_ = data;
length_ = length;
external_buffer_ = external;
}

v8::Local<v8::ArrayBuffer> GetArrayBuffer() const {
auto mode = external_buffer_ ?
v8::ArrayBufferCreationMode::kExternalized :
v8::ArrayBufferCreationMode::kInternalized;

return v8::ArrayBuffer::New(
v8::Isolate::GetCurrent(), data_, length_, mode);
}

bool operator == (const ArrayBufferHelper& rhs) {
if (this != &rhs) {
return data_ == rhs.data_ &&
length_ == rhs.length_ &&
external_buffer_ == rhs.external_buffer_;
}
return true;
}

void* GetData() const { return data_; }
uint32_t GetLength() const { return length_; }
bool IsExternalBuffer() const { return external_buffer_; }

private:
void CopyFrom(const ArrayBufferHelper& rhs) {
if (this != &rhs) {
data_ = rhs.data_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the buffer copy using assign cause multiple free if the mode is internal?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes if external_buffer_ is false, then there can be double delete problem, unless user explicitly change one object and set its external_buffer to true

Can there be an automatically approach to avoid this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the const to change the rhs? Seems not compatible with the coding style. :)

Copy link
Contributor Author

@kenny-y kenny-y Dec 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about we rename the class to ExternalArrayBuffer and make it only work in external buffer mode?

ArrayBuffers with ownership of buffer will be treated in other class, to avoid potential issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The choice of whether ExternalArrayBuffer or InternalArrayBuffer is made only in impl code right? I'm ok with that.

length_ = rhs.length_;
external_buffer_ = rhs.external_buffer_;
}
}

void* data_;
uint32_t length_;
bool external_buffer_;
};

inline v8::Local<v8::Array> EXTRACT_v8_array(v8::Local<v8::Value> value) {
Expand Down Expand Up @@ -163,16 +217,14 @@ inline v8::Local<v8::Function> EXTRACT_v8_function(v8::Local<v8::Value> value, i
return v8::Local<v8::Function>::Cast(value);
}

inline ArrayBuffer EXTRACT_v8_ArrayBuffer(v8::Local<v8::Value> value) {
inline ArrayBufferHelper EXTRACT_v8_ArrayBuffer(v8::Local<v8::Value> value) {
if (value->IsObject()) {
} else {
// throw ...
}

ArrayBuffer arrayBuffer;
arrayBuffer.data = node::Buffer::Data(value->ToObject());
arrayBuffer.size = node::Buffer::Length(value->ToObject());
return arrayBuffer;
v8::ArrayBuffer* buffer = v8::ArrayBuffer::Cast(*value);
return ArrayBufferHelper(buffer->GetContents().Data(), buffer->GetContents().ByteLength());
}

// Helper: to deal with const members in interface of *.idl file
Expand Down
2 changes: 1 addition & 1 deletion templates/helperHeaderArray.dot
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class ArrayHelper {
double GetDouble(uint32_t index) const { return EXTRACT_v8_double(v8_array_->Get(index)); }
std::string GetString(uint32_t index) const { return EXTRACT_v8_string(v8_array_->Get(index)); }
v8::Local<v8::Value> GetValue(uint32_t index) const;
ArrayBuffer GetArrayBuffer(uint32_t index) const { return EXTRACT_v8_ArrayBuffer(v8_array_->Get(index)); }
ArrayBufferHelper GetArrayBuffer(uint32_t index) const { return EXTRACT_v8_ArrayBuffer(v8_array_->Get(index)); }
v8::Local<v8::Object> GetObject(uint32_t index) const { return EXTRACT_v8_object(v8_array_->Get(index)); }
v8::Local<v8::Array> GetArray(uint32_t index) const { return EXTRACT_v8_array(v8_array_->Get(index)); }
v8::Local<v8::Function> GetFunction(uint32_t index) const { return EXTRACT_v8_function(v8_array_->Get(index)); }
Expand Down
2 changes: 1 addition & 1 deletion templates/nanCxxHeaderPropertyVars.def
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if (p.static) {
staticStr = 'static ';
}
}}
{{? isInterface(p.idlType, it.refTypeMap) || (p.idlType.idlType == 'ArrayBuffer') }}
{{? isInterface(p.idlType, it.refTypeMap) }}
{{=staticStr}}std::unique_ptr<Nan::Persistent<v8::Object>> {{=p.name}}_;
{{?}}
{{~}}
6 changes: 2 additions & 4 deletions templates/nanCxxImplMethod.def
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ var argStr = args.join(', ');
info.GetReturnValue().Set(Nan::New(value).ToLocalChecked());
{{?? method.idlType.idlType === 'ArrayBuffer' }}
// Return type is ArrayBuffer
ArrayBuffer arrayBuffer = {{=functionCallPrefix}}{{=methodName}}({{=argStr}});
v8::Local<v8::Object> value;
if (Nan::NewBuffer(arrayBuffer.data, arrayBuffer.size).ToLocal(&value))
info.GetReturnValue().Set(value);
auto arrayBuffer = {{=functionCallPrefix}}{{=methodName}}({{=argStr}});
info.GetReturnValue().Set(arrayBuffer.GetArrayBuffer());
{{?? isInterface(method.idlType, it.refTypeMap)}}
// Return type is an interface object
auto implObj = {{=functionCallPrefix}}{{=methodName}}({{=argStr}});
Expand Down
14 changes: 1 addition & 13 deletions templates/nanCxxImplProperty.def
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,7 @@ NAN_GETTER({{=className}}::{{=p.name}}Getter) {
{{?? isTypedArray(p.idlType) }}
info.GetReturnValue().Set(impl_val.GetTypedArray());
{{?? p.idlType.idlType === 'ArrayBuffer' }}
if (! {{=myself}}{{=p.name}}_) {
v8::Local<v8::Object> value;
if(Nan::NewBuffer(impl_val.data, impl_val.size).ToLocal(&value)) {
{{=myself}}{{=p.name}}_.reset(new Nan::Persistent<v8::Object>(value));
}
}

if ({{=myself}}{{=p.name}}_) {
v8::Local<v8::Object> obj = Nan::New(*{{=myself}}{{=p.name}}_);
info.GetReturnValue().Set(obj);
} else {
info.GetReturnValue().Set(Nan::Undefined());
}
info.GetReturnValue().Set(impl_val.GetArrayBuffer());
{{?? true}}
info.GetReturnValue().Set(Nan::New(impl_val){{=str}});
{{?}}
Expand Down
2 changes: 1 addition & 1 deletion templates/nanCxxImplPropertyVarsRelease.def
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{{#def.members}}

{{~ getNonStaticPropertyMembers(it) :p:i }}
{{? isInterface(p.idlType, it.refTypeMap) || (p.idlType.idlType === 'ArrayBuffer')}}
{{? isInterface(p.idlType, it.refTypeMap) }}
{{=p.name}}_.reset();
{{?}}
{{~}}
File renamed without changes.
2 changes: 2 additions & 0 deletions test/buffer/buffer.widl → test/arraybuffer/arraybuffer.widl
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ interface Buffer {
ArrayBuffer getArrayBuffer();

DOMString buffer2String(ArrayBuffer buffer);

static ArrayBuffer getCommonData();
};
File renamed without changes.
24 changes: 24 additions & 0 deletions test/arraybuffer/buffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2016 Intel Corporation. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

#include "buffer.h"

#include <string.h>

Buffer::Buffer() {
data_ = "hello world!";
}

Buffer::~Buffer() {
}

ArrayBufferHelper Buffer::getArrayBuffer() const {
char* text = "hello world!";
return ArrayBufferHelper(text, strlen(text));
}

ArrayBufferHelper Buffer::getCommonData() {
static char* raw_buf = "static buffer test data";
return ArrayBufferHelper(raw_buf, strlen(raw_buf));
}
45 changes: 45 additions & 0 deletions test/arraybuffer/buffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2016 Intel Corporation. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

#ifndef _BUFFER_H_
#define _BUFFER_H_

#include <node.h>
#include <v8.h>

#include <string>

#include "gen/generator_helper.h"

class Buffer {
public:
Buffer();
~Buffer();

public:
ArrayBufferHelper getArrayBuffer() const;

ArrayBufferHelper get_data() const {
return ArrayBufferHelper(
const_cast<void*>(reinterpret_cast<const void*>(data_.c_str())),
data_.length());
}

void set_data(const ArrayBufferHelper& buffer) {
data_ = std::string((const char*)buffer.GetData(),
buffer.GetLength());
}

std::string buffer2String(const ArrayBufferHelper& arrayBuffer) {
return std::string((const char*)arrayBuffer.GetData(),
arrayBuffer.GetLength());
}

static ArrayBufferHelper getCommonData();

private:
std::string data_;
};

#endif // _BUFFER_H_
27 changes: 0 additions & 27 deletions test/buffer/buffer.cpp

This file was deleted.

38 changes: 0 additions & 38 deletions test/buffer/buffer.h

This file was deleted.

79 changes: 79 additions & 0 deletions test/test-arraybuffer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2016 Intel Corporation. All rights reserved.
// Use of this source code is governed by a MIT-style license that can be
// found in the LICENSE file.

'use strict';

/* global describe, it */
var assert = require('assert');
var buildAddon = require('../lib/addon-builder.js').buildAddon;
var compile = require('../lib/compile.js').compile;
var path = require('path');

var Buffer;

function bufToString(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}

function stringToArrayBuffer(str) {
var buf = new ArrayBuffer(str.length);
var bufView = new Uint8Array(buf);
for (var i = 0, strLen = str.length; i < strLen; ++i) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}

describe('widl-nan Unit Test - Buffer', function() {
it('Generating binding C++ code', function() {
return compile([
'test/arraybuffer/arraybuffer.widl'
], 'test/arraybuffer/gen');
});

it('Building addon', function() {
// building addon maybe slow
this.timeout(100000);

return buildAddon('test/arraybuffer');
});

it('Loading addon', function() {
var addonDir = path.join(path.dirname(__filename), 'arraybuffer');
var addon = require('bindings')(
// eslint-disable-next-line camelcase
{bindings: 'testerAddon', module_root: addonDir});

Buffer = addon.Buffer;
assert.equal(typeof Buffer, 'function');
});

it('Method returning an ArrayBuffer', done => {
var buf = new Buffer();
assert.equal(bufToString(buf.getArrayBuffer()), 'hello world!');
done();
});

it('Static method returning an ArrayBuffer', done => {
assert.equal(bufToString(Buffer.getCommonData()), 'static buffer test data');
assert.equal(bufToString(Buffer.getCommonData()), 'static buffer test data');
assert.equal(bufToString(Buffer.getCommonData()), 'static buffer test data');
done();
});

it('Object property as ArrayBuffer', done => {
var buf = new Buffer();
assert.equal(bufToString(buf.data), 'hello world!');
buf.data = stringToArrayBuffer('hello universe!');
assert.equal(bufToString(buf.data), 'hello universe!');
done();
});

it('Passing ArrayBuffer as paramter', done => {
var buf = new Buffer();
const buffer = stringToArrayBuffer('Array buffer string test...');
assert.equal(buf.buffer2String(buffer), 'Array buffer string test...');
done();
});
});
Loading