From a4f27bab29f6fcfe299224152044dbb2d3248e8b Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Wed, 21 Apr 2021 03:07:59 +0200 Subject: [PATCH 1/6] fixes to array conversion for input (v8 -> gi) conversion: - if fixed-size is set, validate that this size matches the size of the array that has been passed to us - fix bugs in typed array conversion into C array - implement typed array conversion into GArray as well - validate that the element size of the user's typedarray matches the element-size of the array we're emitting - for now, use g_assert_not_reached() because Nan exceptions are not propagated. in the future we could use MaybeLocal for output (gi -> v8) conversion: - validate that element-size (if present) matches the type tag --- src/value.cc | 64 +++++++++++++++++++++++++++++++++++--- tests/conversion__array.js | 14 +++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/value.cc b/src/value.cc index 826bb052..45558c2b 100644 --- a/src/value.cc +++ b/src/value.cc @@ -275,7 +275,9 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { GArray *g_array = (GArray*) data; data = g_array->data; length = g_array->len; - item_size = g_array_get_element_size (g_array); + auto element_size = g_array_get_element_size (g_array); + if (item_size != element_size) + g_critical ("Returned GArray has element-size %lu but element type has size %u", item_size, element_size); break; } case GI_ARRAY_TYPE_PTR_ARRAY: @@ -283,7 +285,8 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { GPtrArray *ptr_array = (GPtrArray*) data; data = ptr_array->pdata; length = ptr_array->len; - item_size = sizeof(gpointer); + if (item_size != sizeof(gpointer)) + g_critical ("Returned GPtrArray but element type has size %lu", item_size); break; } default: @@ -391,18 +394,51 @@ GArray * V8ToGArray(GITypeInfo *type_info, Local value) { } } + g_base_info_unref (element_info); + + } else if (value->IsTypedArray ()) { + auto array = Local::Cast (TO_OBJECT (value)); + int length = array->Length (); + + GITypeInfo* element_info = g_type_info_get_param_type (type_info, 0); + gsize element_size = GetTypeSize(element_info); + + if (array->ByteLength() != length * element_size) { // FIXME hacky but cheap + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); + //Nan::ThrowTypeError("Typed array must have the same element size"); + } + + g_array = g_array_sized_new (zero_terminated, FALSE, element_size, length); + g_array_set_size(g_array, length); + array->CopyContents(g_array->data, length * element_size); + g_base_info_unref (element_info); } else { - Nan::ThrowTypeError("Not an array."); + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); + //Nan::ThrowTypeError("Not an array."); } return g_array; } +// FIXME: for transfer=none we could simply pass the typedarray's data +// and avoid even the memcpy, but this would be a breaking change static void *V8ArrayToCArray(GITypeInfo *type_info, Local value) { auto array = Local::Cast (TO_OBJECT (value)); int length = array->Length(); + int fixed_size = g_type_info_get_array_fixed_size(type_info); + if (fixed_size != -1 && fixed_size != length) { + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); + //Nan::ThrowRangeError("Array not matching fixed size."); + } + bool isZeroTerminated = g_type_info_is_zero_terminated(type_info); GITypeInfo* element_info = g_type_info_get_param_type (type_info, 0); gsize element_size = GetTypeSize(element_info); @@ -433,15 +469,30 @@ static void *V8ArrayToCArray(GITypeInfo *type_info, Local value) { static void *V8TypedArrayToCArray(GITypeInfo *type_info, Local value) { auto array = Local::Cast (TO_OBJECT (value)); - size_t length = array->ByteLength(); + int length = array->Length(); + + int fixed_size = g_type_info_get_array_fixed_size(type_info); + if (fixed_size != -1 && fixed_size != length) { + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); + //Nan::ThrowRangeError("Array not matching fixed size."); + } bool isZeroTerminated = g_type_info_is_zero_terminated(type_info); GITypeInfo* element_info = g_type_info_get_param_type (type_info, 0); gsize element_size = GetTypeSize(element_info); + if (array->ByteLength() != length * element_size) { // FIXME hacky but cheap + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); + //Nan::ThrowTypeError("Typed array must have the same element size"); + } + void *result = malloc(element_size * (length + (isZeroTerminated ? 1 : 0))); - array->CopyContents(result, length); + array->CopyContents(result, length * element_size); if (isZeroTerminated) { void* pointer = (void*)((ulong)result + length * element_size); @@ -468,6 +519,9 @@ void *V8ToCArray(GITypeInfo *type_info, Local value) { return V8TypedArrayToCArray(type_info, value); } + // FIXME: not currently working, exceptions seem to be disabled. + // for now it's better to abort() than to risk a crash from undefined behaviour + g_assert_not_reached(); Nan::ThrowTypeError("Expected value to be an array"); return NULL; diff --git a/tests/conversion__array.js b/tests/conversion__array.js index ea0d6000..1e5927de 100644 --- a/tests/conversion__array.js +++ b/tests/conversion__array.js @@ -17,6 +17,20 @@ describe('IN-array', () => { assert(result === Buffer.from('hello').toString('base64')) }) +describe('IN-array (Uint8Array)', () => { + const data = Uint8Array.from([ 104, 101, 108, 108, 111 ]) // hello + const result = glib.base64Encode(data, data.length) + console.log('Result:', result) + assert(result === Buffer.from('hello').toString('base64')) +}) + +describe('IN-array (Int8Array)', () => { + const data = Int8Array.from([ 104, 101, 108, 108, 111 ]) // hello + const result = glib.base64Encode(data, data.length) + console.log('Result:', result) + assert(result === Buffer.from('hello').toString('base64')) +}) + describe('OUT-array (array-length after)', () => { const data = [ 104, 101, 108, 108, 111 ] // hello const result = glib.computeChecksumForData(glib.ChecksumType.MD5, data) From 3ee734a1f537878313358adcf1f95ffaf6d2733b Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Wed, 21 Apr 2021 12:53:55 +0200 Subject: [PATCH 2/6] [BREAKING] convert integer arrays into typed arrays we still memcpy(), but that's much more efficient than element-by-element conversion to V8 for large buffers of data --- src/value.cc | 64 +++++++++++++++++++++++++++---------- tests/conversion__array.js | 11 +++---- tests/function_call__out.js | 7 ++-- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/value.cc b/src/value.cc index 45558c2b..2aaa2275 100644 --- a/src/value.cc +++ b/src/value.cc @@ -238,19 +238,15 @@ Local GErrorToV8 (GITypeInfo *type_info, GError *err) { return obj; } -Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { - - auto array = New(); - - if (data == nullptr || length == 0) - return array; - - auto array_type = g_type_info_get_array_type (type_info); - auto item_type_info = g_type_info_get_param_type (type_info, 0); - auto item_size = GetTypeSize (item_type_info); - // auto item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; +// Resolve an array of a given type, into its data and element length +// May also validate item_size for some types of array +static void ArrayGetDataAndLength (GITypeInfo *type_info, void*& data, long& length, long& item_size) { + if (data == nullptr) { + length = 0; + return; + } - switch (array_type) { + switch (g_type_info_get_array_type (type_info)) { case GI_ARRAY_TYPE_C: { if (length == -1) { @@ -293,15 +289,53 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { g_assert_not_reached(); break; } +} - if (data == nullptr || length == 0) - goto out; +// FIXME: we could even avoid the memcpy for transfer=none and/or transfer=full +inline Local ArrayToBackingStore (void* data, long byte_length) { + auto buf = v8::ArrayBuffer::New(Isolate::GetCurrent(), byte_length); + memcpy(buf->GetBackingStore()->Data(), data, byte_length); + return buf; +} + +Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { + auto item_type_info = g_type_info_get_param_type (type_info, 0); + long item_size = GetTypeSize (item_type_info); + // auto item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + ArrayGetDataAndLength(type_info, data, length, item_size); + + // First try to convert into TypedArray + + auto type_tag = g_type_info_get_tag (item_type_info); + auto byte_length = length * item_size; + Local typedarray = + // (type_tag == GI_TYPE_TAG_BOOLEAN) ? v8::Uint8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT8) ? v8::Int8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT8) ? v8::Uint8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT16) ? v8::Int16Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT16) ? v8::Uint16Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT32) ? v8::Int32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT32) ? v8::Uint32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT64) ? v8::BigInt64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT64) ? v8::BigUint64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_FLOAT) ? v8::Float32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_DOUBLE) ? v8::Float64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + // special types: + (type_tag == GI_TYPE_TAG_GTYPE) ? v8::BigUint64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UNICHAR) ? v8::Uint32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + Local(); // empty handle + + if (!typedarray.IsEmpty()) { + g_base_info_unref(item_type_info); + return typedarray; + } /* * Fill array elements */ + auto array = New(); GIArgument value; for (int i = 0; i < length; i++) { @@ -310,8 +344,6 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { Nan::Set(array, i, GIArgumentToV8(item_type_info, &value)); } - -out: g_base_info_unref(item_type_info); return array; } diff --git a/tests/conversion__array.js b/tests/conversion__array.js index 1e5927de..807c9fb4 100644 --- a/tests/conversion__array.js +++ b/tests/conversion__array.js @@ -43,14 +43,13 @@ describe('OUT-array (array-length after)', () => { describe('OUT-array (array-length before)', () => { const filepath = path.join(__dirname, 'lorem-ipsum.txt') - const result = glib.fileGetContents(filepath) - console.log('Result:', result) - const content = result[1].map(c => String.fromCharCode(c)).join('') - const actualContent = fs.readFileSync(filepath).toString() + const [ ok, content ] = glib.fileGetContents(filepath) + const actualContent = fs.readFileSync(filepath) console.log([content, actualContent]) - assert(result[0] === true, 'glib_file_get_contents failed') - assert(content === actualContent, 'file content is wrong') + assert(ok === true, 'glib_file_get_contents failed') + assert(content instanceof Uint8Array, 'did not return Uint8Array') + assert(actualContent.equals(content), 'file content is wrong') }) describe('OUT-array (zero-terminated)', () => { diff --git a/tests/function_call__out.js b/tests/function_call__out.js index 615d5125..d423c1a2 100644 --- a/tests/function_call__out.js +++ b/tests/function_call__out.js @@ -6,7 +6,7 @@ const gi = require('../lib/') const Gtk = gi.require('Gtk', '3.0') const GLib = gi.require('GLib') -const { describe, it, expect } = require('./__common__.js') +const { describe, it, expect, assert } = require('./__common__.js') gi.startLoop() Gtk.init() @@ -28,9 +28,10 @@ describe('function out parameters', () => { const data = 'aGVsbG8=' const result = GLib.base64Decode(data, data.length) console.log(result) - const decodedText = result.map(c => String.fromCharCode(c)).join('') + assert(result instanceof Uint8Array, 'result was not Uint8Array') + const decodedText = Buffer.from(result).toString() console.log(decodedText) - expect(result, [ 104, 101, 108, 108, 111 ]) + assert(Buffer.from([ 104, 101, 108, 108, 111 ]).equals(result)) expect(decodedText, 'hello') }) From 46730c985920fd571111678051bc985cf1880032 Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Mon, 26 Apr 2021 03:22:13 +0200 Subject: [PATCH 3/6] support array length on struct fields --- lib/bootstrap.js | 18 +++++++++++++----- src/gi.cc | 24 +++++++++++++++++++++++- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/lib/bootstrap.js b/lib/bootstrap.js index b5cb5189..ef084a05 100644 --- a/lib/bootstrap.js +++ b/lib/bootstrap.js @@ -156,9 +156,9 @@ function addFunction(object, info) { define(object, getFunctionDescription(info)) } -function fieldGetter(fieldInfo) { +function fieldGetter(fieldInfo, lengthFieldInfo) { return function () { - return internal.StructFieldGetter(this, fieldInfo); + return internal.StructFieldGetter(this, fieldInfo, lengthFieldInfo); }; } @@ -168,7 +168,7 @@ function fieldSetter(fieldInfo) { }; } -function addField(object, fieldInfo) { +function addField(object, fieldInfo, lengthFieldInfo) { const flags = GI.field_info_get_flags(fieldInfo) const writable = (flags & GI.FieldInfoFlags.WRITABLE) !== 0 const readable = (flags & GI.FieldInfoFlags.READABLE) !== 0 @@ -178,7 +178,7 @@ function addField(object, fieldInfo) { Object.defineProperty(object, name, { configurable: true, enumerable: readable, - get: readable ? fieldGetter(fieldInfo) : undefined, + get: readable ? fieldGetter(fieldInfo, lengthFieldInfo) : undefined, set: writable ? fieldSetter(fieldInfo) : undefined }) } @@ -317,6 +317,13 @@ function makeUnion(info) { return constructor } +function getStructFieldLength(info, fieldInfo) { + const type = GI.field_info_get_type(fieldInfo); + const arrayLength = GI.type_info_get_array_length(type); + if (arrayLength !== -1) + return GI.struct_info_get_field(info, arrayLength); +} + function makeStruct(info) { const constructor = internal.MakeBoxedClass(info); @@ -329,7 +336,8 @@ function makeStruct(info) { const nFields = GI.struct_info_get_n_fields(info); for (let i = 0; i < nFields; i++) { const fieldInfo = GI.struct_info_get_field(info, i); - addField(constructor.prototype, fieldInfo); + const lengthFieldInfo = getStructFieldLength(info, fieldInfo); + addField(constructor.prototype, fieldInfo, lengthFieldInfo); } return constructor diff --git a/src/gi.cc b/src/gi.cc index 45232441..e643a053 100644 --- a/src/gi.cc +++ b/src/gi.cc @@ -256,6 +256,7 @@ NAN_METHOD(StructFieldSetter) { NAN_METHOD(StructFieldGetter) { Local jsBoxed = info[0].As(); Local jsFieldInfo = info[1].As(); + Local jsLengthFieldInfo = info[2].As(); if (jsBoxed->InternalFieldCount() == 0) { Nan::ThrowError("StructFieldGetter: instance is not a boxed"); @@ -286,6 +287,27 @@ NAN_METHOD(StructFieldGetter) { bool mustCopy = true; BaseInfo typeInfo = g_field_info_get_type(*fieldInfo); + long length = -1; + if (jsLengthFieldInfo->IsObject()) { + if (jsLengthFieldInfo->InternalFieldCount() == 0) { + Nan::ThrowError("StructFieldGetter: length field info is invalid"); + return; + } + BaseInfo lengthFieldInfo = + g_base_info_ref((GIFieldInfo *) GNodeJS::PointerFromWrapper(jsLengthFieldInfo)); + if (jsLengthFieldInfo.IsEmpty()) { + Nan::ThrowError("StructFieldGetter: length field info is NULL"); + return; + } + GIArgument lengthValue; + BaseInfo lengthTypeInfo = g_field_info_get_type(*lengthFieldInfo); + if (!g_field_info_get_field(*lengthFieldInfo, boxed, &lengthValue)) { + Nan::ThrowError("Length is not a primitive field"); + return; + } + length = GNodeJS::GIArgumentToLength(*lengthTypeInfo, &lengthValue, false); + } + if (!g_field_info_get_field(*fieldInfo, boxed, &value)) { /* If g_field_info_get_field() failed, this is a non-primitive type */ @@ -306,7 +328,7 @@ NAN_METHOD(StructFieldGetter) { return; } - RETURN(GNodeJS::GIArgumentToV8(*typeInfo, &value, -1, mustCopy)); + RETURN(GNodeJS::GIArgumentToV8(*typeInfo, &value, length, mustCopy)); } NAN_METHOD(StartLoop) { From 3d3e9b36aa680c89ff9ed5f5f374415ff30b5015 Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Sun, 2 May 2021 00:34:57 +0200 Subject: [PATCH 4/6] fixup! support array length on struct fields --- src/gi.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gi.cc b/src/gi.cc index e643a053..0b95e5f5 100644 --- a/src/gi.cc +++ b/src/gi.cc @@ -295,7 +295,7 @@ NAN_METHOD(StructFieldGetter) { } BaseInfo lengthFieldInfo = g_base_info_ref((GIFieldInfo *) GNodeJS::PointerFromWrapper(jsLengthFieldInfo)); - if (jsLengthFieldInfo.IsEmpty()) { + if (lengthFieldInfo.isEmpty()) { Nan::ThrowError("StructFieldGetter: length field info is NULL"); return; } From cfa4c02cefcbac813e6275a6cde3d215ce37b7e6 Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Sun, 2 May 2021 00:37:46 +0200 Subject: [PATCH 5/6] fixup! [BREAKING] convert integer arrays into typed arrays - use the (now deprecated) GetContents() to get better compatibility across Node.js versions - convert to Buffer instead of a plain Uint8Array --- src/value.cc | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/value.cc b/src/value.cc index 2aaa2275..63e8eaea 100644 --- a/src/value.cc +++ b/src/value.cc @@ -292,9 +292,9 @@ static void ArrayGetDataAndLength (GITypeInfo *type_info, void*& data, long& len } // FIXME: we could even avoid the memcpy for transfer=none and/or transfer=full -inline Local ArrayToBackingStore (void* data, long byte_length) { +inline Local MakeArrayBuffer (void* data, long byte_length) { auto buf = v8::ArrayBuffer::New(Isolate::GetCurrent(), byte_length); - memcpy(buf->GetBackingStore()->Data(), data, byte_length); + memcpy(buf->GetContents().Data(), data, byte_length); return buf; } @@ -310,20 +310,20 @@ Local ArrayToV8 (GITypeInfo *type_info, void* data, long length) { auto type_tag = g_type_info_get_tag (item_type_info); auto byte_length = length * item_size; Local typedarray = - // (type_tag == GI_TYPE_TAG_BOOLEAN) ? v8::Uint8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_INT8) ? v8::Int8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_UINT8) ? v8::Uint8Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_INT16) ? v8::Int16Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_UINT16) ? v8::Uint16Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_INT32) ? v8::Int32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_UINT32) ? v8::Uint32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_INT64) ? v8::BigInt64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_UINT64) ? v8::BigUint64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_FLOAT) ? v8::Float32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_DOUBLE) ? v8::Float64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + // (type_tag == GI_TYPE_TAG_BOOLEAN) ? v8::Uint8Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT8) ? v8::Int8Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT8) ? Nan::CopyBuffer((char*)data, byte_length).ToLocalChecked().As() : + (type_tag == GI_TYPE_TAG_INT16) ? v8::Int16Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT16) ? v8::Uint16Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT32) ? v8::Int32Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT32) ? v8::Uint32Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_INT64) ? v8::BigInt64Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UINT64) ? v8::BigUint64Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_FLOAT) ? v8::Float32Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_DOUBLE) ? v8::Float64Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : // special types: - (type_tag == GI_TYPE_TAG_GTYPE) ? v8::BigUint64Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : - (type_tag == GI_TYPE_TAG_UNICHAR) ? v8::Uint32Array::New(ArrayToBackingStore(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_GTYPE) ? v8::BigUint64Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : + (type_tag == GI_TYPE_TAG_UNICHAR) ? v8::Uint32Array::New(MakeArrayBuffer(data, byte_length), 0, length).As() : Local(); // empty handle if (!typedarray.IsEmpty()) { From 86bb580b19c3950cb2a7a9f71bfabc6167c403a1 Mon Sep 17 00:00:00 2001 From: Alba Mendez Date: Sun, 2 May 2021 01:41:27 +0200 Subject: [PATCH 6/6] support GValues with GByteArray in them --- src/value.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/value.cc b/src/value.cc index 63e8eaea..5fae8717 100644 --- a/src/value.cc +++ b/src/value.cc @@ -1416,6 +1416,8 @@ bool CanConvertV8ToGValue(GValue *gvalue, Local value) { } else if (G_VALUE_HOLDS_OBJECT (gvalue)) { return ValueIsInstanceOfGType(value, G_VALUE_TYPE (gvalue)); } else if (G_VALUE_HOLDS_BOXED (gvalue)) { + if (G_VALUE_TYPE (gvalue) == G_TYPE_BYTE_ARRAY) + return value->IsUint8Array(); return ValueIsInstanceOfGType(value, G_VALUE_TYPE (gvalue)); } else if (G_VALUE_HOLDS_PARAM (gvalue)) { return value->IsObject(); @@ -1488,6 +1490,19 @@ bool V8ToGValue(GValue *gvalue, Local value, bool mustCopy) { } g_value_set_object (gvalue, GObjectFromWrapper (value)); } else if (G_VALUE_HOLDS_BOXED (gvalue)) { + if (G_VALUE_TYPE (gvalue) == G_TYPE_BYTE_ARRAY) { + if (!value->IsUint8Array()) { + Throw::CannotConvertGType("GByteArray", G_VALUE_TYPE (gvalue)); + return false; + } + auto array = value.As(); + auto garray = g_byte_array_sized_new(array->ByteLength()); + g_byte_array_set_size(garray, array->ByteLength()); + array->CopyContents(garray->data, garray->len); + g_value_take_boxed(gvalue, garray); + return true; + } + if (!ValueIsInstanceOfGType(value, G_VALUE_TYPE (gvalue))) { Throw::CannotConvertGType("boxed", G_VALUE_TYPE (gvalue)); return false; @@ -1555,6 +1570,11 @@ Local GValueToV8(const GValue *gvalue, bool mustCopy) { return WrapperFromGObject (G_OBJECT (g_value_get_object (gvalue))); } else if (G_VALUE_HOLDS_BOXED (gvalue)) { GType gtype = G_VALUE_TYPE (gvalue); + if (gtype == G_TYPE_BYTE_ARRAY) { + auto garray = (GByteArray*) g_value_get_boxed(gvalue); + return Nan::CopyBuffer((char*)garray->data, garray->len).ToLocalChecked(); + } + GIBaseInfo *info = g_irepository_find_by_gtype(NULL, gtype); if (info == NULL) { Throw::InvalidGType(gtype);