[XPCOM] Enhance array handling, now they work inside dicts too
authorKalle Vahlman <kalle.vahlman@movial.com>
Mon, 10 Nov 2008 11:02:45 +0000 (13:02 +0200)
committerKalle Vahlman <kalle.vahlman@movial.com>
Mon, 10 Nov 2008 11:02:45 +0000 (13:02 +0200)
xpcom-dbusservice/DBusMarshaling.cpp

index 74ded6b..b71f23c 100644 (file)
@@ -30,6 +30,7 @@
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 #include "nsArrayUtils.h"
+#include "nsTArray.h"
 #include "nsMemory.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIProperties.h"
@@ -39,7 +40,7 @@
 
 #include "bdb-debug.h"
 
-void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
+void addArrayDataToIter(void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
 void addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSignatureIter *aSigIter);
 
 static void
@@ -387,6 +388,40 @@ getSignatureFromISupports(nsISupports *aISupports, nsCString &aResult)
     }
 }
 
+PRUint16 getVType(int dType)
+{
+    switch (dType)
+    {
+       case DBUS_TYPE_BOOLEAN:
+            return nsIDataType::VTYPE_BOOL;
+       case DBUS_TYPE_BYTE:
+            return nsIDataType::VTYPE_INT8;
+       case DBUS_TYPE_INT16:
+            return nsIDataType::VTYPE_INT16;
+       case DBUS_TYPE_UINT16:
+            return nsIDataType::VTYPE_UINT16;
+       case DBUS_TYPE_INT32:
+            return nsIDataType::VTYPE_INT32;
+       case DBUS_TYPE_UINT32:
+            return nsIDataType::VTYPE_UINT32;
+       case DBUS_TYPE_DOUBLE:
+            return nsIDataType::VTYPE_DOUBLE;
+       case DBUS_TYPE_STRING:
+       case DBUS_TYPE_OBJECT_PATH:
+       case DBUS_TYPE_SIGNATURE:
+            return nsIDataType::VTYPE_WCHAR_STR;
+       default:
+            break;
+    }
+
+    return -1;
+}
+
+PRBool typesMatch(PRUint16 vType, int dType)
+{
+    return (vType == getVType(dType));
+}
+
 void
 addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
 {
@@ -412,11 +447,12 @@ addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter
         {
             /* TODO: Support for non-JS Dicts */
             
-          BDBLOG(("  add dict from variant\n"));
+            BDBLOG(("  add dict from variant\n"));
 
             nsCOMPtr<nsISupports> is;
             nsIID *iid;
             // Reported by a leak, dunno why?
+            // It's a comptr so it should go away with the end of context afaik
             aVariant->GetAsInterface(&iid, getter_AddRefs(is));
 
             // test argument for nsIXPConnectWrappedJS
@@ -472,7 +508,6 @@ addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter
 
                         for (int p = 0; p < props->length; p++)
                         {
-                            // get key signature from first property name
                             jsval propname;
                             nsCAutoString tmpsig;
                             JS_IdToValue(cx, props->vector[p], &propname);
@@ -499,7 +534,11 @@ addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter
                                                     JS_GetStringLength(prop_string),
                                                     &propvalue) == JS_TRUE)
                             {
-                                addJSValueToIter(cx, &propvalue, &dictIter, &dictSigIter);
+                                nsIVariant *var = nsnull;
+                                nsresult rs = xpc->JSToVariant(cx, propvalue, &var);
+                                NS_ENSURE_SUCCESS(rs, );
+
+                                addVariantToIter(var, &dictIter, &dictSigIter);
                             }
                             
                             // Close the dict entry container
@@ -532,18 +571,63 @@ addVariantToIter(nsIVariant *aVariant, DBusMessageIter *aIter, DBusSignatureIter
                                  &count,
                                  &data_ptr);
 
-            BDBLOG(("  getSignatureFromVariant: got %d elements of type %d\n", count, type));
-            BDBLOG(("  getSignatureFromVariant: got array signature %s\n", array_signature));
+            BDBLOG(("  %s: got %d elements of type %d\n", __FUNCTION__, count, type));
+            BDBLOG(("  %s: got array signature %s\n", __FUNCTION__, array_signature));
 
-            DBusMessageIter arrayIter;
-            if (dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
-                                                 array_signature, &arrayIter))
+            int dbustype = dbus_signature_iter_get_current_type(&aChildSigIter);
+
+            if (typesMatch(type, dbustype))
             {
-                addArrayDataToIter(data_ptr, count, type, &arrayIter, &aChildSigIter);
+                BDBLOG(("*** Yay, types match!\n"));
+
+                DBusMessageIter arrayIter;
+                if (dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
+                                                     array_signature, &arrayIter))
+                {
+                    addArrayDataToIter(data_ptr, 0, count, type,
+                                       &arrayIter, &aChildSigIter);
+                    dbus_message_iter_close_container(aIter, &arrayIter);
+                }
+                nsMemory::Free(data_ptr);
+            } else {
+                BDBLOG(("*** Bummer, types don't match so we'll need to iterate\n"));
+
+                DBusMessageIter arrayIter;
+                dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
+                                                 array_signature, &arrayIter);
+
+                /* Seems stupid not to be able to iterate over the values as
+                 * nsIVariants directly, but no API to that effect seems to be
+                 * available...
+                 */
+                for (int i = 0; i < count; i++)
+                {
+                    nsCOMPtr<nsIWritableVariant> variant = do_CreateInstance("@mozilla.org/variant;1");
+                    
+                    switch (type)
+                    {
+#define SET_INT(bits) \
+    case nsIDataType::VTYPE_INT ## bits: \
+        variant->SetAsInt ## bits(*(((PRInt ## bits*)data_ptr)+i)); \
+        break; \
+    case nsIDataType::VTYPE_UINT ## bits: \
+        variant->SetAsUint ## bits(*(((PRUint ## bits*)data_ptr)+i)); \
+        break;
+                        SET_INT(16)
+                        SET_INT(32)
+                        SET_INT(64)
+                        default:
+                            BDBLOG(("*** No conversion from %i to %c\n", type, dbustype));
+                            break;
+                    }
+
+                    addVariantToIter(variant, &arrayIter, &aChildSigIter);
+                }
+
                 dbus_message_iter_close_container(aIter, &arrayIter);
