GVariant* js_to_dbus(JSContextRef ctx, const JSValueRef jsvalue, const GVariantType* sig, JSValueRef *exception) { if (g_variant_type_is_array(sig)) { GVariantBuilder builder; g_variant_builder_init(&builder, sig); JSPropertyNameArrayRef array = JSObjectCopyPropertyNames(ctx, (JSObjectRef)jsvalue); const GVariantType* child_sig = g_variant_type_element(sig); if (g_variant_type_is_dict_entry(child_sig)) { const GVariantType* key_sig = g_variant_type_first(child_sig); const GVariantType* value_sig = g_variant_type_next(key_sig); for (size_t i=0; i < JSPropertyNameArrayGetCount(array); i++) { if (filter_function_child(ctx, jsvalue, i)) continue; g_variant_builder_open(&builder, child_sig); JSValueRef key = JSValueMakeString(ctx, JSPropertyNameArrayGetNameAtIndex(array, i)); JSValueRef value = JSObjectGetPropertyAtIndex(ctx, (JSObjectRef)jsvalue, i, NULL); g_variant_builder_add_value(&builder, js_to_dbus(ctx, key, key_sig, exception)); g_variant_builder_add_value(&builder, js_to_dbus(ctx, value, value_sig, exception)); g_variant_builder_close(&builder); } return g_variant_builder_end(&builder); } else { GVariantBuilder builder; g_variant_builder_init(&builder, sig); JSPropertyNameArrayRef array = JSObjectCopyPropertyNames(ctx, (JSObjectRef)jsvalue); const GVariantType* child_sig = g_variant_type_element(sig); for (size_t i=0; i < JSPropertyNameArrayGetCount(array); i++) { if (filter_array_child(ctx, array, i)) continue; g_variant_builder_add_value(&builder, js_to_dbus(ctx, JSObjectGetPropertyAtIndex(ctx, (JSObjectRef)jsvalue, i, NULL), child_sig, exception)); } JSPropertyNameArrayRelease(array); return g_variant_builder_end(&builder); } } else if (g_variant_type_is_tuple(sig)) { GVariantBuilder builder; g_variant_builder_init(&builder, sig); JSPropertyNameArrayRef array = JSObjectCopyPropertyNames(ctx, (JSObjectRef)jsvalue); const GVariantType* current_sig = g_variant_type_first(sig); for (size_t i=0; i < JSPropertyNameArrayGetCount(array); i++) { if (filter_array_child(ctx, array, i)) continue; g_variant_builder_add_value(&builder, js_to_dbus(ctx, JSObjectGetPropertyAtIndex(ctx, (JSObjectRef)jsvalue, i, NULL), current_sig, exception)); current_sig = g_variant_type_next(current_sig); } JSPropertyNameArrayRelease(array); return g_variant_builder_end(&builder); } else { switch (g_variant_type_peek_string(sig)[0]) { case 'y': return g_variant_new_byte(JSValueToNumber(ctx, jsvalue, exception)); case 'n': return g_variant_new_int16(JSValueToNumber(ctx, jsvalue, exception)); case 'q': return g_variant_new_uint16(JSValueToNumber(ctx, jsvalue, exception)); case 'i': return g_variant_new_int32(JSValueToNumber(ctx, jsvalue, exception)); case 'u': return g_variant_new_uint32(JSValueToNumber(ctx, jsvalue, exception)); case 'x': return g_variant_new_int64(JSValueToNumber(ctx, jsvalue, exception)); case 't': return g_variant_new_uint64(JSValueToNumber(ctx, jsvalue, exception)); case 'd': return g_variant_new_double(JSValueToNumber(ctx, jsvalue, exception)); case 'h': return g_variant_new_handle(JSValueToNumber(ctx, jsvalue, exception)); case 'b': return g_variant_new_boolean(JSValueToBoolean(ctx, jsvalue)); case 's': { char* v = jsvalue_to_cstr(ctx, jsvalue); GVariant* r = g_variant_new_string(v); g_free(v); return r; } case 'v': { //TODO: /*g_variant_new_variant()*/ g_assert_not_reached(); } } } g_assert_not_reached(); }
gboolean js_to_dbus(JSContextRef ctx, const JSValueRef jsvalue, DBusMessageIter *iter, const char* sig, JSValueRef* exception) { DBusSignatureIter s_iter; dbus_signature_iter_init(&s_iter, sig); int type; switch (type = dbus_signature_iter_get_current_type(&s_iter)) { case DBUS_TYPE_BOOLEAN: { dbus_bool_t value = JSValueToBoolean(ctx, jsvalue); if (!dbus_message_iter_append_basic(iter, type, (void*)&value)) { g_warning("signatuer:%c error!", type); return FALSE; } else { return TRUE; } } case DBUS_TYPE_DOUBLE: CASE_NUMBER { if (!JSValueIsNumber(ctx, jsvalue)) { js_fill_exception(ctx, exception, "jsvalue is not an number!"); return FALSE; } double value = JSValueToNumber(ctx, jsvalue, NULL); if (!dbus_message_iter_append_basic(iter, type, (void*)&value)) { g_warning("signatuer:%c error!", type); return FALSE; } else { return TRUE; } } CASE_STRING { char* value = jsvalue_to_cstr(ctx, jsvalue); if (value == NULL || !dbus_message_iter_append_basic(iter, type, (void*)&value)) { g_free(value); js_fill_exception(ctx, exception, "jsvalue is not an string or memory not enough!"); return FALSE; } else { g_free(value); return TRUE; } } case DBUS_TYPE_STRUCT: { if (!jsvalue_instanceof(ctx, jsvalue, "Array")) { js_fill_exception(ctx, exception, "jsvalue should an array"); return FALSE; } JSPropertyNameArrayRef prop_names = JSObjectCopyPropertyNames(ctx, (JSObjectRef)jsvalue); int p_num = JSPropertyNameArrayGetCount(prop_names); if (p_num == 0) { JSPropertyNameArrayRelease(prop_names); js_fill_exception(ctx, exception, "Struct at least have one element!"); return FALSE; } DBusMessageIter sub_iter; OPEN_CONTAINER(iter, type, NULL, &sub_iter); DBusSignatureIter sub_s_iter; dbus_signature_iter_recurse(&s_iter, &sub_s_iter); for (int i=0; i<p_num; i++) { JSValueRef value = JSObjectGetProperty(ctx, (JSObjectRef)jsvalue, JSPropertyNameArrayGetNameAtIndex(prop_names, i), NULL); char *sig = dbus_signature_iter_get_signature(&sub_s_iter); if (!js_to_dbus(ctx, value, &sub_iter, sig, exception)) { js_fill_exception(ctx, exception, "Failed append struct with sig:%sTODO"); dbus_free(sig); return FALSE; } dbus_free(sig); if (i != p_num-1 && !dbus_signature_iter_next(&sub_s_iter)) { JSPropertyNameArrayRelease(prop_names); CLOSE_CONTAINER(iter, &sub_iter); js_fill_exception(ctx, exception, "to many params filled to struct"); return FALSE; } } if (dbus_signature_iter_next(&sub_s_iter)) { JSPropertyNameArrayRelease(prop_names); CLOSE_CONTAINER(iter, &sub_iter); js_fill_exception(ctx, exception, "need more params by this struct"); return FALSE; } JSPropertyNameArrayRelease(prop_names); CLOSE_CONTAINER(iter, &sub_iter); return TRUE; } case DBUS_TYPE_ARRAY: if (dbus_signature_iter_get_element_type(&s_iter) == DBUS_TYPE_DICT_ENTRY) { DBusSignatureIter dict_s_iter; dbus_signature_iter_recurse(&s_iter, &dict_s_iter); char *d_sig = dbus_signature_iter_get_signature(&dict_s_iter); DBusMessageIter sub_iter; OPEN_CONTAINER(iter, type, d_sig, &sub_iter); dbus_free(d_sig); JSPropertyNameArrayRef prop_names = JSObjectCopyPropertyNames(ctx, (JSObjectRef)jsvalue); int p_num = JSPropertyNameArrayGetCount(prop_names); DBusSignatureIter dict_sub_s_iter; dbus_signature_iter_recurse(&dict_s_iter, &dict_sub_s_iter); int key_type = dbus_signature_iter_get_current_type(&dict_sub_s_iter); dbus_signature_iter_next(&dict_sub_s_iter); char *val_sig = dbus_signature_iter_get_signature(&dict_sub_s_iter); for (int i=0; i<p_num; i++) { DBusMessageIter dict_iter; OPEN_CONTAINER(&sub_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_iter); JSStringRef key_str = JSPropertyNameArrayGetNameAtIndex(prop_names, i); //TODO: fetch key type switch (key_type) { CASE_STRING { char *value = jsstring_to_cstr(ctx, key_str); dbus_message_iter_append_basic(&dict_iter, key_type, (void*)&value); g_free(value); break; } case DBUS_TYPE_DOUBLE: CASE_NUMBER { //TODO detect illegal number format JSValueRef excp; double value = JSValueToNumber(ctx, JSValueMakeString(ctx, key_str), &excp); if (excp != NULL) { js_fill_exception(ctx, exception, "dict_entry's key must be an number to match the signature!"); return FALSE; } dbus_message_iter_append_basic(&dict_iter, key_type, (void*)&value); break; } default: { js_fill_exception(ctx, exception, "DICT_ENTRY's key must basic type, and you should not see this warning in javascript runtime"); dbus_free(val_sig); JSPropertyNameArrayRelease(prop_names); CLOSE_CONTAINER(iter, &sub_iter); return FALSE; } } js_to_dbus(ctx, JSObjectGetProperty(ctx, (JSObjectRef)jsvalue, key_str, NULL), &dict_iter, val_sig, exception); CLOSE_CONTAINER(&sub_iter, &dict_iter); } dbus_free(val_sig); JSPropertyNameArrayRelease(prop_names); CLOSE_CONTAINER(iter, &sub_iter); return TRUE; } else {