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"
35 #include "nsISupportsPrimitives.h"
36 #include "nsIProperties.h"
37 #include "nsIXPConnect.h"
39 #include "DBusMarshaling.h"
41 #include "bdb-debug.h"
43 void getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult);
44 void getSignatureFromVariantType(PRUint16 aType, nsCString &aResult);
45 void getSignatureFromISupports(JSContext* cx, nsISupports *aISupports, nsCString &aResult);
47 void addArrayToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
48 void addArrayDataToIter(JSContext* cx, void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
50 void addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
51 already_AddRefed<nsIWritableVariant> getVariantFromIter(DBusMessageIter *aIter, int aDBusType);
53 void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
56 getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult)
58 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
60 if (JSVAL_IS_BOOLEAN(*aValue))
61 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
62 else if (JSVAL_IS_INT(*aValue))
63 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
64 else if (JSVAL_IS_DOUBLE(*aValue))
65 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
66 else if (JSVAL_IS_STRING(*aValue))
67 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
68 else if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
70 // guess element type from first property value
72 JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
75 BDBLOG((" got JSIdArray\n"));
76 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
78 // get key signature from first property name
81 JS_IdToValue(cx, props->vector[0], &propname);
84 JSString *prop_string = JS_ValueToString(cx, propname);
85 if (JS_LookupUCProperty(cx,
86 JSVAL_TO_OBJECT(*aValue),
87 JS_GetStringChars(prop_string),
88 JS_GetStringLength(prop_string),
89 &propvalue) == JS_TRUE)
91 getSignatureFromJSValue(cx, &propvalue, tmpsig);
92 aResult.Append(tmpsig);
96 // FIXME - could not find property value??
97 // assume string to keep signature valid
98 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
100 JS_DestroyIdArray(cx, props);
104 else if (JSVAL_IS_OBJECT(*aValue))
106 nsISupports* supports;
108 JSObject* glob = JSVAL_TO_OBJECT(*aValue);
110 clazz = JS_GET_CLASS(cx, JS_GetParent(cx, glob));
113 !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
114 !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
115 !(supports = (nsISupports*) JS_GetPrivate(cx, glob))) {
117 BDBLOG((" getSignatureFromJSValue: could not find nsISupports inside object, assume dictionary\n"));
119 // try to enumerate object properties
120 JSIdArray *props = JS_Enumerate(cx, glob);
123 BDBLOG((" got JSIdArray with %i props\n", props->length));
124 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
125 aResult.Append(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
127 // get key signature from first property name
129 nsCAutoString tmpsig;
130 JS_IdToValue(cx, props->vector[0], &propname);
131 getSignatureFromJSValue(cx, &propname, tmpsig);
132 aResult.Append(tmpsig);
135 JSString *prop_string = JS_ValueToString(cx, propname);
136 if (JS_LookupUCProperty(cx,
138 JS_GetStringChars(prop_string),
139 JS_GetStringLength(prop_string),
140 &propvalue) == JS_TRUE)
142 getSignatureFromJSValue(cx, &propvalue, tmpsig);
143 aResult.Append(tmpsig);
147 // FIXME - could not find property value??
148 // assume string to keep signature valid
149 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
151 aResult.Append(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
152 JS_DestroyIdArray(cx, props);
158 BDBLOG((" getSignatureFromJSValue: clazz->name %s\n", clazz->name));
159 // test argument for nsIXPConnectWrappedNative
160 nsCOMPtr<nsIXPConnectWrappedNative> wrappednative = do_QueryInterface(supports);
163 BDBLOG((" getSignatureFromJSValue: got nsIXPConnectWrappedNative\n"));
164 nsCOMPtr<nsIVariant> variant = do_QueryInterface(wrappednative->Native());
167 BDBLOG((" found wrapped variant\n"));
168 getSignatureFromVariant(cx, variant, aResult);
172 // use string type as fallback
173 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
181 getSignatureFromVariantType(PRUint16 aType, nsCString &aResult)
184 case nsIDataType::VTYPE_BOOL:
185 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
187 case nsIDataType::VTYPE_INT8: /* FIXME - check sign issues;
188 dbus supports only unsigned 8bit */
189 case nsIDataType::VTYPE_UINT8:
190 aResult.Assign(DBUS_TYPE_BYTE_AS_STRING);
192 case nsIDataType::VTYPE_INT16:
193 aResult.Assign(DBUS_TYPE_INT16_AS_STRING);
195 case nsIDataType::VTYPE_UINT16:
196 aResult.Assign(DBUS_TYPE_UINT16_AS_STRING);
198 case nsIDataType::VTYPE_INT32:
199 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
201 case nsIDataType::VTYPE_UINT32:
202 aResult.Assign(DBUS_TYPE_UINT32_AS_STRING);
204 case nsIDataType::VTYPE_INT64:
205 aResult.Assign(DBUS_TYPE_INT64_AS_STRING);
207 case nsIDataType::VTYPE_UINT64:
208 aResult.Assign(DBUS_TYPE_UINT64_AS_STRING);
210 case nsIDataType::VTYPE_DOUBLE:
211 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
213 case nsIDataType::VTYPE_VOID:
214 // FIXME - assume that string is the best representation
215 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
216 case nsIDataType::VTYPE_WCHAR_STR:
217 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
220 BDBLOG((" getSignatureFromVariantType: %d not a simple type\n", aType));
221 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
226 getSignatureFromVariant(JSContext* cx, nsIVariant *aVariant, nsCString &aResult)
228 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
231 aVariant->GetDataType(&dataType);
234 case nsIDataType::VTYPE_VOID:
235 case nsIDataType::VTYPE_BOOL:
236 case nsIDataType::VTYPE_INT8:
237 case nsIDataType::VTYPE_UINT8:
238 case nsIDataType::VTYPE_INT16:
239 case nsIDataType::VTYPE_UINT16:
240 case nsIDataType::VTYPE_INT32:
241 case nsIDataType::VTYPE_UINT32:
242 case nsIDataType::VTYPE_INT64:
243 case nsIDataType::VTYPE_UINT64:
244 case nsIDataType::VTYPE_DOUBLE:
245 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
246 case nsIDataType::VTYPE_WCHAR_STR:
249 aVariant->GetAsUint32(&val);
250 BDBLOG((" getSignatureFromVariant: simple type %i:%i\n", dataType, val));
251 getSignatureFromVariantType(dataType, aResult);
254 case nsIDataType::VTYPE_ARRAY:
256 BDBLOG((" getSignatureFromVariant: array\n"));
258 // need to recurse into array
262 void *data_ptr = nsnull;
264 aVariant->GetAsArray(&type,
269 BDBLOG((" getSignatureFromVariant: got %d elements of type %d\n", count, type));
271 nsCAutoString elementsig;
273 if (type == nsIDataType::VTYPE_INTERFACE_IS)
275 // get element signature from first element
276 nsISupports *element = ((nsISupports **)data_ptr)[0];
277 getSignatureFromISupports(cx, element, elementsig);
279 else if (type == nsIDataType::VTYPE_ARRAY)
281 // FIXME - can this happen?
282 BDBLOG((" element type array, don't know how to handle\n"));
286 getSignatureFromVariantType(type, elementsig);
289 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
290 aResult.Append(elementsig);
292 nsMemory::Free(data_ptr);
295 case nsIDataType::VTYPE_INTERFACE_IS:
297 BDBLOG((" getSignatureFromVariant: interface\n"));
298 nsCOMPtr<nsISupports> is;
300 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
301 getSignatureFromISupports(cx, is, aResult);
306 BDBLOG((" getSignatureFromVariant: unknown type %d\n", dataType));
313 getSignatureFromISupports(JSContext* cx, nsISupports *aISupports, nsCString &aResult)
315 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
317 // test argument for nsIVariant
318 nsCOMPtr<nsIVariant> variant = do_QueryInterface(aISupports);
321 BDBLOG((" getSignatureFromISupports: nsIVariant\n"));
322 getSignatureFromVariant(cx, variant, aResult);
326 // test argument for nsIXPConnectWrappedJS
327 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aISupports);
330 BDBLOG((" getSignatureFromISupports: nsIXPConnectWrappedJS\n"));
331 JSObject *js_obj = nsnull;
332 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
334 jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
335 getSignatureFromJSValue(cx, &obj_as_jsval, aResult);
340 PRUint16 getVType(int dType)
344 case DBUS_TYPE_BOOLEAN:
345 return nsIDataType::VTYPE_BOOL;
347 return nsIDataType::VTYPE_INT8;
348 case DBUS_TYPE_INT16:
349 return nsIDataType::VTYPE_INT16;
350 case DBUS_TYPE_UINT16:
351 return nsIDataType::VTYPE_UINT16;
352 case DBUS_TYPE_INT32:
353 return nsIDataType::VTYPE_INT32;
354 case DBUS_TYPE_UINT32:
355 return nsIDataType::VTYPE_UINT32;
356 case DBUS_TYPE_DOUBLE:
357 return nsIDataType::VTYPE_DOUBLE;
358 case DBUS_TYPE_STRING:
359 case DBUS_TYPE_OBJECT_PATH:
360 case DBUS_TYPE_SIGNATURE:
361 return nsIDataType::VTYPE_WCHAR_STR;
369 PRBool typesMatch(PRUint16 vType, int dType)
371 return (vType == getVType(dType));
375 addVariantToIter(JSContext* cx, nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
377 char *element_signature = dbus_signature_iter_get_signature(aSigIter);
378 int element_type = dbus_signature_iter_get_current_type(aSigIter);
380 PRUint16 variant_type;
381 aVariant->GetDataType(&variant_type);
383 BDBLOG(("addVariantToIter: signature \"%s\", type %c, variant type: %i\n",
388 if (dbus_type_is_basic(element_type))
390 BDBLOG((" add basic type from variant\n"));
391 addBasicTypeToIter(aVariant, aIter, element_type);
393 else if (element_type == DBUS_TYPE_ARRAY)
395 if (dbus_signature_iter_get_element_type(aSigIter) == DBUS_TYPE_DICT_ENTRY)
397 /* TODO: Support for non-JS Dicts */
399 BDBLOG((" add dict from variant\n"));
401 nsCOMPtr<nsISupports> is;
403 // Reported by a leak, dunno why?
404 // It's a comptr so it should go away with the end of context afaik
405 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
407 // test argument for nsIXPConnectWrappedJS
408 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(is);
411 BDBLOG((" Found XPConnect object\n"));
412 JSObject *js_obj = nsnull;
413 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
415 // try to enumerate object properties
416 JSIdArray *props = JS_Enumerate(cx, js_obj);
419 BDBLOG((" got JSIdArray with %i props\n", props->length));
421 // Start the array container
422 DBusMessageIter childIter;
423 DBusSignatureIter childSigIter;
424 DBusSignatureIter dictSigIter;
425 dbus_signature_iter_recurse(aSigIter, &childSigIter);
426 dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
427 dbus_signature_iter_get_signature(&childSigIter),
430 // Skip the dict signature iter to the value type
431 dbus_signature_iter_recurse(&childSigIter, &dictSigIter);
432 dbus_signature_iter_next(&dictSigIter); // key type
435 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
438 BDBLOG((" got nsIXPConnect\n"));
441 for (int p = 0; p < props->length; p++)
444 nsCAutoString tmpsig;
445 JS_IdToValue(cx, props->vector[p], &propname);
447 // Start the dict container
448 DBusMessageIter dictIter;
449 dbus_message_iter_open_container(&childIter, DBUS_TYPE_DICT_ENTRY,
452 JSString *prop_string = JS_ValueToString(cx, propname);
453 const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
454 JS_GetStringLength(prop_string)).get();
455 // TODO: we only use strings as keys currently, although
456 // the spec allows any basic type to be a key and we
457 // probably *could* use the property index.
458 dbus_message_iter_append_basic(&dictIter,
463 if (JS_LookupUCProperty(cx,
465 JS_GetStringChars(prop_string),
466 JS_GetStringLength(prop_string),
467 &propvalue) == JS_TRUE)
469 nsIVariant *var = nsnull;
470 nsresult rs = xpc->JSToVariant(cx, propvalue, &var);
471 NS_ENSURE_SUCCESS(rs, );
473 addVariantToIter(cx, var, &dictIter, &dictSigIter);
476 // Close the dict entry container
477 dbus_message_iter_close_container(&childIter, &dictIter);
480 // Close the array container
481 dbus_message_iter_close_container(aIter, &childIter);
483 JS_DestroyIdArray(cx, props);
488 BDBLOG((" add array from variant\n"));
490 // need to recurse into array
494 void *data_ptr = nsnull;
496 DBusSignatureIter aChildSigIter;
497 dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
499 char *array_signature = dbus_signature_iter_get_signature(&aChildSigIter);
501 aVariant->GetAsArray(&type,
506 BDBLOG((" %s: got %d elements of type %d\n", __FUNCTION__, count, type));
507 BDBLOG((" %s: got array signature %s\n", __FUNCTION__, array_signature));
509 int dbustype = dbus_signature_iter_get_current_type(&aChildSigIter);
511 if (typesMatch(type, dbustype))
513 BDBLOG(("*** Yay, types match!\n"));
515 DBusMessageIter arrayIter;
516 if (dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
517 array_signature, &arrayIter))
519 addArrayDataToIter(cx, data_ptr, 0, count, type,
520 &arrayIter, &aChildSigIter);
521 dbus_message_iter_close_container(aIter, &arrayIter);
523 nsMemory::Free(data_ptr);
525 BDBLOG(("*** Bummer, types don't match so we'll need to iterate\n"));
527 DBusMessageIter arrayIter;
528 dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
529 array_signature, &arrayIter);
531 /* Seems stupid not to be able to iterate over the values as
532 * nsIVariants directly, but no API to that effect seems to be
535 for (PRUint32 i = 0; i < count; i++)
537 nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
541 #define SET_INT(bits) \
542 case nsIDataType::VTYPE_INT ## bits: \
543 variant->SetAsInt ## bits(*(((PRInt ## bits*)data_ptr)+i)); \
545 case nsIDataType::VTYPE_UINT ## bits: \
546 variant->SetAsUint ## bits(*(((PRUint ## bits*)data_ptr)+i)); \
552 BDBLOG(("*** No conversion from %i to %c\n", type, dbustype));
556 addVariantToIter(cx, variant, &arrayIter, &aChildSigIter);
559 dbus_message_iter_close_container(aIter, &arrayIter);
560 nsMemory::Free(data_ptr);
565 else if (element_type == DBUS_TYPE_STRUCT)
567 BDBLOG((" add struct from variant\n"));
571 BDBLOG((" unhandled\n"));
574 dbus_free(element_signature);
578 int is_valid_path (const char *path)
580 const char *cur = path;
581 const char *prev = cur;
583 if (strlen(path) == 0)
586 /* MUST begin with zero */
590 /* The path is guranteed to be null-terminated */
593 /* Two slashes can't be together */
594 if (*cur == '/' && *prev == '/')
597 } else if (!(((*cur) >= '0' && (*cur) <= '9') ||
598 ((*cur) >= 'A' && (*cur) <= 'Z') ||
599 ((*cur) >= 'a' && (*cur) <= 'z') ||
600 (*cur) == '_' || (*cur) == '/')) {
611 void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType)
615 aVariant->GetDataType(&dataType);
617 /* If we got passed an nsISupports, query the variant iface from it and recurse */
618 if (dataType == nsIDataType::VTYPE_INTERFACE_IS)
620 nsCOMPtr<nsISupports> is;
622 if (NS_FAILED(aVariant->GetAsInterface(&iid, getter_AddRefs(is))))
625 nsCOMPtr<nsIVariant> myVariant = do_QueryInterface(is);
627 addBasicTypeToIter(myVariant, aIter, aDBusType);
634 case DBUS_TYPE_BOOLEAN:
637 if (NS_FAILED(aVariant->GetAsBool(&val)))
639 BDBLOG((" arg : BOOLEAN %s\n", val ? "true" : "false"));
640 dbus_message_iter_append_basic(aIter,
646 case DBUS_TYPE_INT16:
647 case DBUS_TYPE_UINT16:
648 case DBUS_TYPE_INT32:
649 case DBUS_TYPE_UINT32:
652 if (NS_FAILED(aVariant->GetAsUint32(&val)))
655 BDBLOG((" arg : INT(8|16|32) (%c) %d:%d\n", aDBusType, dataType, val));
656 dbus_message_iter_append_basic(aIter,
661 case DBUS_TYPE_INT64:
664 if (NS_FAILED(aVariant->GetAsInt64(&val)))
666 BDBLOG((" arg : INT64 %lld\n", val));
667 dbus_message_iter_append_basic(aIter,
672 case DBUS_TYPE_UINT64:
675 if (NS_FAILED(aVariant->GetAsUint64(&val)))
677 BDBLOG((" arg : UINT64 %llu\n", val));
678 dbus_message_iter_append_basic(aIter,
683 case DBUS_TYPE_DOUBLE:
686 if (NS_FAILED(aVariant->GetAsDouble(&val)))
688 BDBLOG((" arg : DOUBLE (%c) %f\n", aDBusType, val));
689 dbus_message_iter_append_basic(aIter,
694 case DBUS_TYPE_STRING:
695 case DBUS_TYPE_OBJECT_PATH:
696 case DBUS_TYPE_SIGNATURE:
698 /* FIXME - handle utf-8 conversion */
701 if (NS_FAILED(aVariant->GetAsAUTF8String(val)))
704 val_ptr = PromiseFlatCString(val).get();
705 BDBLOG((" arg : STRING '%s'\n", val_ptr));
706 if (aDBusType == DBUS_TYPE_OBJECT_PATH
707 && !is_valid_path(val_ptr))
710 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
715 BDBLOG((" addBasicTypeToIter: unhandled DBus type %d!\n", aDBusType));
721 void addArrayDataToIter(JSContext* cx, void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
723 int aDBusType = dbus_signature_iter_get_current_type(aSigIter);
724 BDBLOG(("addArrayDataToIter: appending %d elements of type %d '%c'\n", count, type, aDBusType));
729 for (PRUint32 i = start; i < count; i++) \
730 dbus_message_iter_append_basic(aIter, aDBusType, data+i)
731 case nsIDataType::VTYPE_INT8:
732 case nsIDataType::VTYPE_UINT8:
734 char *data = (char *)data_ptr;
738 case nsIDataType::VTYPE_INT16:
739 case nsIDataType::VTYPE_UINT16:
741 PRInt16 *data = (PRInt16 *)data_ptr;
745 case nsIDataType::VTYPE_INT32:
746 case nsIDataType::VTYPE_UINT32:
748 PRInt32 *data = (PRInt32 *)data_ptr;
752 case nsIDataType::VTYPE_INT64:
753 case nsIDataType::VTYPE_UINT64:
755 PRInt64 *data = (PRInt64 *)data_ptr;
759 case nsIDataType::VTYPE_DOUBLE:
761 double *data = (double *)data_ptr;
765 case nsIDataType::VTYPE_WCHAR_STR:
767 PRUnichar **data = (PRUnichar **)data_ptr;
768 for (PRUint32 i = start; i < count; i++)
771 nsCAutoString val = NS_ConvertUTF16toUTF8(data[i]);
773 val_ptr = PromiseFlatCString(val).get();
774 BDBLOG((" arg : STRING '%s'\n", val_ptr));
775 if (aDBusType == DBUS_TYPE_OBJECT_PATH
776 && !is_valid_path(val_ptr))
779 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
783 case nsIDataType::VTYPE_INTERFACE_IS:
785 nsISupports **data = (nsISupports **)data_ptr;
786 for (PRUint32 i = start; i < count; i++)
788 nsCOMPtr<nsIVariant> data_variant = do_QueryInterface(data[i]);
790 addVariantToIter(cx, data_variant, aIter, aSigIter);
792 BDBLOG((" interface not nsIVariant\n"));
798 BDBLOG(("addArrayDataToIter: unhandled array data type %d\n", type));
806 addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
809 int dbusType = dbus_signature_iter_get_current_type(aSigIter);
811 BDBLOG(("%s(%s, %c, %s)\n", __FUNCTION__,
812 JS_GetTypeName(cx, JS_TypeOfValue(cx, *aValue)),
813 dbusType, dbus_signature_iter_get_signature(aSigIter)));
815 // Using the expected type instead of the actual allows autoconversion
818 case DBUS_TYPE_BOOLEAN:
821 if (JS_ValueToBoolean(cx, *aValue, &b))
823 dbus_message_iter_append_basic(aIter, DBUS_TYPE_BOOLEAN, &b);
827 BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
834 case DBUS_TYPE_INT16:
835 case DBUS_TYPE_UINT16:
836 case DBUS_TYPE_INT32:
837 case DBUS_TYPE_UINT32:
838 case DBUS_TYPE_INT64:
839 case DBUS_TYPE_UINT64:
840 case DBUS_TYPE_DOUBLE:
844 if (JS_ValueToNumber(cx, *aValue, &d))
846 BDBLOG(("%s(%f)\n", __FUNCTION__, d));
847 dbus_message_iter_append_basic(aIter, dbusType, &d);
851 BDBLOG(("%s(): Could not fetch number from jsvalue\n", __FUNCTION__));
856 case DBUS_TYPE_STRING:
857 case DBUS_TYPE_OBJECT_PATH:
858 case DBUS_TYPE_SIGNATURE:
860 JSString *prop_string = JS_ValueToString(cx, *aValue);
861 const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
862 JS_GetStringLength(prop_string)).get();
863 dbus_message_iter_append_basic(aIter, dbusType, &cstr);
866 case DBUS_TYPE_ARRAY:
868 if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
870 // Arrays are simply converted to variants and pushed to the
873 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
876 BDBLOG((" got nsIXPConnect\n"));
878 nsIVariant *var = nsnull;
879 nsresult rs = xpc->JSToVariant(cx, *aValue, &var);
880 NS_ENSURE_SUCCESS(rs, );
882 addVariantToIter(cx, var, aIter, aSigIter);
888 BDBLOG(("Don't know how to convert type '%c'\n", dbus_signature_iter_get_current_type(aSigIter)));
893 void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v)
896 BDBLOG(("%s(%c)\n", __FUNCTION__, aDBusType));
901 case DBUS_TYPE_STRING:
902 case DBUS_TYPE_OBJECT_PATH:
903 case DBUS_TYPE_SIGNATURE:
906 dbus_message_iter_get_basic(aIter, &val);
909 JSString *str = JS_NewStringCopyN(cx, val, strlen(val));
910 *v = STRING_TO_JSVAL(str);
915 case DBUS_TYPE_INT16:
916 case DBUS_TYPE_UINT16:
917 case DBUS_TYPE_INT32:
918 case DBUS_TYPE_UINT32:
919 case DBUS_TYPE_INT64:
920 case DBUS_TYPE_UINT64:
922 dbus_uint64_t val = 0;
923 dbus_message_iter_get_basic(aIter, &val);
924 if (!JS_NewNumberValue(cx, (jsdouble)val, v))
926 BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
931 case DBUS_TYPE_DOUBLE:
934 dbus_message_iter_get_basic(aIter, &val);
935 if (!JS_NewNumberValue(cx, val, v))
937 BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
942 case DBUS_TYPE_ARRAY:
947 nsTArray<jsval> elems;
949 // recurse to container
950 DBusMessageIter arrayIter;
951 dbus_message_iter_recurse(aIter, &arrayIter);
953 // iterate over array elements
957 BDBLOG(("arg type: %c\n", dbus_message_iter_get_arg_type(&arrayIter)));
958 getJSValueFromIter(cx,
960 dbus_message_iter_get_arg_type(&arrayIter),
962 elems.AppendElement(cv);
964 } while (dbus_message_iter_next(&arrayIter));
966 // Create an Array object with the elements
967 JSObject *array = JS_NewArrayObject(cx, elems.Length(), elems.Elements());
968 *v = OBJECT_TO_JSVAL(array);
971 case DBUS_TYPE_STRUCT:
974 BDBLOG(("%s: Unhandled type %c\n", __FUNCTION__, aDBusType));
981 already_AddRefed<nsIWritableVariant> getVariantFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType)
983 nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
984 nsIWritableVariant *retval;
988 case DBUS_TYPE_BOOLEAN:
991 BDBLOG((" arg type BOOLEAN: "));
992 dbus_message_iter_get_basic(aIter, &val);
993 BDBLOG(("%d\n", val));
994 variant->SetAsBool(val);
999 case DBUS_TYPE_INT16:
1000 case DBUS_TYPE_UINT16:
1001 case DBUS_TYPE_INT32:
1002 case DBUS_TYPE_UINT32:
1005 BDBLOG((" arg type INT: "));
1006 dbus_message_iter_get_basic(aIter, &val);
1007 BDBLOG(("%d\n", val));
1008 variant->SetAsUint32(val);
1011 case DBUS_TYPE_INT64:
1014 BDBLOG((" arg type INT64: "));
1015 dbus_message_iter_get_basic(aIter, &val);
1016 BDBLOG(("%lld\n", val));
1017 variant->SetAsInt64(val);
1020 case DBUS_TYPE_UINT64:
1023 BDBLOG((" arg type UINT64: "));
1024 dbus_message_iter_get_basic(aIter, &val);
1025 BDBLOG(("%llu\n", val));
1026 variant->SetAsUint64(val);
1029 case DBUS_TYPE_DOUBLE:
1032 BDBLOG((" arg type DOUBLE: "));
1033 dbus_message_iter_get_basic(aIter, &val);
1034 BDBLOG(("%f\n", val));
1035 variant->SetAsDouble(val);
1038 case DBUS_TYPE_STRING:
1039 case DBUS_TYPE_OBJECT_PATH:
1040 case DBUS_TYPE_SIGNATURE:
1043 BDBLOG((" arg type STRING/OBJECT_PATH/SIGNATURE: "));
1044 dbus_message_iter_get_basic(aIter, &tmp);
1045 nsDependentCString val(tmp);
1046 BDBLOG(("\"%s\"\n", PromiseFlatCString(val).get()));
1047 variant->SetAsAUTF8String(val);
1050 case DBUS_TYPE_ARRAY:
1052 if (dbus_message_iter_get_element_type(aIter) == DBUS_TYPE_DICT_ENTRY)
1054 BDBLOG((" arg type ARRAY with DICT_ENTRY\n"));
1056 // Construct a JS Object
1057 JSObject *obj = JS_NewObject(cx, nsnull, nsnull, nsnull);
1059 // Set the properties
1060 DBusMessageIter array_iter;
1061 dbus_message_iter_recurse(aIter, &array_iter);
1065 DBusMessageIter dict_iter;
1067 dbus_message_iter_recurse(&array_iter, &dict_iter);
1068 dbus_message_iter_get_basic(&dict_iter, &key);
1069 BDBLOG((" found key %s\n", key ? key : "null"));
1070 dbus_message_iter_next(&dict_iter);
1071 int value_type = dbus_message_iter_get_arg_type(&dict_iter);
1072 BDBLOG((" found value type %c\n", value_type));
1074 getJSValueFromIter(cx, &dict_iter, value_type, &v);
1075 JS_SetProperty(cx, obj, key, &v);
1077 } while (dbus_message_iter_next(&array_iter));
1079 // get the xpconnect service
1081 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1084 BDBLOG((" got nsIXPConnect\n"));
1086 // Convert to variant and return
1087 nsIVariant *var = nsnull;
1088 rv = xpc->JSToVariant(cx, OBJECT_TO_JSVAL(obj), &var);
1091 variant->SetFromVariant(var);
1093 NS_ADDREF(retval = variant);
1100 DBusMessageIter array_iter;
1101 nsCOMPtr<nsIMutableArray> items;
1102 PRUint32 item_count;
1104 BDBLOG((" arg type ARRAY\n"));
1105 dbus_message_iter_recurse(aIter, &array_iter);
1106 items = getArrayFromIter(cx, &array_iter);
1107 items->GetLength(&item_count);
1108 BDBLOG((" array: %d items\n", item_count));
1110 nsIVariant **item_array = new nsIVariant*[item_count];
1111 for (PRUint32 i = 0; i < item_count; i++)
1113 nsCOMPtr<nsIVariant> item = do_QueryElementAt(items, i);
1114 item_array[i] = item;
1117 variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
1118 &NS_GET_IID(nsIVariant),
1121 for (PRUint32 i = 0; i < item_count; i++)
1122 NS_RELEASE(item_array[i]);
1123 delete[] item_array;
1129 BDBLOG((" arg type '%c' (%d)\n", aDBusType, aDBusType));
1134 NS_ADDREF(retval = variant);
1138 already_AddRefed<nsIMutableArray> getArrayFromIter(JSContext* cx, DBusMessageIter *aIter)
1141 nsCOMPtr<nsIMutableArray> array = do_CreateInstance("@mozilla.org/array;1");
1142 nsIMutableArray *retval;
1144 BDBLOG((" ++ enter getArrayFromIter\n"));
1146 while ((current_type = dbus_message_iter_get_arg_type(aIter)) != DBUS_TYPE_INVALID)
1148 nsCOMPtr<nsIWritableVariant> variant = getVariantFromIter(cx, aIter, current_type);
1150 array->AppendElement(variant, PR_FALSE);
1152 BDBLOG((" arg type '%c' (%d) not handled\n", current_type, current_type));
1154 dbus_message_iter_next(aIter);
1157 NS_ADDREF(retval = array);
1158 BDBLOG((" ++ leave getArrayFromIter\n"));
1162 /* vim: set cindent ts=4 et sw=4: */