+                nsMemory::Free(data_ptr);
             }
 
-            nsMemory::Free(data_ptr);
         }
     }
     else if (element_type == DBUS_TYPE_STRUCT)
@@ -702,7 +786,7 @@ void addBasicTypeToIter(nsIVariant *aVariant, DBusMessageIter *aIter, int aDBusT
     }
 }
 
-void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
+void addArrayDataToIter(void *data_ptr, PRUint32 start, PRUint32 count, PRUint16 type, DBusMessageIter *aIter, DBusSignatureIter *aSigIter)
 {
     int aDBusType = dbus_signature_iter_get_current_type(aSigIter);
     BDBLOG(("addArrayDataToIter: appending %d elements of type %d '%c'\n", count, type, aDBusType));
@@ -710,7 +794,7 @@ void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessa
     switch (type)
     {
 #define ADD_DATA \
-            for (int i = 0; i < count; i++) \
+            for (int i = start; i < count; i++) \
                 dbus_message_iter_append_basic(aIter, aDBusType, data+i)
         case nsIDataType::VTYPE_INT8:
         case nsIDataType::VTYPE_UINT8:
@@ -749,7 +833,7 @@ void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessa
         case nsIDataType::VTYPE_WCHAR_STR:
         {
             PRUnichar **data = (PRUnichar **)data_ptr;
-            for (int i = 0; i < count; i++)
+            for (int i = start; i < count; i++)
             {
                 const char *val_ptr;
                 nsCAutoString val = NS_ConvertUTF16toUTF8(data[i]);
@@ -767,7 +851,7 @@ void addArrayDataToIter(void *data_ptr, PRUint32 count, PRUint16 type, DBusMessa
         case nsIDataType::VTYPE_INTERFACE_IS:
         {
             nsISupports **data = (nsISupports **)data_ptr;
-            for (int i = 0; i < count; i++)
+            for (int i = start; i < count; i++)
             {
                 nsCOMPtr<nsIVariant> data_variant = do_QueryInterface(data[i]);
                 if (data_variant)
@@ -792,8 +876,9 @@ addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSigna
 
     int dbusType = dbus_signature_iter_get_current_type(aSigIter);
 
-    BDBLOG(("%s(%c, %s)\n", __FUNCTION__, dbusType,
-           dbus_signature_iter_get_signature(aSigIter)));
+    BDBLOG(("%s(%s, %c, %s)\n", __FUNCTION__,
+            JS_GetTypeName(cx, JS_TypeOfValue(cx, *aValue)),
+            dbusType, dbus_signature_iter_get_signature(aSigIter)));
 
     // Using the expected type instead of the actual allows autoconversion
     switch (dbusType)
@@ -826,11 +911,12 @@ addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSigna
             
             if (JS_ValueToNumber(cx, *aValue, &d))
             {
+                BDBLOG(("%s(%f)\n", __FUNCTION__, d));
                 dbus_message_iter_append_basic(aIter, dbusType, &d);
             }
             else
             {
-                BDBLOG(("%s(): Could not fetch boolean from jsvalue\n", __FUNCTION__));
+                BDBLOG(("%s(): Could not fetch number from jsvalue\n", __FUNCTION__));
             }
 
             break;
@@ -849,46 +935,19 @@ addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSigna
         {
             if (JSVAL_IS_OBJECT(*aValue) && JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*aValue)))
             {
-                JSIdArray *props = JS_Enumerate(cx, JSVAL_TO_OBJECT(*aValue));
-                if (props)
-                {
-                    BDBLOG(("    got JSIdArray\n"));
+                // Arrays are simply converted to variants and pushed to the
+                // variant code path
+                nsresult rv;
+                nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
+                if(NS_FAILED(rv))
+                    return;
+                BDBLOG(("    got nsIXPConnect\n"));
 
-                    // Open container
-                    DBusSignatureIter arraySigIter;
-                    dbus_signature_iter_recurse(aSigIter, &arraySigIter);
-                    char *array_sig = dbus_signature_iter_get_signature(&arraySigIter);
-                    
-                    DBusMessageIter arrayIter;
-                    dbus_message_iter_open_container(aIter, DBUS_TYPE_ARRAY,
-                                                     array_sig, &arrayIter);
-                    dbus_free(array_sig);
-                    
-                    for (int p = 0; p < props->length; p++)
-                    {
-                        int type = dbus_signature_iter_get_current_type(&arraySigIter);
-                        jsval propname;
-                        JS_IdToValue(cx, props->vector[p], &propname);
-                        
-                        jsval propvalue;
-                        JSString *prop_string = JS_ValueToString(cx, propname);
-                        if (JS_LookupUCProperty(cx,
-                                                JSVAL_TO_OBJECT(*aValue),
-                                                JS_GetStringChars(prop_string),
-                                                JS_GetStringLength(prop_string),
-                                                &propvalue) == JS_TRUE)
-                        {
-                            addJSValueToIter(cx, &propvalue, &arrayIter, &arraySigIter);
-                        } else {
-                            break;
-                        }
-                        
-                        dbus_signature_iter_next(&arraySigIter);
-                    }
-                    
-                    dbus_message_iter_close_container(aIter, &arrayIter);
-                    JS_DestroyIdArray(cx, props);
-                }
+                nsIVariant *var = nsnull;
+                nsresult rs = xpc->JSToVariant(cx, *aValue, &var);
+                NS_ENSURE_SUCCESS(rs, );
+
+                addVariantToIter(var, aIter, aSigIter);
             }
             
             break;
@@ -902,6 +961,9 @@ addJSValueToIter(JSContext *cx, jsval *aValue, DBusMessageIter *aIter, DBusSigna
 void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, jsval *v)
 {
 
+    BDBLOG(("%s(%c)\n", __FUNCTION__, aDBusType));
+
+
     switch (aDBusType)
     {
         case DBUS_TYPE_STRING:
@@ -924,7 +986,6 @@ void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, js
         case DBUS_TYPE_UINT32:
         case DBUS_TYPE_INT64:
         case DBUS_TYPE_UINT64:
-        case DBUS_TYPE_DOUBLE:
         {
             dbus_uint64_t val = 0;
             dbus_message_iter_get_basic(aIter, &val);
@@ -935,24 +996,44 @@ void getJSValueFromIter(JSContext* cx, DBusMessageIter *aIter, int aDBusType, js
             }
             break;
         }
+        case DBUS_TYPE_DOUBLE:
+        {
+            jsdouble val = 0.0;
+            dbus_message_iter_get_basic(aIter, &val);
+            if (!JS_NewNumberValue(cx, val, v))
+            {
+                BDBLOG(("%s: Number conversion from %c failed\n", __FUNCTION__,
+                       aDBusType));
+            }
+            break;
+        }
         case DBUS_TYPE_ARRAY:
         {
             // FIXME: implement!
-/*            
+            // FIXME: Dicts
+
             nsTArray<jsval> elems;
             
             // recurse to container
+            DBusMessageIter arrayIter;
+            dbus_message_iter_recurse(aIter, &arrayIter);
             
             // iterate over array elements
             do
             {
-                getJSValueFromIter
+                jsval cv;
+                BDBLOG(("arg type: %c\n", dbus_message_iter_get_arg_type(&arrayIter)));
+                getJSValueFromIter(cx,
+                                   &arrayIter,
+                                   dbus_message_iter_get_arg_type(&arrayIter),
+                                   &cv);
+                elems.AppendElement(cv);
                 
-            } while (iter_next);
+            } while (dbus_message_iter_next(&arrayIter));
 
             // Create an Array object with the elements
-            JSObject *array = JS_NewArrayObject(cx, 0, NULL);
-*/            
+            JSObject *array = JS_NewArrayObject(cx, elems.Length(), elems.Elements());
+            *v = OBJECT_TO_JSVAL(array);
             break;
         }
         case DBUS_TYPE_STRUCT: