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"
40 #include "DBusDataCarrier.h"
42 #include "bdb-debug.h"
44 void getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult);
45 void getSignatureFromVariantType(PRUint16 aType, nsCString &aResult);
46 void getSignatureFromISupports(JSContext* cx, nsISupports *aISupports, nsCString &aResult);
48 void addArrayToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
49 void addArrayDataToIter(JSContext* cx, void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter, DBusSignatureIter *containerSigIter);
51 void addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
52 void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v);
53 already_AddRefed<nsIWritableVariant> getVariantFromIter(DBusMessageIter *aIter, int aDBusType);
55 void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType);
58 getSignatureFromJSValue(JSContext *cx, jsval *aValue, nsCString &aResult)
60 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
62 if (JSVAL_IS_BOOLEAN(*aValue))
63 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
64 else if (JSVAL_IS_INT(*aValue))
65 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
66 else if (JSVAL_IS_DOUBLE(*aValue))
67 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
68 else if (JSVAL_IS_STRING(*aValue))
69 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
70 else if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
72 // guess element type from first property value
74 JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
77 BDBLOG((" got JSIdArray\n"));
78 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
80 // get key signature from first property name
83 JS_IdToValue(cx, props->vector[0], &propname);
86 JSString *prop_string = JS_ValueToString(cx, propname);
87 if (JS_LookupUCProperty(cx,
88 JSVAL_TO_OBJECT(*aValue),
89 JS_GetStringChars(prop_string),
90 JS_GetStringLength(prop_string),
91 &propvalue) == JS_TRUE)
93 getSignatureFromJSValue(cx, &propvalue, tmpsig);
94 aResult.Append(tmpsig);
98 // FIXME - could not find property value??
99 // assume string to keep signature valid
100 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
102 JS_DestroyIdArray(cx, props);
106 else if (JSVAL_IS_OBJECT(*aValue))
108 nsISupports* supports;
110 JSObject* glob = JSVAL_TO_OBJECT(*aValue);
112 clazz = JS_GET_CLASS(cx, JS_GetParent(cx, glob));
115 !(clazz->flags & JSCLASS_HAS_PRIVATE) ||
116 !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
117 !(supports = (nsISupports*) JS_GetPrivate(cx, glob))) {
119 BDBLOG((" getSignatureFromJSValue: could not find nsISupports inside object, assume dictionary\n"));
121 // try to enumerate object properties
122 JSIdArray *props = JS_Enumerate(cx, glob);
125 BDBLOG((" got JSIdArray with %i props\n", props->length));
126 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
127 aResult.Append(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
129 // get key signature from first property name
131 nsCAutoString tmpsig;
132 JS_IdToValue(cx, props->vector[0], &propname);
133 getSignatureFromJSValue(cx, &propname, tmpsig);
134 aResult.Append(tmpsig);
137 JSString *prop_string = JS_ValueToString(cx, propname);
138 if (JS_LookupUCProperty(cx,
140 JS_GetStringChars(prop_string),
141 JS_GetStringLength(prop_string),
142 &propvalue) == JS_TRUE)
144 getSignatureFromJSValue(cx, &propvalue, tmpsig);
145 aResult.Append(tmpsig);
149 // FIXME - could not find property value??
150 // assume string to keep signature valid
151 aResult.Append(DBUS_TYPE_STRING_AS_STRING);
153 aResult.Append(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
154 JS_DestroyIdArray(cx, props);
160 BDBLOG((" getSignatureFromJSValue: clazz->name %s\n", clazz->name));
161 // test argument for nsIXPConnectWrappedNative
162 nsCOMPtr<nsIXPConnectWrappedNative> wrappednative = do_QueryInterface(supports);
165 BDBLOG((" getSignatureFromJSValue: got nsIXPConnectWrappedNative\n"));
166 nsCOMPtr<nsIVariant> variant = do_QueryInterface(wrappednative->Native());
169 BDBLOG((" found wrapped variant\n"));
170 getSignatureFromVariant(cx, variant, aResult);
174 // use string type as fallback
175 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
183 getSignatureFromVariantType(PRUint16 aType, nsCString &aResult)
186 case nsIDataType::VTYPE_BOOL:
187 aResult.Assign(DBUS_TYPE_BOOLEAN_AS_STRING);
189 case nsIDataType::VTYPE_INT8: /* FIXME - check sign issues;
190 dbus supports only unsigned 8bit */
191 case nsIDataType::VTYPE_UINT8:
192 aResult.Assign(DBUS_TYPE_BYTE_AS_STRING);
194 case nsIDataType::VTYPE_INT16:
195 aResult.Assign(DBUS_TYPE_INT16_AS_STRING);
197 case nsIDataType::VTYPE_UINT16:
198 aResult.Assign(DBUS_TYPE_UINT16_AS_STRING);
200 case nsIDataType::VTYPE_INT32:
201 aResult.Assign(DBUS_TYPE_INT32_AS_STRING);
203 case nsIDataType::VTYPE_UINT32:
204 aResult.Assign(DBUS_TYPE_UINT32_AS_STRING);
206 case nsIDataType::VTYPE_INT64:
207 aResult.Assign(DBUS_TYPE_INT64_AS_STRING);
209 case nsIDataType::VTYPE_UINT64:
210 aResult.Assign(DBUS_TYPE_UINT64_AS_STRING);
212 case nsIDataType::VTYPE_DOUBLE:
213 aResult.Assign(DBUS_TYPE_DOUBLE_AS_STRING);
215 case nsIDataType::VTYPE_VOID:
216 // FIXME - assume that string is the best representation
217 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
218 case nsIDataType::VTYPE_WCHAR_STR:
219 aResult.Assign(DBUS_TYPE_STRING_AS_STRING);
222 BDBLOG((" getSignatureFromVariantType: %d not a simple type\n", aType));
223 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
228 getSignatureFromVariant(JSContext* cx, nsIVariant *aVariant, nsCString &aResult)
230 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
233 aVariant->GetDataType(&dataType);
236 case nsIDataType::VTYPE_VOID:
237 case nsIDataType::VTYPE_BOOL:
238 case nsIDataType::VTYPE_INT8:
239 case nsIDataType::VTYPE_UINT8:
240 case nsIDataType::VTYPE_INT16:
241 case nsIDataType::VTYPE_UINT16:
242 case nsIDataType::VTYPE_INT32:
243 case nsIDataType::VTYPE_UINT32:
244 case nsIDataType::VTYPE_INT64:
245 case nsIDataType::VTYPE_UINT64:
246 case nsIDataType::VTYPE_DOUBLE:
247 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
248 case nsIDataType::VTYPE_WCHAR_STR:
251 aVariant->GetAsUint32(&val);
252 BDBLOG((" getSignatureFromVariant: simple type %i:%i\n", dataType, val));
253 getSignatureFromVariantType(dataType, aResult);
256 case nsIDataType::VTYPE_ARRAY:
258 BDBLOG((" getSignatureFromVariant: array\n"));
260 // need to recurse into array
264 void *data_ptr = nsnull;
266 aVariant->GetAsArray(&type,
271 BDBLOG((" getSignatureFromVariant: got %d elements of type %d\n", count, type));
273 nsCAutoString elementsig;
275 if (type == nsIDataType::VTYPE_INTERFACE_IS)
277 // get element signature from first element
278 nsISupports *element = ((nsISupports **)data_ptr)[0];
279 getSignatureFromISupports(cx, element, elementsig);
280 for (PRUint32 i = 0; i < count; i++)
281 NS_IF_RELEASE(((nsISupports **)data_ptr)[i]);
284 else if (type == nsIDataType::VTYPE_WCHAR_STR)
286 for (PRUint32 i = 0; i < count; i++)
287 nsMemory::Free(((char**)data_ptr)[i]);
291 getSignatureFromVariantType(type, elementsig);
294 aResult.Assign(DBUS_TYPE_ARRAY_AS_STRING);
295 aResult.Append(elementsig);
297 nsMemory::Free(data_ptr);
300 case nsIDataType::VTYPE_INTERFACE_IS:
302 BDBLOG((" getSignatureFromVariant: interface\n"));
303 nsCOMPtr<nsISupports> is;
305 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
306 getSignatureFromISupports(cx, is, aResult);
311 BDBLOG((" getSignatureFromVariant: unknown type %d\n", dataType));
318 getSignatureFromISupports(JSContext* cx, nsISupports *aISupports, nsCString &aResult)
320 aResult.Assign(DBUS_TYPE_INVALID_AS_STRING);
322 // test argument for nsIVariant
323 nsCOMPtr<nsIVariant> variant = do_QueryInterface(aISupports);
326 BDBLOG((" getSignatureFromISupports: nsIVariant\n"));
327 getSignatureFromVariant(cx, variant, aResult);
331 // test argument for DBusDataCarrier
332 nsCOMPtr<DBusDataCarrier> carrier = do_QueryInterface(aISupports);
335 BDBLOG((" getSignatureFromISupports: DBusDataCarrier\n"));
336 carrier->GetType(aResult);
337 if (aResult.Equals("r")) {
339 carrier->GetValue(&value);
340 getSignatureFromVariant(cx, value, aResult);
342 } else if (aResult.Equals("v")) {
343 carrier->GetSignature(aResult);
348 // test argument for nsIXPConnectWrappedJS
349 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(aISupports);
352 BDBLOG((" getSignatureFromISupports: nsIXPConnectWrappedJS\n"));
353 JSObject *js_obj = nsnull;
354 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
356 jsval obj_as_jsval = OBJECT_TO_JSVAL(js_obj);
357 getSignatureFromJSValue(cx, &obj_as_jsval, aResult);
362 PRUint16 getVType(int dType)
366 case DBUS_TYPE_BOOLEAN:
367 return nsIDataType::VTYPE_BOOL;
369 return nsIDataType::VTYPE_INT8;
370 case DBUS_TYPE_INT16:
371 return nsIDataType::VTYPE_INT16;
372 case DBUS_TYPE_UINT16:
373 return nsIDataType::VTYPE_UINT16;
374 case DBUS_TYPE_INT32:
375 return nsIDataType::VTYPE_INT32;
376 case DBUS_TYPE_UINT32:
377 return nsIDataType::VTYPE_UINT32;
378 case DBUS_TYPE_DOUBLE:
379 return nsIDataType::VTYPE_DOUBLE;
380 case DBUS_TYPE_STRING:
381 case DBUS_TYPE_OBJECT_PATH:
382 case DBUS_TYPE_SIGNATURE:
383 return nsIDataType::VTYPE_WCHAR_STR;
391 PRBool typesMatch(PRUint16 vType, int dType)
393 return (vType == getVType(dType));
397 addVariantToIter(JSContext* cx, nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
399 int element_type = dbus_signature_iter_get_current_type(aSigIter);
401 PRUint16 variant_type;
402 aVariant->GetDataType(&variant_type);
405 char *element_signature = dbus_signature_iter_get_signature(aSigIter);
406 BDBLOG(("addVariantToIter: signature \"%s\", type %c, variant type: %i\n",
410 dbus_free(element_signature);
413 // If the carrier has a nsISupports, check for DataCarrier
414 if (variant_type == nsIDataType::VTYPE_INTERFACE_IS)
416 nsCOMPtr<nsISupports> is;
419 if (NS_FAILED(aVariant->GetAsInterface(&iid, getter_AddRefs(is))))
422 nsCOMPtr<DBusDataCarrier> myCarrier = do_QueryInterface(is);
425 myCarrier->GetValue(&myValue);
426 addVariantToIter(cx, myValue, aIter, aSigIter);
427 NS_IF_RELEASE(myValue);
433 if (dbus_type_is_basic(element_type))
435 BDBLOG((" add basic type from variant\n"));
436 addBasicTypeToIter(aVariant, aIter, element_type);
438 else if (element_type == DBUS_TYPE_ARRAY)
440 if (dbus_signature_iter_get_element_type(aSigIter) == DBUS_TYPE_DICT_ENTRY)
442 /* TODO: Support for non-JS Dicts */
444 BDBLOG((" add dict from variant\n"));
446 nsCOMPtr<nsISupports> is;
448 // Reported by a leak, dunno why?
449 // It's a comptr so it should go away with the end of context afaik
450 aVariant->GetAsInterface(&iid, getter_AddRefs(is));
452 // test argument for nsIXPConnectWrappedJS
453 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(is);
456 BDBLOG((" Found XPConnect object\n"));
457 JSObject *js_obj = nsnull;
458 if (NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
460 // try to enumerate object properties
461 JSIdArray *props = JS_Enumerate(cx, js_obj);
464 BDBLOG((" got JSIdArray with %i props\n", props->length));
466 // Start the array container
467 DBusMessageIter childIter;
468 DBusSignatureIter childSigIter;
469 DBusSignatureIter dictSigIter;
470 dbus_signature_iter_recurse(aSigIter, &childSigIter);
471 char *array_signature = dbus_signature_iter_get_signature(&childSigIter);
472 dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
473 array_signature, &childIter);
474 dbus_free(array_signature);
476 // Skip the dict signature iter to the value type
477 dbus_signature_iter_recurse(&childSigIter, &dictSigIter);
478 dbus_signature_iter_next(&dictSigIter); // key type
481 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
484 BDBLOG((" got nsIXPConnect\n"));
487 for (int p = 0; p < props->length; p++)
490 JS_IdToValue(cx, props->vector[p], &propname);
492 // Start the dict container
493 DBusMessageIter dictIter;
494 dbus_message_iter_open_container(&childIter, DBUS_TYPE_DICT_ENTRY,
497 JSString *prop_string = JS_ValueToString(cx, propname);
498 nsCAutoString u8str = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
499 JS_GetStringLength(prop_string));
500 const char *cstr = u8str.get();
501 // TODO: we only use strings as keys currently, although
502 // the spec allows any basic type to be a key and we
503 // probably *could* use the property index.
504 dbus_message_iter_append_basic(&dictIter,
509 if (JS_LookupUCProperty(cx,
511 JS_GetStringChars(prop_string),
512 JS_GetStringLength(prop_string),
513 &propvalue) == JS_TRUE)
515 nsIVariant *var = nsnull;
516 nsresult rs = xpc->JSToVariant(cx, propvalue, &var);
517 NS_ENSURE_SUCCESS(rs, );
519 addVariantToIter(cx, var, &dictIter, &dictSigIter);
523 // Close the dict entry container
524 dbus_message_iter_close_container(&childIter, &dictIter);
527 // Close the array container
528 dbus_message_iter_close_container(aIter, &childIter);
530 JS_DestroyIdArray(cx, props);
535 BDBLOG((" add array from variant\n"));
537 // need to recurse into array
541 void *data_ptr = nsnull;
543 DBusSignatureIter aChildSigIter;
544 dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
546 char *array_signature = dbus_signature_iter_get_signature(&aChildSigIter);
548 aVariant->GetAsArray(&type,
553 BDBLOG((" %s: got %d elements of type %d\n", __FUNCTION__, count, type));
554 BDBLOG((" %s: got array signature %s\n", __FUNCTION__, array_signature));
556 DBusMessageIter arrayIter;
557 if (!dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
558 array_signature, &arrayIter))
560 nsMemory::Free(data_ptr);
561 dbus_free(array_signature);
565 addArrayDataToIter(cx, data_ptr, 0, count, type,
566 &arrayIter, &aChildSigIter, aSigIter);
568 dbus_message_iter_close_container(aIter, &arrayIter);
569 nsMemory::Free(data_ptr);
570 dbus_free(array_signature);
573 else if (element_type == DBUS_TYPE_VARIANT)
575 BDBLOG((" add variant from variant\n"));
577 nsCAutoString variantSignature;
578 getSignatureFromVariant(cx, aVariant, variantSignature);
580 BDBLOG((" variant sig: %s\n", variantSignature.get()));
582 DBusSignatureIter aChildSigIter;
583 dbus_signature_iter_init(&aChildSigIter, variantSignature.get());
585 DBusMessageIter variantIter;
586 dbus_message_iter_open_container(aIter, DBUS_TYPE_VARIANT,
587 variantSignature.get(), &variantIter);
588 addVariantToIter(cx, aVariant, &variantIter, &aChildSigIter);
589 dbus_message_iter_close_container(aIter, &variantIter);
592 else if (element_type == DBUS_TYPE_STRUCT)
594 BDBLOG((" add struct from variant\n"));
596 if (variant_type != nsIDataType::VTYPE_ARRAY)
598 BDBLOG((" struct not presented as array!\n"));
602 DBusSignatureIter aChildSigIter;
603 dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
605 char *signature = dbus_signature_iter_get_signature(aSigIter);
606 DBusMessageIter structIter;
607 dbus_message_iter_open_container(aIter, DBUS_TYPE_STRUCT,
608 signature, &structIter);
609 BDBLOG((" struct sig: %s\n", signature));
610 dbus_free(signature);
612 // Structs are just mixed-type arrays really
616 void *data_ptr = nsnull;
618 aVariant->GetAsArray(&type,
623 addArrayDataToIter(cx, data_ptr, 0, count, type,
624 &structIter, &aChildSigIter, aSigIter);
626 dbus_message_iter_close_container(aIter, &structIter);
627 nsMemory::Free(data_ptr);
631 BDBLOG((" unhandled\n"));
636 int is_valid_path (const char *path)
638 const char *cur = path;
639 const char *prev = cur;
641 if (strlen(path) == 0)
644 /* MUST begin with zero */
648 /* The path is guranteed to be null-terminated */
651 /* Two slashes can't be together */
652 if (*cur == '/' && *prev == '/')
655 } else if (!(((*cur) >= '0' && (*cur) <= '9') ||
656 ((*cur) >= 'A' && (*cur) <= 'Z') ||
657 ((*cur) >= 'a' && (*cur) <= 'z') ||
658 (*cur) == '_' || (*cur) == '/')) {
669 void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusType)
673 aVariant->GetDataType(&dataType);
675 /* If we got passed an nsISupports, query the variant iface from it and recurse */
676 if (dataType == nsIDataType::VTYPE_INTERFACE_IS)
678 nsCOMPtr<nsISupports> is;
680 if (NS_FAILED(aVariant->GetAsInterface(&iid, getter_AddRefs(is))))
683 nsCOMPtr<nsIVariant> myVariant = do_QueryInterface(is);
685 addBasicTypeToIter(myVariant, aIter, aDBusType);
689 nsCOMPtr<DBusDataCarrier> myCarrier = do_QueryInterface(is);
691 nsCOMPtr<nsIVariant> myValue;
692 myCarrier->GetValue(getter_AddRefs(myValue));
693 addBasicTypeToIter(myValue, aIter, aDBusType);
697 BDBLOG((" Got nsISupports, but don't know what to do with it!\n"));
704 case DBUS_TYPE_BOOLEAN:
707 if (NS_FAILED(aVariant->GetAsBool(&val)))
709 BDBLOG((" arg : BOOLEAN %s\n", val ? "true" : "false"));
710 dbus_message_iter_append_basic(aIter,
716 case DBUS_TYPE_INT16:
717 case DBUS_TYPE_UINT16:
718 case DBUS_TYPE_INT32:
719 case DBUS_TYPE_UINT32:
722 if (NS_FAILED(aVariant->GetAsUint32(&val)))
725 BDBLOG((" arg : INT(8|16|32) (%c) %d:%d\n", aDBusType, dataType, val));
726 dbus_message_iter_append_basic(aIter,
731 case DBUS_TYPE_INT64:
734 if (NS_FAILED(aVariant->GetAsInt64(&val)))
736 BDBLOG((" arg : INT64 %lld\n", val));
737 dbus_message_iter_append_basic(aIter,
742 case DBUS_TYPE_UINT64:
745 if (NS_FAILED(aVariant->GetAsUint64(&val)))
747 BDBLOG((" arg : UINT64 %llu\n", val));
748 dbus_message_iter_append_basic(aIter,
753 case DBUS_TYPE_DOUBLE:
756 if (NS_FAILED(aVariant->GetAsDouble(&val)))
758 BDBLOG((" arg : DOUBLE (%c) %f\n", aDBusType, val));
759 dbus_message_iter_append_basic(aIter,
764 case DBUS_TYPE_STRING:
765 case DBUS_TYPE_OBJECT_PATH:
766 case DBUS_TYPE_SIGNATURE:
768 /* FIXME - handle utf-8 conversion */
771 if (NS_FAILED(aVariant->GetAsAUTF8String(val)))
774 val_ptr = PromiseFlatCString(val).get();
775 BDBLOG((" arg : STRING '%s'\n", val_ptr));
776 if (aDBusType == DBUS_TYPE_OBJECT_PATH
777 && !is_valid_path(val_ptr))
780 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
785 BDBLOG((" addBasicTypeToIter: unhandled DBus type %d!\n", aDBusType));
791 void addArrayDataToIter(JSContext* cx, void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter, DBusSignatureIter *containerSigIter)
793 int aDBusType = dbus_signature_iter_get_current_type(aSigIter);
794 BDBLOG(("addArrayDataToIter: appending %d elements of type %d '%c'\n", count, type, aDBusType));
799 for (PRUint32 i = start; i < count; i++) \
800 dbus_message_iter_append_basic(aIter, aDBusType, data+i)
801 #define ADD_DATA_AS_DOUBLE do { \
802 for (PRUint32 i = start; i < count; i++) { \
803 double t = *(data+i); \
804 dbus_message_iter_append_basic(aIter, aDBusType, &t); \
806 case nsIDataType::VTYPE_BOOL:
808 PRBool *data = (PRBool *)data_ptr;
812 case nsIDataType::VTYPE_INT8:
813 case nsIDataType::VTYPE_UINT8:
815 char *data = (char *)data_ptr;
816 if (aDBusType == DBUS_TYPE_DOUBLE)
822 case nsIDataType::VTYPE_INT16:
823 case nsIDataType::VTYPE_UINT16:
825 PRInt16 *data = (PRInt16 *)data_ptr;
826 if (aDBusType == DBUS_TYPE_DOUBLE)
832 case nsIDataType::VTYPE_INT32:
833 case nsIDataType::VTYPE_UINT32:
835 PRInt32 *data = (PRInt32 *)data_ptr;
836 if (aDBusType == DBUS_TYPE_DOUBLE)
842 case nsIDataType::VTYPE_INT64:
843 case nsIDataType::VTYPE_UINT64:
845 PRInt64 *data = (PRInt64 *)data_ptr;
846 if (aDBusType == DBUS_TYPE_DOUBLE)
852 case nsIDataType::VTYPE_DOUBLE:
854 double *data = (double *)data_ptr;
858 case nsIDataType::VTYPE_WCHAR_STR:
860 PRUnichar **data = (PRUnichar **)data_ptr;
861 for (PRUint32 i = start; i < count; i++)
864 nsCAutoString val = NS_ConvertUTF16toUTF8(data[i]);
866 val_ptr = PromiseFlatCString(val).get();
867 BDBLOG((" arg : STRING '%s'\n", val_ptr));
868 if (aDBusType == DBUS_TYPE_OBJECT_PATH
869 && !is_valid_path(val_ptr))
872 dbus_message_iter_append_basic(aIter, aDBusType, &val_ptr);
876 case nsIDataType::VTYPE_INTERFACE_IS:
878 DBusSignatureIter childSigIter;
879 dbus_signature_iter_recurse(containerSigIter, &childSigIter);
881 nsISupports **data = (nsISupports **)data_ptr;
882 for (PRUint32 i = 0; i < count; i++)
885 // We might have a wrapped JS object in the nsISupports
887 nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(data[i]);
890 JSObject *js_obj = nsnull;
891 if (!NS_SUCCEEDED(wrapped->GetJSObject(&js_obj)))
894 jsval js_obj_as_value = OBJECT_TO_JSVAL(js_obj);
895 addJSValueToIter(cx, &js_obj_as_value,
896 aIter, &childSigIter);
899 // We might have a variant
900 nsCOMPtr<nsIVariant> variant = do_QueryInterface(data[i]);
903 addVariantToIter(cx, variant, aIter, &childSigIter);
906 /* Advance the signature iter or reset */
907 if (!dbus_signature_iter_next(&childSigIter))
908 dbus_signature_iter_recurse(containerSigIter, &childSigIter);
916 BDBLOG(("addArrayDataToIter: unhandled array data type %d\n", type));
924 addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
927 int dbusType = dbus_signature_iter_get_current_type(aSigIter);
929 BDBLOG(("%s(%s, %c, %s)\n", __FUNCTION__,
930 JS_GetTypeName(cx, JS_TypeOfValue(cx, *aValue)),
931 dbusType, dbus_signature_iter_get_signature(aSigIter)));
933 // Using the expected type instead of the actual allows autoconversion
936 case DBUS_TYPE_BOOLEAN:
939 if (JS_ValueToBoolean(cx, *aValue, &b))
941 dbus_message_iter_append_basic(aIter, DBUS_TYPE_BOOLEAN, &b);
945 BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
952 case DBUS_TYPE_INT16:
953 case DBUS_TYPE_UINT16:
954 case DBUS_TYPE_INT32:
955 case DBUS_TYPE_UINT32:
956 case DBUS_TYPE_INT64:
957 case DBUS_TYPE_UINT64:
958 case DBUS_TYPE_DOUBLE:
962 if (JS_ValueToNumber(cx, *aValue, &d))
964 BDBLOG(("%s(%f)\n", __FUNCTION__, d));
965 dbus_message_iter_append_basic(aIter, dbusType, &d);
969 BDBLOG(("%s(): Could not fetch number from jsvalue\n", __FUNCTION__));
974 case DBUS_TYPE_STRING:
975 case DBUS_TYPE_OBJECT_PATH:
976 case DBUS_TYPE_SIGNATURE:
978 JSString *prop_string = JS_ValueToString(cx, *aValue);
979 const char *cstr = NS_ConvertUTF16toUTF8(JS_GetStringChars(prop_string),
980 JS_GetStringLength(prop_string)).get();
981 dbus_message_iter_append_basic(aIter, dbusType, &cstr);
984 case DBUS_TYPE_ARRAY:
986 if (!JSVAL_IS_OBJECT(*aValue))
989 if (JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue))) {
990 // We iterate the JS arrays here to (potentially) avoid
991 // extra conversions to variants
993 JSObject *array = JSVAL_TO_OBJECT(*aValue);
995 if (!JS_GetArrayLength(cx, array, &length))
998 DBusSignatureIter aChildSigIter;
999 dbus_signature_iter_recurse(aSigIter, &aChildSigIter);
1001 char *array_signature = dbus_signature_iter_get_signature(&aChildSigIter);
1003 BDBLOG((" %s: got array signature %s\n", __FUNCTION__, array_signature));
1005 DBusMessageIter arrayIter;
1006 if (!dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
1007 array_signature, &arrayIter))
1009 dbus_free(array_signature);
1012 dbus_free(array_signature);
1014 for (jsuint e = 0; e < length; e++)
1017 if (JS_GetElement(cx, array, e, &ev))
1018 addJSValueToIter(cx, &ev, &arrayIter, &aChildSigIter);
1021 dbus_message_iter_close_container(aIter, &arrayIter);
1024 // non-array JS objects are converted to variants and pushed
1025 // to the variant code path
1027 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1030 BDBLOG((" got nsIXPConnect\n"));
1032 nsIVariant *var = nsnull;
1033 nsresult rs = xpc->JSToVariant(cx, *aValue, &var);
1034 NS_ENSURE_SUCCESS(rs, );
1036 addVariantToIter(cx, var, aIter, aSigIter);
1043 BDBLOG(("Don't know how to convert type '%c'\n", dbus_signature_iter_get_current_type(aSigIter)));
1048 void getDictFromArray(JSContext* cx, DBusMessageIter *arrayIter, JSObject **obj)
1050 *obj = JS_NewObject(cx, nsnull, nsnull, nsnull);
1054 DBusMessageIter dict_iter;
1056 dbus_message_iter_recurse(arrayIter, &dict_iter);
1057 dbus_message_iter_get_basic(&dict_iter, &key);
1058 BDBLOG((" found key %s\n", key ? key : "null"));
1059 dbus_message_iter_next(&dict_iter);
1060 int value_type = dbus_message_iter_get_arg_type(&dict_iter);
1061 BDBLOG((" found value type %c\n", value_type));
1063 getJSValueFromIter(cx, &dict_iter, value_type, &v);
1064 nsAutoString ukey = NS_ConvertUTF8toUTF16(key);
1065 JS_SetUCProperty(cx, *obj, ukey.get(), ukey.Length(), &v);
1067 } while (dbus_message_iter_next(arrayIter));
1071 void getJSArrayFromIter(JSContext* cx, DBusMessageIter *aIter, JSObject **array)
1073 nsTArray<jsval> elems;
1075 // iterate over array elements
1079 BDBLOG(("arg type: %c\n",
1080 dbus_message_iter_get_arg_type(aIter)));
1081 getJSValueFromIter(cx, aIter,
1082 dbus_message_iter_get_arg_type(aIter),
1084 elems.AppendElement(cv);
1086 } while (dbus_message_iter_next(aIter));
1088 // Create an Array object with the elements
1089 *array = JS_NewArrayObject(cx, elems.Length(), elems.Elements());
1092 void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v)
1095 BDBLOG(("%s(%c)\n", __FUNCTION__, aDBusType));
1100 case DBUS_TYPE_STRING:
1101 case DBUS_TYPE_OBJECT_PATH:
1102 case DBUS_TYPE_SIGNATURE:
1105 dbus_message_iter_get_basic(aIter, &val);
1108 nsAutoString uval = NS_ConvertUTF8toUTF16(val);
1109 JSString *str = JS_NewUCStringCopyN(cx, uval.get(), uval.Length());
1110 *v = STRING_TO_JSVAL(str);
1114 case DBUS_TYPE_BYTE:
1115 case DBUS_TYPE_INT16:
1116 case DBUS_TYPE_UINT16:
1117 case DBUS_TYPE_INT32:
1118 case DBUS_TYPE_UINT32:
1119 case DBUS_TYPE_INT64:
1120 case DBUS_TYPE_UINT64:
1122 dbus_uint64_t val = 0;
1123 dbus_message_iter_get_basic(aIter, &val);
1124 if (!JS_NewNumberValue(cx, (jsdouble)val, v))
1126 BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
1131 case DBUS_TYPE_DOUBLE:
1134 dbus_message_iter_get_basic(aIter, &val);
1135 if (!JS_NewNumberValue(cx, val, v))
1137 BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
1142 case DBUS_TYPE_ARRAY:
1144 DBusMessageIter arrayIter;
1145 dbus_message_iter_recurse(aIter, &arrayIter);
1147 if (dbus_message_iter_get_element_type(aIter) == DBUS_TYPE_DICT_ENTRY)
1149 BDBLOG((" arg type ARRAY with DICT_ENTRY\n"));
1151 JSObject *obj = nsnull;
1152 getDictFromArray(cx, &arrayIter, &obj);
1154 *v = OBJECT_TO_JSVAL(obj);
1156 JSObject *array = nsnull;
1157 getJSArrayFromIter(cx, &arrayIter, &array);
1158 *v = OBJECT_TO_JSVAL(array);
1162 case DBUS_TYPE_VARIANT:
1164 DBusMessageIter variantIter;
1165 dbus_message_iter_recurse(aIter, &variantIter);
1166 getJSValueFromIter(cx, &variantIter,
1167 dbus_message_iter_get_arg_type(&variantIter),
1171 case DBUS_TYPE_STRUCT:
1173 DBusMessageIter structIter;
1174 dbus_message_iter_recurse(aIter, &structIter);
1176 JSObject *array = nsnull;
1177 getJSArrayFromIter(cx, &structIter, &array);
1178 *v = OBJECT_TO_JSVAL(array);
1184 BDBLOG(("%s: Unhandled type %c\n", __FUNCTION__, aDBusType));
1191 already_AddRefed<nsIWritableVariant> getVariantFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType)
1193 nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
1194 nsIWritableVariant *retval;
1198 case DBUS_TYPE_BOOLEAN:
1201 BDBLOG((" arg type BOOLEAN: "));
1202 dbus_message_iter_get_basic(aIter, &val);
1203 BDBLOG(("%d\n", val));
1204 variant->SetAsBool(val);
1208 case DBUS_TYPE_BYTE:
1209 case DBUS_TYPE_INT16:
1210 case DBUS_TYPE_UINT16:
1211 case DBUS_TYPE_INT32:
1212 case DBUS_TYPE_UINT32:
1215 BDBLOG((" arg type INT: "));
1216 dbus_message_iter_get_basic(aIter, &val);
1217 BDBLOG(("%d\n", val));
1218 variant->SetAsUint32(val);
1221 case DBUS_TYPE_INT64:
1224 BDBLOG((" arg type INT64: "));
1225 dbus_message_iter_get_basic(aIter, &val);
1226 BDBLOG(("%lld\n", val));
1227 variant->SetAsInt64(val);
1230 case DBUS_TYPE_UINT64:
1233 BDBLOG((" arg type UINT64: "));
1234 dbus_message_iter_get_basic(aIter, &val);
1235 BDBLOG(("%llu\n", val));
1236 variant->SetAsUint64(val);
1239 case DBUS_TYPE_DOUBLE:
1242 BDBLOG((" arg type DOUBLE: "));
1243 dbus_message_iter_get_basic(aIter, &val);
1244 BDBLOG(("%f\n", val));
1245 variant->SetAsDouble(val);
1248 case DBUS_TYPE_STRING:
1249 case DBUS_TYPE_OBJECT_PATH:
1250 case DBUS_TYPE_SIGNATURE:
1253 BDBLOG((" arg type STRING/OBJECT_PATH/SIGNATURE: "));
1254 dbus_message_iter_get_basic(aIter, &tmp);
1255 nsDependentCString val(tmp);
1256 BDBLOG(("\"%s\"\n", PromiseFlatCString(val).get()));
1257 variant->SetAsAUTF8String(val);
1260 case DBUS_TYPE_ARRAY:
1262 if (dbus_message_iter_get_element_type(aIter) == DBUS_TYPE_DICT_ENTRY)
1264 BDBLOG((" arg type ARRAY with DICT_ENTRY\n"));
1266 DBusMessageIter array_iter;
1267 dbus_message_iter_recurse(aIter, &array_iter);
1269 JSObject *obj = nsnull;
1270 getDictFromArray(cx, &array_iter, &obj);
1272 // get the xpconnect service
1274 nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
1277 BDBLOG((" got nsIXPConnect\n"));
1279 // Convert to variant and return
1280 nsIVariant *var = nsnull;
1281 rv = xpc->JSToVariant(cx, OBJECT_TO_JSVAL(obj), &var);
1284 variant->SetFromVariant(var);
1287 NS_ADDREF(retval = variant);
1294 DBusMessageIter array_iter;
1295 nsCOMPtr<nsIMutableArray> items;
1296 PRUint32 item_count;
1298 BDBLOG((" arg type ARRAY\n"));
1299 dbus_message_iter_recurse(aIter, &array_iter);
1300 items = getArrayFromIter(cx, &array_iter);
1301 items->GetLength(&item_count);
1302 BDBLOG((" array: %d items\n", item_count));
1304 nsIVariant **item_array = new nsIVariant*[item_count];
1305 for (PRUint32 i = 0; i < item_count; i++)
1307 nsCOMPtr<nsIVariant> item = do_QueryElementAt(items, i);
1308 item_array[i] = item;
1311 variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
1312 &NS_GET_IID(nsIVariant),
1315 for (PRUint32 i = 0; i < item_count; i++)
1316 NS_RELEASE(item_array[i]);
1317 delete[] item_array;
1321 case DBUS_TYPE_VARIANT:
1323 BDBLOG((" arg type VARIANT\n"));
1325 DBusMessageIter variant_iter;
1326 dbus_message_iter_recurse(aIter, &variant_iter);
1328 int childType = dbus_message_iter_get_arg_type(&variant_iter);
1329 variant = getVariantFromIter(cx, &variant_iter, childType);
1333 case DBUS_TYPE_STRUCT:
1335 BDBLOG((" arg type STRUCT\n"));
1337 DBusMessageIter array_iter;
1338 nsCOMPtr<nsIMutableArray> items;
1339 PRUint32 item_count;
1341 dbus_message_iter_recurse(aIter, &array_iter);
1342 items = getArrayFromIter(cx, &array_iter);
1343 items->GetLength(&item_count);
1344 BDBLOG((" struct: %d items\n", item_count));
1346 nsIVariant **item_array = new nsIVariant*[item_count];
1347 for (PRUint32 i = 0; i < item_count; i++)
1349 nsCOMPtr<nsIVariant> item = do_QueryElementAt(items, i);
1350 item_array[i] = item;
1353 variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
1354 &NS_GET_IID(nsIVariant),
1357 for (PRUint32 i = 0; i < item_count; i++)
1358 NS_RELEASE(item_array[i]);
1359 delete[] item_array;
1365 BDBLOG((" arg type '%c' (%d)\n", aDBusType, aDBusType));
1370 NS_ADDREF(retval = variant);
1374 already_AddRefed<nsIMutableArray> getArrayFromIter(JSContext* cx, DBusMessageIter *aIter)
1377 nsCOMPtr<nsIMutableArray> array = do_CreateInstance("@mozilla.org/array;1");
1378 nsIMutableArray *retval;
1380 BDBLOG((" ++ enter getArrayFromIter\n"));
1382 while ((current_type = dbus_message_iter_get_arg_type(aIter)) != DBUS_TYPE_INVALID)
1384 nsCOMPtr<nsIWritableVariant> variant = getVariantFromIter(cx, aIter, current_type);
1386 array->AppendElement(variant, PR_FALSE);
1388 BDBLOG((" arg type '%c' (%d) not handled\n", current_type, current_type));
1390 dbus_message_iter_next(aIter);
1393 NS_ADDREF(retval = array);
1394 BDBLOG((" ++ leave getArrayFromIter\n"));
1398 /* vim: set cindent ts=4 et sw=4: */