2 * Browser D-Bus Bridge, XPCOM version
4 * Copyright © 2008 Movial Creative Technologies Inc
5 * Contact: Movial Creative Technologies Inc, <info@movial.com>
6 * Authors: Lauri Mylläri, <lauri.myllari@movial.fi>
7 * Kalle Vahlman, <kalle.vahlman@movial.com>
9 * The contents of this file are subject to the Mozilla Public License
10 * Version 1.1 (the "License"); you may not use this file except in
11 * compliance with the License. You may obtain a copy of the License at
12 * http://www.mozilla.org/MPL/
14 * Software distributed under the License is distributed on an "AS IS"
15 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
16 * License for the specific language governing rights and limitations
19 * The Original Code is the Browser D-Bus Bridge, XPCOM version.
21 * The Initial Developer of the Original Code is Movial Creative Technologies
22 * Inc. Portions created by Initial Developer are Copyright (C) 2008
23 * Movial Creative Technologies Inc. All Rights Reserved.
29 #include "nsEmbedString.h"
30 #include "nsComponentManagerUtils.h"
31 #include "nsServiceManagerUtils.h"
32 #include "nsArrayUtils.h"
34 #include "nsISupportsPrimitives.h"
35 #include "nsIProperties.h"
36 #include "nsIXPConnect.h"
38 #include "DBusMarshaling.h"
40 #include "bdb-debug.h"
42 void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
43 void addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
46 listJSObjectProperties(JSContext *cx, JSObject *js_obj)
48 JSIdArray *props = JS_Enumerate(cx, js_obj);
51 BDBLOG((" listJSObjectProperties: got JSIdArray with %i props\n", props->length));
53 for (int i = 0; i < props->length; i++)
56 const PRUnichar *name;
57 JS_IdToValue( cx, props->vector[i], &v );
58 JSString *prop_string = JS_ValueToString(cx, v);
59 name = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(prop_string));
60 nsDependentString name_s(name);
61 const char *utf8prop = NS_ConvertUTF16toUTF8(name_s).get();
62 BDBLOG((" property %s\n", utf8prop));
65 if (JS_LookupUCProperty(cx,
67 JS_GetStringChars(prop_string),
68 JS_GetStringLength(prop_string),
71 JSString *val_string = JS_ValueToString(cx, value);
72 const PRUnichar *valstr = reinterpret_cast<const PRUnichar*>(JS_GetStringChars(val_string));
73 nsDependentString val_s(valstr);
74 const char *utf8val = NS_ConvertUTF16toUTF8(val_s).get();
75 BDBLOG((" value %s\n", utf8val));
78 JS_DestroyIdArray(cx, props);
83 getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult)
85 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
87 if (JSVAL_IS_BOOLEAN(*aValue))
88 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
89 else if (JSVAL_IS_INT(*aValue))
90 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
91 else if (JSVAL_IS_DOUBLE(*aValue))
92 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
93 else if (JSVAL_IS_STRING(*aValue))
94 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
95 else if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
97 // guess element type from first property value
99 JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
102 BDBLOG((" got JSIdArray\n"));
103 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
105 // get key signature from first property name
107 nsCAutoString tmpsig;
108 JS_IdToValue(cx, props->vector[0], &propname);
111 JSString *prop_string = JS_ValueToString(cx, propname);
112 if (JS_LookupUCProperty(cx,
113 JSVAL_TO_OBJECT(*aValue),
114 JS_GetStringChars(prop_string),
115 JS_GetStringLength(prop_string),
116 &propvalue) == JS_TRUE)
118 getSignatureFromJSValue(cx, &propvalue, tmpsig);
119 aResult.Append(tmpsig);
123 // FIXME - could not find property value??
124 // assume string to keep signature valid
125 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
127 JS_DestroyIdArray(cx, props);
131 else if (JSVAL_IS_OBJECT(*aValue))
133 nsISupports* supports;
136 JSObject* glob = JSVAL_TO_OBJECT(*aValue);
138 clazz = JS_GET_CLASS(cx, JS_GetParent(cx, glob));
141 !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
142 !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
143 !(supports = (nsISupports*) JS_GetPrivate(cx, glob))) {
145 BDBLOG((" getSignatureFromJSValue: could not find nsISupports inside object, assume dictionary\n"));
147 // try to enumerate object properties
148 JSIdArray *props = JS_Enumerate(cx, glob);
151 BDBLOG((" got JSIdArray with %i props\n", props->length));
152 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
153 aResult.Append(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
155 // get key signature from first property name
157 nsCAutoString tmpsig;
158 JS_IdToValue(cx, props->vector[0], &propname);
159 getSignatureFromJSValue(cx, &propname, tmpsig);
160 aResult.Append(tmpsig);
163 JSString *prop_string = JS_ValueToString(cx, propname);
164 if (JS_LookupUCProperty(cx,
166 JS_GetStringChars(prop_string),
167 JS_GetStringLength(prop_string),
168 &propvalue) == JS_TRUE)
170 getSignatureFromJSValue(cx, &propvalue, tmpsig);
171 aResult.Append(tmpsig);
175 // FIXME - could not find property value??
176 // assume string to keep signature valid
177 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
179 aResult.Append(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
180 JS_DestroyIdArray(cx, props);
186 BDBLOG((" getSignatureFromJSValue: clazz->name %s\n", clazz->name));
187 // test argument for nsIXPConnectWrappedNative
188 nsCOMPtr<nsIXPConnectWrappedNative> wrappednative = do_QueryInterface(supports);
191 BDBLOG((" getSignatureFromJSValue: got nsIXPConnectWrappedNative\n"));
192 nsCOMPtr<nsIVariant> variant = do_QueryInterface(wrappednative->Native());
195 BDBLOG((" found wrapped variant\n"));
196 getSignatureFromVariant(variant, aResult);
200 // use string type as fallback
201 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
209 getSignatureFromVariantType(PRUint16 aType, nsCString &aResult)
212 case nsIDataType::VTYPE_BOOL:
213 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
215 case nsIDataType::VTYPE_INT8: /* FIXME - check sign issues;
216 dbus supports only unsigned 8bit */
217 case nsIDataType::VTYPE_UINT8:
218 aResult.Assign(DBUS_TYPE_BYTE_AS_STRING);
220 case nsIDataType::VTYPE_INT16:
221 aResult.Assign(DBUS_TYPE_INT16_AS_STRING);
223 case nsIDataType::VTYPE_UINT16:
224 aResult.Assign(DBUS_TYPE_UINT16_AS_STRING);
226 case nsIDataType::VTYPE_INT32:
227 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
229 case nsIDataType::VTYPE_UINT32:
230 aResult.Assign(DBUS_TYPE_UINT32_AS_STRING);
232 case nsIDataType::VTYPE_INT64:
233 aResult.Assign(DBUS_TYPE_INT64_AS_STRING);
235 case nsIDataType::VTYPE_UINT64:
236 aResult.Assign(DBUS_TYPE_UINT64_AS_STRING);
238 case nsIDataType::VTYPE_DOUBLE:
239 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
241 case nsIDataType::VTYPE_VOID:
242 // FIXME - assume that string is the best representation
243 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
244 case nsIDataType::VTYPE_WCHAR_STR:
245 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
248 BDBLOG((" getSignatureFromVariantType: %d not a simple type\n", aType));
249 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
254 getSignatureFromVariant(nsIVariant *aVariant, nsCString &aResult)
256 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
259 aVariant->GetDataType(&dataType);
262 case nsIDataType::VTYPE_VOID:
263 case nsIDataType::VTYPE_BOOL:
264 case nsIDataType::VTYPE_INT8:
265 case nsIDataType::VTYPE_UINT8:
266 case nsIDataType::VTYPE_INT16:
267 case nsIDataType::VTYPE_UINT16:
268 case nsIDataType::VTYPE_INT32:
269 case nsIDataType::VTYPE_UINT32:
270 case nsIDataType::VTYPE_INT64:
271 case nsIDataType::VTYPE_UINT64:
272 case nsIDataType::VTYPE_DOUBLE:
273 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
274 case nsIDataType::VTYPE_WCHAR_STR:
277 aVariant->GetAsUint32(&val);
278 BDBLOG((" getSignatureFromVariant: simple type %i:%i\n", dataType, val));
279 getSignatureFromVariantType(dataType, aResult);
282 case nsIDataType::VTYPE_ARRAY:
284 BDBLOG((" getSignatureFromVariant: array\n"));
286 // need to recurse into array
290 void *data_ptr = nsnull;
292 aVariant->GetAsArray(&type,
297 BDBLOG((" getSignatureFromVariant: got %d elements of type %d\n", count, type));
299 nsCAutoString elementsig;
301 if (type == nsIDataType::VTYPE_INTERFACE_IS)
303 // get element signature from first element
304 nsISupports *element = ((nsISupports **)data_ptr)[0];
305 getSignatureFromISupports(element, elementsig);
307 else if (type == nsIDataType::VTYPE_ARRAY)
309 // FIXME - can this happen?
310 BDBLOG((" element type array, don't know how to handle\n"));
314 getSignatureFromVariantType(type, elementsig);
317 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
318 aResult.Append(elementsig);
320 nsMemory::Free(data_ptr);
323 case nsIDataType::VTYPE_INTERFACE_IS:
325 BDBLOG((" getSignatureFromVariant: interface\n"));
326 nsCOMPtr<nsISupports> is;
328 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
329 getSignatureFromISupports(is, aResult);
334 BDBLOG((" getSignatureFromVariant: unknown type %d\n", dataType));
341 getSignatureFromISupports(nsISupports *aISupports, nsCString &aResult)
343 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
345 // test argument for nsIVariant
346 nsCOMPtr<nsIVariant> variant = do_QueryInterface(aISupports);
349 BDBLOG((" getSignatureFromISupports: nsIVariant\n"));
350 getSignatureFromVariant(variant, aResult);
354 // test argument for nsIXPConnectWrappedJS
355 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aISupports);
358 BDBLOG((" getSignatureFromISupports: nsIXPConnectWrappedJS\n"));
359 JSObject *js_obj = nsnull;
360 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
362 // try to get a JS context (code borrowed from xpcsample1.cpp)
364 // get the xpconnect service
366 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
369 BDBLOG((" got nsIXPConnect\n"));
371 // get the xpconnect native call context
372 nsAXPCNativeCallContext *callContext = nsnull;
373 xpc->GetCurrentNativeCallContext(&callContext);
377 // Get JSContext of current call
379 rv = callContext->GetJSContext(&cx);
380 if(NS_FAILED(rv) || !cx)
382 BDBLOG((" got JSContext\n"));
384 jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
385 getSignatureFromJSValue(cx, &obj_as_jsval, aResult);
391 addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
393 char *element_signature = dbus_signature_iter_get_signature(aSigIter);
394 int element_type = dbus_signature_iter_get_current_type(aSigIter);
396 PRUint16 variant_type;
397 aVariant->GetDataType(&variant_type);
399 BDBLOG(("addVariantToIter: signature \"%s\", type %c, variant type: %i\n",
404 if (dbus_type_is_basic(element_type))
406 BDBLOG((" add basic type from variant\n"));
407 addBasicTypeToIter(aVariant, aIter, element_type);
409 else if (element_type == DBUS_TYPE_ARRAY)
411 if (dbus_signature_iter_get_element_type(aSigIter) == DBUS_TYPE_DICT_ENTRY)
413 /* TODO: Support for non-JS Dicts */
415 BDBLOG((" add dict from variant\n"));
417 nsCOMPtr<nsISupports> is;
419 // Reported by a leak, dunno why?
420 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
422 // test argument for nsIXPConnectWrappedJS
423 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(is);
426 BDBLOG((" Found XPConnect object\n"));
427 JSObject *js_obj = nsnull;
428 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
430 // try to get a JS context (code borrowed from xpcsample1.cpp)
432 // get the xpconnect service
434 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
437 BDBLOG((" got nsIXPConnect\n"));
439 // get the xpconnect native call context
440 nsAXPCNativeCallContext *callContext = nsnull;
441 xpc->GetCurrentNativeCallContext(&callContext);
445 // Get JSContext of current call
447 rv = callContext->GetJSContext(&cx);
448 if(NS_FAILED(rv) || !cx)
450 BDBLOG((" got JSContext\n"));
452 jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
454 // try to enumerate object properties
455 JSIdArray *props = JS_Enumerate(cx, js_obj);
458 BDBLOG((" got JSIdArray with %i props\n", props->length));
460 // Start the array container
461 DBusMessageIter childIter;
462 DBusSignatureIter childSigIter;
463 DBusSignatureIter dictSigIter;
464 dbus_signature_iter_recurse(aSigIter, &childSigIter);
465 dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
466 dbus_signature_iter_get_signature(&childSigIter),
469 // Skip the dict signature iter to the value type
470 dbus_signature_iter_recurse(&childSigIter, &dictSigIter);
471 dbus_signature_iter_next(&dictSigIter); // key type
473 for (int p = 0; p < props->length; p++)
475 // get key signature from first property name
477 nsCAutoString tmpsig;
478 JS_IdToValue(cx, props->vector[p], &propname);
480 // Start the dict container
481 DBusMessageIter dictIter;
482 dbus_message_iter_open_container(&childIter, DBUS_TYPE_DICT_ENTRY,
485 JSString *prop_string = JS_ValueToString(cx, propname);
486 const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
487 JS_GetStringLength(prop_string)).get();
488 // TODO: we only use strings as keys currently, although
489 // the spec allows any basic type to be a key and we
490 // probably *could* use the property index.
491 dbus_message_iter_append_basic(&dictIter,
496 if (JS_LookupUCProperty(cx,
498 JS_GetStringChars(prop_string),
499 JS_GetStringLength(prop_string),
500 &propvalue) == JS_TRUE)
502 addJSValueToIter(cx, &propvalue, &dictIter, &dictSigIter);
505 // Close the dict entry container
506 dbus_message_iter_close_container(&childIter, &dictIter);
509 // Close the array container
510 dbus_message_iter_close_container(aIter, &childIter);
512 JS_DestroyIdArray(cx, props);
517 BDBLOG((" add array from variant\n"));
519 // need to recurse into array
523 void *data_ptr = nsnull;
525 DBusSignatureIter aChildSigIter;
526 dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
528 char *array_signature = dbus_signature_iter_get_signature(&aChildSigIter);
530 aVariant->GetAsArray(&type,
535 BDBLOG((" getSignatureFromVariant: got %d elements of type %d\n", count, type));
536 BDBLOG((" getSignatureFromVariant: got array signature %s\n", array_signature));
538 DBusMessageIter arrayIter;
539 if (dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
540 array_signature, &arrayIter))
542 addArrayDataToIter(data_ptr, count, type, &arrayIter, &aChildSigIter);
543 dbus_message_iter_close_container(aIter, &arrayIter);
546 nsMemory::Free(data_ptr);
549 else if (element_type == DBUS_TYPE_STRUCT)
551 BDBLOG((" add struct from variant\n"));
555 BDBLOG((" unhandled\n"));
558 dbus_free(element_signature);
562 int is_valid_path (const char *path)
564 const char *cur = path;
565 const char *prev = cur;
567 if (strlen(path) == 0)
570 /* MUST begin with zero */
574 /* The path is guranteed to be null-terminated */
577 /* Two slashes can't be together */
578 if (*cur == '/' && *prev == '/')
581 } else if (!(((*cur) >= '0' && (*cur) <= '9') ||
582 ((*cur) >= 'A' && (*cur) <= 'Z') ||
583 ((*cur) >= 'a' && (*cur) <= 'z') ||
584 (*cur) == '_' || (*cur) == '/')) {
595 void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType)
599 aVariant->GetDataType(&dataType);
601 /* If we got passed an nsISupports, query the variant iface from it and recurse */
602 if (dataType == nsIDataType::VTYPE_INTERFACE_IS)
604 nsCOMPtr<nsISupports> is;
606 if (NS_FAILED(aVariant->GetAsInterface(&iid, getter_AddRefs(is))))
609 nsCOMPtr<nsIVariant> myVariant = do_QueryInterface(is);
611 addBasicTypeToIter(myVariant, aIter, aDBusType);
618 case DBUS_TYPE_BOOLEAN:
621 if (NS_FAILED(aVariant->GetAsBool(&val)))
623 BDBLOG((" arg : BOOLEAN %s\n", val ? "true" : "false"));
624 dbus_message_iter_append_basic(aIter,
630 case DBUS_TYPE_INT16:
631 case DBUS_TYPE_UINT16:
632 case DBUS_TYPE_INT32:
633 case DBUS_TYPE_UINT32:
636 if (NS_FAILED(aVariant->GetAsUint32(&val)))
639 BDBLOG((" arg : INT(8|16|32) (%c) %d:%d\n", aDBusType, dataType, val));
640 dbus_message_iter_append_basic(aIter,
645 case DBUS_TYPE_INT64:
648 if (NS_FAILED(aVariant->GetAsInt64(&val)))
650 BDBLOG((" arg : INT64 %lld\n", val));
651 dbus_message_iter_append_basic(aIter,
656 case DBUS_TYPE_UINT64:
659 if (NS_FAILED(aVariant->GetAsUint64(&val)))
661 BDBLOG((" arg : UINT64 %llu\n", val));
662 dbus_message_iter_append_basic(aIter,
667 case DBUS_TYPE_DOUBLE:
670 if (NS_FAILED(aVariant->GetAsDouble(&val)))
672 BDBLOG((" arg : DOUBLE (%c) %f\n", aDBusType, val));
673 dbus_message_iter_append_basic(aIter,
678 case DBUS_TYPE_STRING:
679 case DBUS_TYPE_OBJECT_PATH:
680 case DBUS_TYPE_SIGNATURE:
682 /* FIXME - handle utf-8 conversion */
685 if (NS_FAILED(aVariant->GetAsAUTF8String(val)))
688 val_ptr = PromiseFlatCString(val).get();
689 BDBLOG((" arg : STRING '%s'\n", val_ptr));
690 if (aDBusType == DBUS_TYPE_OBJECT_PATH
691 && !is_valid_path(val_ptr))
694 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
699 BDBLOG((" addBasicTypeToIter: unhandled DBus type %d!\n", aDBusType));
705 void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
707 int aDBusType = dbus_signature_iter_get_current_type(aSigIter);
708 BDBLOG(("addArrayDataToIter: appending %d elements of type %d '%c'\n", count, type, aDBusType));
713 for (int i = 0; i < count; i++) \
714 dbus_message_iter_append_basic(aIter, aDBusType, data+i)
715 case nsIDataType::VTYPE_INT8:
716 case nsIDataType::VTYPE_UINT8:
718 char *data = (char *)data_ptr;
722 case nsIDataType::VTYPE_INT16:
723 case nsIDataType::VTYPE_UINT16:
725 PRInt16 *data = (PRInt16 *)data_ptr;
729 case nsIDataType::VTYPE_INT32:
730 case nsIDataType::VTYPE_UINT32:
732 PRInt32 *data = (PRInt32 *)data_ptr;
736 case nsIDataType::VTYPE_INT64:
737 case nsIDataType::VTYPE_UINT64:
739 PRInt64 *data = (PRInt64 *)data_ptr;
743 case nsIDataType::VTYPE_DOUBLE:
745 double *data = (double *)data_ptr;
749 case nsIDataType::VTYPE_WCHAR_STR:
751 PRUnichar **data = (PRUnichar **)data_ptr;
752 for (int i = 0; i < count; i++)
755 nsCAutoString val = NS_ConvertUTF16toUTF8(data[i]);
757 val_ptr = PromiseFlatCString(val).get();
758 BDBLOG((" arg : STRING '%s'\n", val_ptr));
759 if (aDBusType == DBUS_TYPE_OBJECT_PATH
760 && !is_valid_path(val_ptr))
763 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
767 case nsIDataType::VTYPE_INTERFACE_IS:
769 nsISupports **data = (nsISupports **)data_ptr;
770 for (int i = 0; i < count; i++)
772 nsCOMPtr<nsIVariant> data_variant = do_QueryInterface(data[i]);
774 addVariantToIter(data_variant, aIter, aSigIter);
776 BDBLOG((" interface not nsIVariant\n"));
782 BDBLOG(("addArrayDataToIter: unhandled array data type %d\n", type));
790 addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
793 int dbusType = dbus_signature_iter_get_current_type(aSigIter);
795 BDBLOG(("%s(%c, %s)\n", __FUNCTION__, dbusType,
796 dbus_signature_iter_get_signature(aSigIter)));
798 // Using the expected type instead of the actual allows autoconversion
801 case DBUS_TYPE_BOOLEAN:
804 if (JS_ValueToBoolean(cx, *aValue, &b))
806 dbus_message_iter_append_basic(aIter, DBUS_TYPE_BOOLEAN, &b);
810 BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
817 case DBUS_TYPE_INT16:
818 case DBUS_TYPE_UINT16:
819 case DBUS_TYPE_INT32:
820 case DBUS_TYPE_UINT32:
821 case DBUS_TYPE_INT64:
822 case DBUS_TYPE_UINT64:
823 case DBUS_TYPE_DOUBLE:
827 if (JS_ValueToNumber(cx, *aValue, &d))
829 dbus_message_iter_append_basic(aIter, dbusType, &d);
833 BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
838 case DBUS_TYPE_STRING:
839 case DBUS_TYPE_OBJECT_PATH:
840 case DBUS_TYPE_SIGNATURE:
842 JSString *prop_string = JS_ValueToString(cx, *aValue);
843 const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
844 JS_GetStringLength(prop_string)).get();
845 dbus_message_iter_append_basic(aIter, dbusType, &cstr);
848 case DBUS_TYPE_ARRAY:
850 if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
852 JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
855 BDBLOG((" got JSIdArray\n"));
858 DBusSignatureIter arraySigIter;
859 dbus_signature_iter_recurse(aSigIter, &arraySigIter);
860 char *array_sig = dbus_signature_iter_get_signature(&arraySigIter);
862 DBusMessageIter arrayIter;
863 dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
864 array_sig, &arrayIter);
865 dbus_free(array_sig);
867 for (int p = 0; p < props->length; p++)
869 int type = dbus_signature_iter_get_current_type(&arraySigIter);
871 JS_IdToValue(cx, props->vector[p], &propname);
874 JSString *prop_string = JS_ValueToString(cx, propname);
875 if (JS_LookupUCProperty(cx,
876 JSVAL_TO_OBJECT(*aValue),
877 JS_GetStringChars(prop_string),
878 JS_GetStringLength(prop_string),
879 &propvalue) == JS_TRUE)
881 addJSValueToIter(cx, &propvalue, &arrayIter, &arraySigIter);
886 dbus_signature_iter_next(&arraySigIter);
889 dbus_message_iter_close_container(aIter, &arrayIter);
890 JS_DestroyIdArray(cx, props);
897 BDBLOG(("Don't know how to convert type '%c'\n", dbus_signature_iter_get_current_type(aSigIter)));
902 void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v)
907 case DBUS_TYPE_STRING:
908 case DBUS_TYPE_OBJECT_PATH:
909 case DBUS_TYPE_SIGNATURE:
912 dbus_message_iter_get_basic(aIter, &val);
915 JSString *str = JS_NewStringCopyN(cx, val, strlen(val));
916 *v = STRING_TO_JSVAL(str);
921 case DBUS_TYPE_INT16:
922 case DBUS_TYPE_UINT16:
923 case DBUS_TYPE_INT32:
924 case DBUS_TYPE_UINT32:
925 case DBUS_TYPE_INT64:
926 case DBUS_TYPE_UINT64:
927 case DBUS_TYPE_DOUBLE:
929 dbus_uint64_t val = 0;
930 dbus_message_iter_get_basic(aIter, &val);
931 if (!JS_NewNumberValue(cx, (jsdouble)val, v))
933 BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
938 case DBUS_TYPE_ARRAY:
942 nsTArray<jsval> elems;
944 // recurse to container
946 // iterate over array elements
953 // Create an Array object with the elements
954 JSObject *array = JS_NewArrayObject(cx, 0, NULL);
958 case DBUS_TYPE_STRUCT:
961 BDBLOG(("%s: Unhandled type %c\n", __FUNCTION__, aDBusType));
968 already_AddRefed<nsIWritableVariant> getVariantFromIter(DBusMessageIter *aIter, int aDBusType)
970 nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
971 nsIWritableVariant *retval;
975 case DBUS_TYPE_BOOLEAN:
978 BDBLOG((" arg type BOOLEAN: "));
979 dbus_message_iter_get_basic(aIter, &val);
980 BDBLOG(("%d\n", val));
981 variant->SetAsBool(val);
986 case DBUS_TYPE_INT16:
987 case DBUS_TYPE_UINT16:
988 case DBUS_TYPE_INT32:
989 case DBUS_TYPE_UINT32:
992 BDBLOG((" arg type INT: "));
993 dbus_message_iter_get_basic(aIter, &val);
994 BDBLOG(("%d\n", val));
995 variant->SetAsUint32(val);
998 case DBUS_TYPE_INT64:
1001 BDBLOG((" arg type INT64: "));
1002 dbus_message_iter_get_basic(aIter, &val);
1003 BDBLOG(("%lld\n", val));
1004 variant->SetAsInt64(val);
1007 case DBUS_TYPE_UINT64:
1010 BDBLOG((" arg type UINT64: "));
1011 dbus_message_iter_get_basic(aIter, &val);
1012 BDBLOG(("%llu\n", val));
1013 variant->SetAsUint64(val);
1016 case DBUS_TYPE_DOUBLE:
1019 BDBLOG((" arg type DOUBLE: "));
1020 dbus_message_iter_get_basic(aIter, &val);
1021 BDBLOG(("%f\n", val));
1022 variant->SetAsDouble(val);
1025 case DBUS_TYPE_STRING:
1026 case DBUS_TYPE_OBJECT_PATH:
1027 case DBUS_TYPE_SIGNATURE:
1030 BDBLOG((" arg type STRING/OBJECT_PATH/SIGNATURE: "));
1031 dbus_message_iter_get_basic(aIter, &tmp);
1032 nsDependentCString val(tmp);
1033 BDBLOG(("\"%s\"\n", PromiseFlatCString(val).get()));
1034 variant->SetAsAUTF8String(val);
1037 case DBUS_TYPE_ARRAY:
1039 if (dbus_message_iter_get_element_type(aIter) == DBUS_TYPE_DICT_ENTRY)
1041 BDBLOG((" arg type ARRAY with DICT_ENTRY\n"));
1043 // try to get a JS context (code borrowed from xpcsample1.cpp)
1045 // get the xpconnect service
1047 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1050 BDBLOG((" got nsIXPConnect\n"));
1052 // get the xpconnect native call context
1053 // FIXME: this doesn't work for signals since there's no
1054 // active context there...
1055 nsAXPCNativeCallContext *callContext = nsnull;
1056 xpc->GetCurrentNativeCallContext(&callContext);
1059 BDBLOG((" callContext :(\n"));
1062 // Get JSContext of current call
1064 rv = callContext->GetJSContext(&cx);
1065 if(NS_FAILED(rv) || !cx)
1067 BDBLOG((" got JSContext\n"));
1069 // Construct a JS Object
1070 JSObject *obj = JS_NewObject(cx, nsnull, nsnull, nsnull);
1072 // Set the properties
1073 DBusMessageIter array_iter;
1074 dbus_message_iter_recurse(aIter, &array_iter);
1078 DBusMessageIter dict_iter;
1080 dbus_message_iter_recurse(&array_iter, &dict_iter);
1081 dbus_message_iter_get_basic(&dict_iter, &key);
1082 BDBLOG((" found key %s\n", key ? key : "null"));
1083 dbus_message_iter_next(&dict_iter);
1084 int value_type = dbus_message_iter_get_arg_type(&dict_iter);
1085 BDBLOG((" found value type %c\n", value_type));
1087 getJSValueFromIter(cx, &dict_iter, value_type, &v);
1088 JS_SetProperty(cx, obj, key, &v);
1090 } while (dbus_message_iter_next(&array_iter));
1092 // Convert to variant and return
1093 nsIVariant *var = nsnull;
1094 nsresult rs = xpc->JSToVariant(cx, OBJECT_TO_JSVAL(obj), &var);
1095 variant->SetFromVariant(var);
1097 NS_ADDREF(retval = variant);
1104 DBusMessageIter array_iter;
1105 nsCOMPtr<nsIMutableArray> items;
1106 PRUint32 item_count;
1108 BDBLOG((" arg type ARRAY\n"));
1109 dbus_message_iter_recurse(aIter, &array_iter);
1110 items = getArrayFromIter(&array_iter);
1111 items->GetLength(&item_count);
1112 BDBLOG((" array: %d items\n", item_count));
1114 nsIVariant **item_array = new nsIVariant*[item_count];
1115 for (int i = 0; i < item_count; i++)
1117 nsCOMPtr<nsIVariant> item = do_QueryElementAt(items, i);
1118 item_array[i] = item;
1121 variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
1122 &NS_GET_IID(nsIVariant),
1125 for (int i = 0; i < item_count; i++)
1126 NS_RELEASE(item_array[i]);
1127 delete[] item_array;
1133 BDBLOG((" arg type '%c' (%d)\n", aDBusType, aDBusType));
1138 NS_ADDREF(retval = variant);
1142 already_AddRefed<nsIMutableArray> getArrayFromIter(DBusMessageIter *aIter)
1145 nsCOMPtr<nsIMutableArray> array = do_CreateInstance("@mozilla.org/array;1");
1146 nsIMutableArray *retval;
1148 BDBLOG((" ++ enter getArrayFromIter\n"));
1150 while ((current_type = dbus_message_iter_get_arg_type(aIter)) != DBUS_TYPE_INVALID)
1152 nsCOMPtr<nsIWritableVariant> variant = getVariantFromIter(aIter, current_type);
1154 array->AppendElement(variant, PR_FALSE);
1156 BDBLOG((" arg type '%c' (%d) not handled\n", current_type, current_type));
1158 dbus_message_iter_next(aIter);
1161 NS_ADDREF(retval = array);
1162 BDBLOG((" ++ leave getArrayFromIter\n"));
1166 /* vim: set cindent ts=4 et sw=4: */