Skip to content

Commit 341d477

Browse files
authored
Merge pull request #175 from LGSInnovations/setProperty-strict-encoding
Set property strict encoding
2 parents d817c10 + ccae62e commit 341d477

File tree

8 files changed

+158
-45
lines changed

8 files changed

+158
-45
lines changed

lib/interface.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,14 @@ Interface.prototype.setProperty = function(propertyName, value, callback) {
103103
return;
104104
}
105105

106+
var propSig = self.object['property'][propertyName].type;
107+
106108
self.bus.callMethod(self.bus.connection,
107109
self.serviceName,
108110
self.objectPath,
109111
'org.freedesktop.DBus.Properties',
110112
'Set',
111-
'ssv',
113+
{ type: 'ssv', concrete_type: 'ss' + propSig },
112114
-1,
113115
[ self.interfaceName, propertyName, value ],
114116
function(err) {

src/dbus.cc

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ namespace NodeDBus {
196196
// Preparing method arguments
197197
if (info[7]->IsObject()) {
198198
DBusMessageIter iter;
199-
DBusSignatureIter siter;
199+
DBusSignatureIter siter, concrete_siter;
200200

201201
Local<Array> argument_arr = Local<Array>::Cast(info[7]);
202202
if (argument_arr->Length() > 0) {
@@ -205,29 +205,71 @@ namespace NodeDBus {
205205
dbus_message_iter_init_append(message, &iter);
206206

207207
// Initializing signature
208-
char *sig = strdup(*String::Utf8Value(info[5]->ToString()));
208+
char *sig = NULL, *concrete_sig = NULL;
209+
if (info[5]->IsObject())
210+
{
211+
Local<Object> obj(info[5]->ToObject());
212+
213+
Local<Value> typeKey(Nan::New("type").ToLocalChecked());
214+
Nan::MaybeLocal<Value> mb_sig(Nan::Get(obj, typeKey));
215+
sig = strdup(*String::Utf8Value(mb_sig.ToLocalChecked()->ToString()));
216+
217+
Local<Value> concreteTypeKey(Nan::New("concrete_type").ToLocalChecked());
218+
Nan::MaybeLocal<Value> mb_concrete_sig(Nan::Get(obj, concreteTypeKey));
219+
Local<Value> concrete_sig_value;
220+
if (mb_concrete_sig.ToLocal(&concrete_sig_value))
221+
{
222+
concrete_sig = strdup(*String::Utf8Value(concrete_sig_value->ToString()));
223+
}
224+
}
225+
else
226+
{
227+
sig = strdup(*String::Utf8Value(info[5]->ToString()));
228+
}
229+
230+
if (concrete_sig == NULL) {
231+
concrete_sig = strdup(sig);
232+
}
233+
209234
if (!dbus_signature_validate(sig, &error)) {
210235
return Nan::ThrowError(error.message);
211236
}
212237

238+
if (!dbus_signature_validate(concrete_sig, &error)) {
239+
return Nan::ThrowError(error.message);
240+
}
241+
213242
// Getting all signatures
214243
dbus_signature_iter_init(&siter, sig);
244+
dbus_signature_iter_init(&concrete_siter, concrete_sig);
215245
for (unsigned int i = 0; i < argument_arr->Length(); ++i) {
216246
char *arg_sig = dbus_signature_iter_get_signature(&siter);
247+
char *arg_concrete_sig = dbus_signature_iter_get_signature(&concrete_siter);
248+
249+
DBusSignatureIter item_siter, item_concrete_siter;
217250
Local<Value> arg = argument_arr->Get(i);
218251

219-
if (!Encoder::EncodeObject(arg, &iter, arg_sig)) {
252+
dbus_signature_iter_init(&item_siter, arg_sig);
253+
dbus_signature_iter_init(&item_concrete_siter, arg_concrete_sig);
254+
255+
if (!Encoder::EncodeObject(arg, &iter, &item_siter, &item_concrete_siter)) {
220256
dbus_free(arg_sig);
257+
dbus_free(arg_concrete_sig);
221258
break;
222259
}
223260

224261
dbus_free(arg_sig);
262+
dbus_free(arg_concrete_sig);
225263

226264
if (!dbus_signature_iter_next(&siter))
227265
break;
266+
267+
if (!dbus_signature_iter_next(&concrete_siter))
268+
break;
228269
}
229270

230271
dbus_free(sig);
272+
dbus_free(concrete_sig);
231273
}
232274
}
233275

src/encoder.cc

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -151,17 +151,23 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
151151
return "";
152152
}
153153

154-
bool EncodeObject(Local<Value> value, DBusMessageIter *iter, const char *signature)
154+
bool EncodeObject(Local<Value> value, DBusMessageIter *iter,
155+
const DBusSignatureIter *siter,
156+
const DBusSignatureIter *concreteSiter)
155157
{
156158
// printf("EncodeObject %s\n",signature);
157159
// printf("%p", value);
158160
Nan::HandleScope scope;
159-
DBusSignatureIter siter;
160161
int type;
162+
163+
if (concreteSiter == NULL)
164+
{
165+
// this is safe because we never modify siter
166+
concreteSiter = siter;
167+
}
161168

162169
// Get type of current value
163-
dbus_signature_iter_init(&siter, signature);
164-
type = dbus_signature_iter_get_current_type(&siter);
170+
type = dbus_signature_iter_get_current_type(siter);
165171

166172
switch(type) {
167173
case DBUS_TYPE_INVALID:
@@ -315,11 +321,12 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
315321
}
316322

317323
DBusMessageIter subIter;
318-
DBusSignatureIter arraySiter;
324+
DBusSignatureIter arraySiter, arrayConcreteSiter;
319325
char *array_sig = NULL;
320326

321327
// Getting signature of array object
322-
dbus_signature_iter_recurse(&siter, &arraySiter);
328+
dbus_signature_iter_recurse(siter, &arraySiter);
329+
dbus_signature_iter_recurse(concreteSiter, &arrayConcreteSiter);
323330
array_sig = dbus_signature_iter_get_signature(&arraySiter);
324331

325332
// Open array container to process elements in there
@@ -328,27 +335,24 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
328335
printf("Can't open container for Array type\n");
329336
return false;
330337
}
338+
dbus_free(array_sig);
331339

332340
// It's a dictionary
333-
if (dbus_signature_iter_get_element_type(&siter) == DBUS_TYPE_DICT_ENTRY) {
334-
335-
dbus_free(array_sig);
336-
341+
if (dbus_signature_iter_get_element_type(siter) == DBUS_TYPE_DICT_ENTRY) {
337342
Local<Object> value_object = value->ToObject();
338-
DBusSignatureIter dictSubSiter;
339-
340-
// Getting sub-signature object
341-
dbus_signature_iter_recurse(&arraySiter, &dictSubSiter);
342-
dbus_signature_iter_next(&dictSubSiter);
343-
char *sig = dbus_signature_iter_get_signature(&dictSubSiter);
344343

345344
// process each elements
346345
Local<Array> prop_names = value_object->GetPropertyNames();
347346
unsigned int len = prop_names->Length();
348347

349348
bool failed = false;
350349
for (unsigned int i = 0; i < len; ++i) {
350+
DBusSignatureIter dictSubSiter, dictSubConcreteSiter;
351351
DBusMessageIter dict_iter;
352+
353+
// Getting sub-signature object
354+
dbus_signature_iter_recurse(&arraySiter, &dictSubSiter);
355+
dbus_signature_iter_recurse(&arrayConcreteSiter, &dictSubConcreteSiter);
352356

353357
// Open dict entry container
354358
if (!dbus_message_iter_open_container(&subIter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter)) {
@@ -362,13 +366,17 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
362366
Local<Value> prop_value = value_object->Get(prop_key);
363367

364368
// Append the key
365-
char *prop_key_str = strdup(*String::Utf8Value(prop_key->ToString()));
366-
// printf("key: %s\n", prop_key_str);
367-
dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &prop_key_str);
368-
dbus_free(prop_key_str);
369+
if (!EncodeObject(prop_key, &dict_iter, &dictSubSiter, &dictSubConcreteSiter)) {
370+
dbus_message_iter_close_container(&subIter, &dict_iter);
371+
printf("Failed to encode element of dictionary\n");
372+
failed = true;
373+
break;
374+
}
369375

370376
// Append the value
371-
if (!EncodeObject(prop_value, &dict_iter, sig)) {
377+
dbus_signature_iter_next(&dictSubSiter);
378+
dbus_signature_iter_next(&dictSubConcreteSiter);
379+
if (!EncodeObject(prop_value, &dict_iter, &dictSubSiter, &dictSubConcreteSiter)) {
372380
dbus_message_iter_close_container(&subIter, &dict_iter);
373381
printf("Failed to encode element of dictionary\n");
374382
failed = true;
@@ -378,7 +386,6 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
378386
dbus_message_iter_close_container(&subIter, &dict_iter);
379387
}
380388

381-
dbus_free(sig);
382389
dbus_message_iter_close_container(iter, &subIter);
383390

384391
if (failed)
@@ -396,42 +403,54 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
396403
Local<Array> arrayData = Local<Array>::Cast(value);
397404
for (unsigned int i = 0; i < arrayData->Length(); ++i) {
398405
Local<Value> arrayItem = arrayData->Get(i);
399-
if (!EncodeObject(arrayItem, &subIter, array_sig))
406+
if (!EncodeObject(arrayItem, &subIter, &arraySiter, &arrayConcreteSiter))
400407
break;
401408
}
402409

403410
dbus_message_iter_close_container(iter, &subIter);
404-
dbus_free(array_sig);
405411

406412
break;
407413
}
408414

409415
case DBUS_TYPE_VARIANT:
410416
{
411417
DBusMessageIter subIter;
412-
413-
string str_sig = GetSignatureFromV8Type(value);
414-
const char *var_sig = str_sig.c_str();
418+
DBusSignatureIter subSiter;
419+
420+
char *var_sig;
421+
if (dbus_signature_iter_get_current_type(concreteSiter) == DBUS_TYPE_VARIANT)
422+
{
423+
string str_sig = GetSignatureFromV8Type(value);
424+
var_sig = strdup(str_sig.c_str());
425+
}
426+
else
427+
{
428+
var_sig = dbus_signature_iter_get_signature(concreteSiter);
429+
}
415430

416431
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_sig, &subIter)) {
432+
dbus_free(var_sig);
417433
printf("Can't open container for VARIANT type\n");
418434
return false;
419435
}
420436

421-
if (!EncodeObject(value, &subIter, var_sig)) {
437+
dbus_signature_iter_init(&subSiter, var_sig);
438+
if (!EncodeObject(value, &subIter, &subSiter, &subSiter)) {
422439
dbus_message_iter_close_container(iter, &subIter);
440+
dbus_free(var_sig);
423441
return false;
424442
}
425443

426444
dbus_message_iter_close_container(iter, &subIter);
445+
dbus_free(var_sig);
427446

428447
break;
429448
}
430449
case DBUS_TYPE_STRUCT:
431450
{
432451
// printf("struct\n");
433452
DBusMessageIter subIter;
434-
DBusSignatureIter structSiter;
453+
DBusSignatureIter structSiter, structConcreteSiter;
435454

436455
// Open array container to process elements in there
437456
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &subIter)) {
@@ -442,28 +461,27 @@ typedef bool (*CheckTypeCallback) (Local<Value>& value, const char* sig);
442461
Local<Object> value_object = value->ToObject();
443462

444463
// Getting sub-signature object
445-
dbus_signature_iter_recurse(&siter, &structSiter);
464+
dbus_signature_iter_recurse(siter, &structSiter);
465+
dbus_signature_iter_recurse(concreteSiter, &structConcreteSiter);
446466

447467
// process each elements
448468
Local<Array> prop_names = value_object->GetPropertyNames();
449469
unsigned int len = prop_names->Length();
450470

451471
for (unsigned int i = 0; i < len; ++i) {
452472

453-
char *sig = dbus_signature_iter_get_signature(&structSiter);
454-
455473
Local<Value> prop_key = prop_names->Get(i);
456474

457-
if (!EncodeObject(value_object->Get(prop_key), &subIter, sig)) {
458-
dbus_free(sig);
475+
if (!EncodeObject(value_object->Get(prop_key), &subIter, &structSiter, &structConcreteSiter)) {
459476
printf("Failed to encode element of dictionary\n");
460477
return false;
461478
}
462479

463-
dbus_free(sig);
464-
465480
if (!dbus_signature_iter_next(&structSiter))
466481
break;
482+
483+
if (!dbus_signature_iter_next(&structConcreteSiter))
484+
break;
467485
}
468486

469487
dbus_message_iter_close_container(iter, &subIter);

src/encoder.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ namespace Encoder {
88
using namespace std;
99

1010
string GetSignatureFromV8Type(Local<Value>& value);
11-
bool EncodeObject(Local<Value> value, DBusMessageIter *iter, const char *signature);
11+
12+
// expects two signatures - one for the type signature as DBus will see it,
13+
// and a second that is the same as the first, except that variants requiring
14+
// a particular concrete type inside should be replaced by their required concrete type.
15+
//
16+
// for example, when writing a property, the property value in the Get method is
17+
// a variant at the DBus interface level, but should only actually be encoded with
18+
// the actual concrete type declared for the property.
19+
//
20+
// If the concrete type is NULL or the same as the main one, types of variant
21+
// elements will be inferred based on the V8 type (and, in the case of numbers,
22+
// their values)
23+
bool EncodeObject(Local<Value> value, DBusMessageIter *iter,
24+
const DBusSignatureIter *siter, const DBusSignatureIter *concreteSiter = NULL);
1225
}
1326

1427
#endif

src/object_handler.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,15 @@ namespace ObjectHandler {
7777
{
7878
Nan::HandleScope scope;
7979
DBusMessageIter iter;
80+
DBusSignatureIter siter;
8081
DBusMessage *reply;
8182
dbus_uint32_t serial = 0;
8283

8384
reply = dbus_message_new_method_return(message);
8485

8586
dbus_message_iter_init_append(reply, &iter);
86-
if (!Encoder::EncodeObject(reply_value, &iter, signature)) {
87+
dbus_signature_iter_init(&siter, signature);
88+
if (!Encoder::EncodeObject(reply_value, &iter, &siter)) {
8789
printf("Failed to encode reply value\n");
8890
}
8991

src/signal.cc

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ namespace Signal {
4141
}
4242

4343
NAN_METHOD(EmitSignal) {
44+
DBusError error;
45+
4446
if (!info[0]->IsObject()) {
4547
return Nan::ThrowTypeError("First parameter must be an object");
4648
}
@@ -80,6 +82,9 @@ namespace Signal {
8082
char *signal = strdup(*String::Utf8Value(info[3]->ToString()));
8183
message = dbus_message_new_signal(path, interface, signal);
8284

85+
// Initializing error handler
86+
dbus_error_init(&error);
87+
8388
// Preparing message
8489
dbus_message_iter_init_append(message, &iter);
8590

@@ -88,10 +93,15 @@ namespace Signal {
8893
Local<Array> signatures = Local<Array>::Cast(info[5]);
8994
for (unsigned int i = 0; i < arguments->Length(); ++i) {
9095
Local<Value> arg = arguments->Get(i);
91-
96+
DBusSignatureIter siter;
97+
9298
char *sig = strdup(*String::Utf8Value(signatures->Get(i)->ToString()));
93-
94-
if (!Encoder::EncodeObject(arg, &iter, sig)) {
99+
if (!dbus_signature_validate(sig, &error)) {
100+
return Nan::ThrowError(error.message);
101+
}
102+
103+
dbus_signature_iter_init(&siter, sig);
104+
if (!Encoder::EncodeObject(arg, &iter, &siter)) {
95105
dbus_free(sig);
96106
printf("Failed to encode arguments of signal\n");
97107
break;

0 commit comments

Comments
 (0)