2003-03-31 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-marshal.c
index 1462936..2222ad9 100644 (file)
 
 #include "dbus-marshal.h"
 #include "dbus-internals.h"
+#define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
+#include "dbus-string-private.h"
 
 #include <string.h>
 
-#define DBUS_UINT32_SWAP_LE_BE_CONSTANT(val)   ((dbus_uint32_t) ( \
-    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x000000ffU) << 24) |  \
-    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x0000ff00U) <<  8) |  \
-    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0x00ff0000U) >>  8) |  \
-    (((dbus_uint32_t) (val) & (dbus_uint32_t) 0xff000000U) >> 24)))
-
-#define DBUS_UINT32_SWAP_LE_BE(val) (DBUS_UINT32_SWAP_LE_BE_CONSTANT (val))
-
-#ifdef WORDS_BIGENDIAN
-#define DBUS_INT32_TO_BE(val)  ((dbus_int32_t) (val))
-#define DBUS_UINT32_TO_BE(val) ((dbus_uint32_t) (val))
-#define DBUS_INT32_TO_LE(val)  ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
-#define DBUS_UINT32_TO_LE(val) (DBUS_UINT32_SWAP_LE_BE (val))
-#else
-#define DBUS_INT32_TO_LE(val)  ((dbus_int32_t) (val))
-#define DBUS_UINT32_TO_LE(val) ((dbus_uint32_t) (val))
-#define DBUS_INT32_TO_BE(val)  ((dbus_int32_t) DBUS_UINT32_SWAP_LE_BE (val))
-#define DBUS_UINT32_TO_BE(val) (DBUS_UINT32_SWAP_LE_BE (val))
-#endif
-
-/* The transformation is symmetric, so the FROM just maps to the TO. */
-#define DBUS_INT32_FROM_LE(val)         (DBUS_INT32_TO_LE (val))
-#define DBUS_UINT32_FROM_LE(val) (DBUS_UINT32_TO_LE (val))
-#define DBUS_INT32_FROM_BE(val)         (DBUS_INT32_TO_BE (val))
-#define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val))
-
-
 /* from ORBit */
 static void
 swap_bytes (unsigned char *data,
@@ -72,9 +47,27 @@ swap_bytes (unsigned char *data,
     }
 }
 
-static dbus_uint32_t
-unpack_uint32 (int                  byte_order,
-               const unsigned char *data)
+/**
+ * @defgroup DBusMarshal marshaling and unmarshaling
+ * @ingroup  DBusInternals
+ * @brief functions to marshal/unmarshal data from the wire
+ *
+ * Types and functions related to converting primitive data types from
+ * wire format to native machine format, and vice versa.
+ *
+ * @{
+ */
+
+/**
+ * Unpacks a 32 bit unsigned integer from a data pointer
+ *
+ * @param byte_order The byte order to use
+ * @param data the data pointer
+ * @returns the integer
+ */
+dbus_uint32_t
+_dbus_unpack_uint32 (int                  byte_order,
+                     const unsigned char *data)
 {
   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
   
@@ -82,18 +75,18 @@ unpack_uint32 (int                  byte_order,
     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
   else
     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
-}             
+}  
 
 /**
- * Unpacks a 32 bit unsigned integer from a data pointer
+ * Unpacks a 32 bit signed integer from a data pointer
  *
  * @param byte_order The byte order to use
  * @param data the data pointer
  * @returns the integer
  */
 dbus_int32_t
-dbus_unpack_int32 (int                  byte_order,
-                  const unsigned char *data)
+_dbus_unpack_int32 (int                  byte_order,
+                    const unsigned char *data)
 {
   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
   
@@ -104,27 +97,36 @@ dbus_unpack_int32 (int                  byte_order,
 }
 
 /**
- * @defgroup DBusMarshal marshaling and unmarshaling
- * @ingroup  DBusInternals
- * @brief functions to marshal/unmarshal data from the wire
- *
- * Types and functions related to converting primitive data types from
- * wire format to native machine format, and vice versa.
+ * Packs a 32 bit unsigned integer into a data pointer.
  *
- * @{
+ * @param value the value
+ * @param byte_order the byte order to use
+ * @param data the data pointer
  */
+void
+_dbus_pack_uint32 (dbus_uint32_t   value,
+                   int             byte_order,
+                   unsigned char  *data)
+{
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
+  
+  if ((byte_order) == DBUS_LITTLE_ENDIAN)                  
+    *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_LE (value);       
+  else
+    *((dbus_uint32_t*)(data)) = DBUS_UINT32_TO_BE (value);
+}
 
 /**
- * Packs a 32 bit unsigned integer into a data pointer.
+ * Packs a 32 bit signed integer into a data pointer.
  *
  * @param value the value
  * @param byte_order the byte order to use
  * @param data the data pointer
  */
 void
-dbus_pack_int32 (dbus_int32_t   value,
-                int            byte_order,
-                unsigned char *data)
+_dbus_pack_int32 (dbus_int32_t   value,
+                  int            byte_order,
+                  unsigned char *data)
 {
   _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
   
@@ -135,6 +137,97 @@ dbus_pack_int32 (dbus_int32_t   value,
 }
 
 /**
+ * Sets the 4 bytes at the given offset to a marshaled signed integer,
+ * replacing anything found there previously.
+ *
+ * @param str the string to write the marshalled int to
+ * @param offset the byte offset where int should be written
+ * @param byte_order the byte order to use
+ * @param value the value
+ * 
+ */
+void
+_dbus_marshal_set_int32 (DBusString          *str,
+                         int                  byte_order,
+                         int                  offset,
+                         dbus_int32_t         value)
+{
+  char *data;
+  
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+  
+  data = _dbus_string_get_data_len (str, offset, 4);
+
+  _dbus_pack_int32 (value, byte_order, data);
+}
+
+/**
+ * Sets the 4 bytes at the given offset to a marshaled unsigned
+ * integer, replacing anything found there previously.
+ *
+ * @param str the string to write the marshalled int to
+ * @param offset the byte offset where int should be written
+ * @param byte_order the byte order to use
+ * @param value the value
+ * 
+ */
+void
+_dbus_marshal_set_uint32 (DBusString          *str,
+                          int                  byte_order,
+                          int                  offset,
+                          dbus_uint32_t        value)
+{
+  char *data;
+  
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+  
+  data = _dbus_string_get_data_len (str, offset, 4);
+
+  _dbus_pack_uint32 (value, byte_order, data);
+}
+
+/**
+ * Sets the existing marshaled string at the given offset with
+ * a new marshaled string. The given offset must point to
+ * an existing string or the wrong length will be deleted
+ * and replaced with the new string.
+ *
+ * @param str the string to write the marshalled string to
+ * @param offset the byte offset where string should be written
+ * @param byte_order the byte order to use
+ * @param value the value
+ * @param len the length to use
+ * @returns #TRUE on success
+ * 
+ */
+dbus_bool_t
+_dbus_marshal_set_string (DBusString          *str,
+                          int                  byte_order,
+                          int                  offset,
+                          const DBusString    *value,
+                         int                  len)
+{
+  int old_len;
+  
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+  
+  old_len = _dbus_demarshal_uint32 (str, byte_order,
+                                    offset, NULL);
+
+  if (!_dbus_string_replace_len (value, 0, len,
+                                 str, offset + 4, old_len))
+    return FALSE;
+
+  _dbus_marshal_set_uint32 (str, byte_order,
+                            offset, len);
+
+  return TRUE;
+}
+
+/**
  * Marshals a double value.
  *
  * @param str the string to append the marshalled value to
@@ -147,9 +240,9 @@ _dbus_marshal_double (DBusString *str,
                      int         byte_order,
                      double      value)
 {
-  if (!_dbus_string_set_length (str,
-                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
-                                                 sizeof (double))))
+  _dbus_assert (sizeof (double) == 8);
+
+  if (!_dbus_string_align_length (str, sizeof (double)))
     return FALSE;
   
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
@@ -171,13 +264,11 @@ _dbus_marshal_int32  (DBusString   *str,
                      int           byte_order,
                      dbus_int32_t  value)
 {
-  if (!_dbus_string_set_length (str,
-                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
-                                                 sizeof (dbus_int32_t))))
+  if (!_dbus_string_align_length (str, sizeof (dbus_int32_t)))
     return FALSE;
   
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-    swap_bytes ((unsigned char *)&value, sizeof (dbus_int32_t));
+    value = DBUS_INT32_SWAP_LE_BE (value);
 
   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_int32_t));
 }
@@ -195,13 +286,11 @@ _dbus_marshal_uint32 (DBusString    *str,
                      int            byte_order,
                      dbus_uint32_t  value)
 {
-  if (!_dbus_string_set_length (str,
-                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
-                                                 sizeof (dbus_uint32_t))))
+  if (!_dbus_string_align_length (str, sizeof (dbus_uint32_t)))
     return FALSE;
-
+  
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-    swap_bytes ((unsigned char *)&value, sizeof (dbus_uint32_t));
+    value = DBUS_UINT32_SWAP_LE_BE (value);
 
   return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
 }
@@ -241,8 +330,8 @@ _dbus_marshal_string (DBusString    *str,
  *
  * @param str the string to append the marshalled value to
  * @param byte_order the byte order to use
- * @param value the byte array
- * @param len the length of the byte array
+ * @param value the array
+ * @param len number of elements in the array
  * @returns #TRUE on success
  */
 dbus_bool_t
@@ -263,9 +352,339 @@ _dbus_marshal_byte_array (DBusString          *str,
       return FALSE;
     }
 
-  return _dbus_string_append_len (str, value, len);
+  if (len == 0)
+    return TRUE;
+  else
+    return _dbus_string_append_len (str, value, len);
+}
+
+/**
+ * Marshals a 32 bit signed integer array
+ *
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param value the array
+ * @param len the length of the array
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_int32_array (DBusString         *str,
+                          int                 byte_order,
+                          const dbus_int32_t *value,
+                          int                 len)
+{
+  int i, old_string_len;
+
+  old_string_len = _dbus_string_get_length (str);
+
+  if (!_dbus_marshal_uint32 (str, byte_order, len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    if (!_dbus_marshal_int32 (str, byte_order, value[i]))
+      goto error;
+
+  return TRUE;
+  
+ error:
+  /* Restore previous length */
+  _dbus_string_set_length (str, old_string_len);
+  
+  return FALSE;
+}
+
+/**
+ * Marshals a 32 bit unsigned integer array
+ *
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param value the array
+ * @param len the length of the array
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_uint32_array (DBusString          *str,
+                           int                  byte_order,
+                           const dbus_uint32_t  *value,
+                           int                  len)
+{
+  int i, old_string_len;
+
+  old_string_len = _dbus_string_get_length (str);
+
+  if (!_dbus_marshal_uint32 (str, byte_order, len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    if (!_dbus_marshal_uint32 (str, byte_order, value[i]))
+      goto error;
+
+  return TRUE;
+  
+ error:
+  /* Restore previous length */
+  _dbus_string_set_length (str, old_string_len);
+  
+  return FALSE;  
+}
+
+/**
+ * Marshals a double array
+ *
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param value the array
+ * @param len the length of the array
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_double_array (DBusString          *str,
+                           int                  byte_order,
+                           const double        *value,
+                           int                  len)
+{
+  int i, old_string_len;
+
+  old_string_len = _dbus_string_get_length (str);
+
+  if (!_dbus_marshal_uint32 (str, byte_order, len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    if (!_dbus_marshal_double (str, byte_order, value[i]))
+      goto error;
+
+  return TRUE;
+  
+ error:
+  /* Restore previous length */
+  _dbus_string_set_length (str, old_string_len);
+  
+  return FALSE;    
+}
+
+/**
+ * Marshals a string array
+ *
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param value the array
+ * @param len the length of the array
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_string_array (DBusString  *str,
+                           int          byte_order,
+                           const char **value,
+                           int          len)
+{
+  int i, old_string_len;
+
+  old_string_len = _dbus_string_get_length (str);
+
+  if (!_dbus_marshal_uint32 (str, byte_order, len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    if (!_dbus_marshal_string (str, byte_order, value[i]))
+      goto error;
+
+  return TRUE;
+  
+ error:
+  /* Restore previous length */
+  _dbus_string_set_length (str, old_string_len);
+  
+  return FALSE;      
+}
+
+
+/**
+ * Marshals a dict
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param dict the dict
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_dict (DBusString *str,
+                   int         byte_order,
+                   DBusDict   *dict)
+{
+  int old_string_len;
+  int i, len;
+  char **keys;
+  
+  old_string_len = _dbus_string_get_length (str);
+
+  if (!dbus_dict_get_keys (dict, &keys, &len))
+    goto error;
+
+  if (len == 0)
+    return TRUE;
+
+  if (!_dbus_marshal_string_array (str, byte_order,
+                                  (const char **)keys, len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    {
+      int value_type;
+
+      value_type = dbus_dict_get_value_type (dict, keys[i]);
+
+      if (!_dbus_string_append_byte (str, value_type))
+       goto error;
+      
+      switch (dbus_dict_get_value_type (dict, keys[i]))
+       {
+       case DBUS_TYPE_BOOLEAN:
+         {
+           dbus_bool_t value;
+
+           if (!dbus_dict_get_boolean (dict, keys[i], &value))
+             goto error;
+           
+           if (!_dbus_string_append_byte (str, (value != FALSE)))
+             goto error;
+
+           break;
+         }
+         
+       case DBUS_TYPE_INT32:
+         {
+           dbus_int32_t value;
+           
+           if (!dbus_dict_get_int32 (dict, keys[i], &value))
+             goto error;
+           
+           if (!_dbus_marshal_int32 (str, byte_order, value))
+             goto error;
+
+           break;
+         }
+       case DBUS_TYPE_UINT32:
+         {
+           dbus_uint32_t value;
+           
+           if (!dbus_dict_get_uint32 (dict, keys[i], &value))
+             goto error;
+           
+           if (!_dbus_marshal_uint32 (str, byte_order, value))
+             goto error;
+
+           break;
+         }
+       case DBUS_TYPE_DOUBLE:
+         {
+           double value;
+           
+           if (!dbus_dict_get_double (dict, keys[i], &value))
+             goto error;
+
+           if (!_dbus_marshal_double (str, byte_order, value))
+             goto error;
+
+           break;
+         }
+       case DBUS_TYPE_INT32_ARRAY:
+         {
+           const dbus_int32_t *value;
+           int len;
+
+           if (!dbus_dict_get_int32_array (dict, keys[i], &value, &len))
+             goto error;
+
+           if (!_dbus_marshal_int32_array (str, byte_order, value, len))
+             goto error;
+           
+           break;
+         }
+       case DBUS_TYPE_STRING:
+         {
+           const char *value;
+
+           if (!dbus_dict_get_string (dict, keys[i], &value))
+             goto error;
+
+           if (!_dbus_marshal_string (str, byte_order, value))
+             goto error;
+           
+           break;
+         }       
+       case DBUS_TYPE_BOOLEAN_ARRAY:
+         {
+           const unsigned char *value;
+           int len;
+
+           if (!dbus_dict_get_boolean_array (dict, keys[i], &value, &len))
+             goto error;
+
+           if (!_dbus_marshal_byte_array (str, byte_order, value, len))
+             goto error;
+           
+           break;
+         }       
+       case DBUS_TYPE_UINT32_ARRAY:
+         {
+           const dbus_uint32_t *value;
+           int len;
+
+           if (!dbus_dict_get_uint32_array (dict, keys[i], &value, &len))
+             goto error;
+
+           if (!_dbus_marshal_uint32_array (str, byte_order, value, len))
+             goto error;
+           
+           break;
+         }       
+       case DBUS_TYPE_DOUBLE_ARRAY:
+         {
+           const double *value;
+           int len;
+
+           if (!dbus_dict_get_double_array (dict, keys[i], &value, &len))
+             goto error;
+
+           if (!_dbus_marshal_double_array (str, byte_order, value, len))
+             goto error;
+           
+           break;
+         }
+       case DBUS_TYPE_STRING_ARRAY:
+         {
+           const char **value;
+           int len;
+
+           if (!dbus_dict_get_string_array (dict, keys[i], &value, &len))
+             goto error;
+
+           if (!_dbus_marshal_string_array (str, byte_order, (const char **)value, len))
+             goto error;
+           
+           break;
+         }
+       default:
+         _dbus_warn ("unkown value type %d\n", dbus_dict_get_value_type (dict, keys[i]));
+         _dbus_assert_not_reached ("unknown value type in dict");
+       }
+    }
+
+  dbus_free_string_array (keys);
+
+  return TRUE;
+  
+ error:
+  
+  dbus_free_string_array (keys);
+  
+  /* Restore previous length */
+  _dbus_string_set_length (str, old_string_len);
+
+  return FALSE;
 }
 
+
 /**
  * Demarshals a double.
  *
@@ -276,7 +695,7 @@ _dbus_marshal_byte_array (DBusString          *str,
  * @returns the demarshaled double.
  */
 double
-_dbus_demarshal_double (DBusString  *str,
+_dbus_demarshal_double (const DBusString  *str,
                        int          byte_order,
                        int          pos,
                        int         *new_pos)
@@ -286,7 +705,7 @@ _dbus_demarshal_double (DBusString  *str,
 
   pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
 
-  _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
+  buffer = _dbus_string_get_const_data_len (str, pos, sizeof (double));
 
   retval = *(double *)buffer;
   
@@ -309,21 +728,22 @@ _dbus_demarshal_double (DBusString  *str,
  * @returns the demarshaled integer.
  */
 dbus_int32_t
-_dbus_demarshal_int32  (DBusString *str,
-                       int         byte_order,
-                       int         pos,
-                       int        *new_pos)
+_dbus_demarshal_int32  (const DBusString *str,
+                       int               byte_order,
+                       int               pos,
+                       int              *new_pos)
 {
-  const char *buffer;
-
+  const DBusRealString *real = (const DBusRealString*) str;
+  
   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
   
-  _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
-
   if (new_pos)
     *new_pos = pos + sizeof (dbus_int32_t);
 
-  return dbus_unpack_int32 (byte_order, buffer);
+  if (byte_order == DBUS_LITTLE_ENDIAN)
+    return DBUS_INT32_FROM_LE (*(dbus_int32_t*)(real->str + pos));
+  else
+    return DBUS_INT32_FROM_BE (*(dbus_int32_t*)(real->str + pos));
 }
 
 /**
@@ -336,21 +756,22 @@ _dbus_demarshal_int32  (DBusString *str,
  * @returns the demarshaled integer.
  */
 dbus_uint32_t
-_dbus_demarshal_uint32  (DBusString *str,
+_dbus_demarshal_uint32  (const DBusString *str,
                         int         byte_order,
                         int         pos,
                         int        *new_pos)
 {
-  const char *buffer;
-
+  const DBusRealString *real = (const DBusRealString*) str;
+  
   pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
   
-  _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
-
   if (new_pos)
     *new_pos = pos + sizeof (dbus_uint32_t);
 
-  return unpack_uint32 (byte_order, buffer);
+  if (byte_order == DBUS_LITTLE_ENDIAN)
+    return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)(real->str + pos));
+  else
+    return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)(real->str + pos));
 }
 
 /**
@@ -360,6 +781,9 @@ _dbus_demarshal_uint32  (DBusString *str,
  * that it's  valid UTF-8, and maybe "fix" the string
  * if it's broken?
  *
+ * @todo Should probably demarshal to a DBusString,
+ * having memcpy() in here is Evil(tm).
+ *
  * @param str the string containing the data
  * @param byte_order the byte order
  * @param pos the position in the string
@@ -367,7 +791,7 @@ _dbus_demarshal_uint32  (DBusString *str,
  * @returns the demarshaled string.
  */
 char *
-_dbus_demarshal_string (DBusString *str,
+_dbus_demarshal_string (const DBusString *str,
                        int         byte_order,
                        int         pos,
                        int        *new_pos)
@@ -375,7 +799,7 @@ _dbus_demarshal_string (DBusString *str,
   int len;
   char *retval;
   const char *data;
-
+  
   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
 
   retval = dbus_malloc (len + 1);
@@ -383,7 +807,7 @@ _dbus_demarshal_string (DBusString *str,
   if (!retval)
     return NULL;
 
-  _dbus_string_get_const_data_len (str, &data, pos, len);
+  data = _dbus_string_get_const_data_len (str, pos, len);
 
   if (!data)
     return NULL;
@@ -396,12 +820,28 @@ _dbus_demarshal_string (DBusString *str,
   return retval;
 }
 
-unsigned char *
-_dbus_demarshal_byte_array (DBusString *str,
-                           int         byte_order,
-                           int         pos,
-                           int        *new_pos,
-                           int        *array_len)
+/**
+ * Demarshals a byte array.
+ *
+ * @todo Should probably demarshal to a DBusString,
+ * having memcpy() in here is Evil(tm).
+ *
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param array the array
+ * @param array_len length of the demarshaled data
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_demarshal_byte_array (const DBusString  *str,
+                           int                byte_order,
+                           int                pos,
+                           int               *new_pos,
+                           unsigned char    **array,
+                           int               *array_len)
 {
   int len;
   unsigned char *retval;
@@ -409,50 +849,500 @@ _dbus_demarshal_byte_array (DBusString *str,
 
   len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
 
+  if (len == 0)
+    {
+      *array_len = len;
+      *array = NULL;
+
+      if (new_pos)
+       *new_pos = pos;
+      
+      return TRUE;
+    }
+  
   retval = dbus_malloc (len);
 
   if (!retval)
-    return NULL;
+    return FALSE;
 
-  _dbus_string_get_const_data_len (str, &data, pos, len);
+  data = _dbus_string_get_const_data_len (str, pos, len);
 
   if (!data)
-    return NULL;
+    {
+      dbus_free (retval);
+      return FALSE;
+    }
 
   memcpy (retval, data, len);
 
   if (new_pos)
     *new_pos = pos + len;
 
-  if (array_len)
-    *array_len = len;
-
-  return retval;
+  *array = retval;
+  *array_len = len;
+  
+  return TRUE;
 }
 
-/** 
- * Returns the position right after the end position 
- * end position of a field
+/**
+ * Demarshals a 32 bit signed integer array.
  *
- * @param str a string
- * @param byte_order the byte order to use
- * @param pos the pos where the field starts
- * @param end_pos pointer where the position right
- * after the end position will follow
- * @returns TRUE if more data exists after the field
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param array the array
+ * @param array_len length of the demarshaled data
+ * @returns #TRUE on success
  */
 dbus_bool_t
-_dbus_marshal_get_field_end_pos (DBusString *str,
-                                int         byte_order,
-                                int         pos,
-                                int        *end_pos)
+_dbus_demarshal_int32_array (const DBusString  *str,
+                            int                byte_order,
+                            int                pos,
+                            int               *new_pos,
+                            dbus_int32_t     **array,
+                            int               *array_len)
 {
-  const char *data;
+  int len, i;
+  dbus_int32_t *retval;
+  
+  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
 
-  if (pos >= _dbus_string_get_length (str))
-    return FALSE;
+  if (len == 0)
+    {
+      *array_len = 0;
+      *array = NULL;
 
-  _dbus_string_get_const_data_len (str, &data, pos, 1);
+      if (new_pos)
+       *new_pos = pos;
+      
+      return TRUE;
+    }
+  
+  retval = dbus_new (dbus_int32_t, len);
+  
+  if (!retval)
+    return FALSE;
+
+  for (i = 0; i < len; i++)
+    retval[i] = _dbus_demarshal_int32 (str, byte_order, pos, &pos);
+
+  if (new_pos)
+    *new_pos = pos;
+
+  *array_len = len;
+  *array = retval;
+  
+  return TRUE;
+}
+
+/**
+ * Demarshals a 32 bit unsigned integer array.
+ *
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param array the array
+ * @param array_len length of the demarshaled data
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_demarshal_uint32_array (const DBusString  *str,
+                             int                byte_order,
+                             int                pos,
+                             int               *new_pos,
+                             dbus_uint32_t    **array,
+                             int               *array_len)
+{
+  int len, i;
+  dbus_uint32_t *retval;
+  
+  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+  if (len == 0)
+    {
+      *array_len = 0;
+      *array = NULL;
+
+      if (new_pos)
+       *new_pos = pos;
+      
+      return TRUE;
+    }
+  
+  retval = dbus_new (dbus_uint32_t, len);
+
+  if (!retval)
+    return FALSE;
+
+  for (i = 0; i < len; i++)
+    retval[i] = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+  if (new_pos)
+    *new_pos = pos;
+
+  *array_len = len;
+  *array = retval;
+  
+  return TRUE;  
+}
+
+/**
+ * Demarshals a double array.
+ *
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param array the array
+ * @param array_len length of the demarshaled data
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_demarshal_double_array (const DBusString  *str,
+                             int                byte_order,
+                             int                pos,
+                             int               *new_pos,
+                             double           **array,
+                             int               *array_len)
+{
+  int len, i;
+  double *retval;
+  
+  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+  if (len == 0)
+    {
+      *array_len = 0;
+      *array = NULL;
+
+      if (new_pos)
+       *new_pos = pos;
+      
+      return TRUE;
+    }
+  
+  retval = dbus_new (double, len);
+
+  if (!retval)
+    return FALSE;
+
+  for (i = 0; i < len; i++)
+    retval[i] = _dbus_demarshal_double (str, byte_order, pos, &pos);
+
+  if (new_pos)
+    *new_pos = pos;
+
+  *array_len = len;
+  *array = retval;
+  
+  return TRUE; 
+}
+
+/**
+ * Demarshals a string array.
+ *
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param array the array
+ * @param array_len length of the demarshaled data
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_demarshal_string_array (const DBusString   *str,
+                             int                 byte_order,
+                             int                 pos,
+                             int                *new_pos,
+                             char             ***array,
+                             int                *array_len)
+{
+  int len, i, j;
+  char **retval;
+
+  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+  if (len == 0)
+    {
+      *array_len = 0;
+      *array = NULL;
+
+      if (new_pos)
+       *new_pos = pos;
+      
+      return TRUE;
+    }
+  
+  retval = dbus_new (char *, len + 1);
+
+  if (!retval)
+    return FALSE;
+
+  retval[len] = NULL;
+  
+  for (i = 0; i < len; i++)
+    {
+      retval[i] = _dbus_demarshal_string (str, byte_order, pos, &pos);
+
+      if (retval[i] == 0)
+       goto error;
+    }
+
+ if (new_pos)
+    *new_pos = pos;
+
+ *array = retval;
+ *array_len = len;
+  
+  return TRUE;
+
+ error:
+  for (j = 0; j < i; j++)
+    dbus_free (retval[i]);
+  dbus_free (retval);
+
+  return FALSE;
+}
+
+/**
+ * Demarshals a dict
+ *
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position in the string
+ * @param dict the dict
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_demarshal_dict (const DBusString *str,
+                     int               byte_order,
+                     int               pos,
+                     int              *new_pos,
+                     DBusDict       **dict)
+{
+  char **keys;
+  int i, len;
+  
+  *dict = dbus_dict_new ();
+  if (!*dict)
+    return FALSE;
+
+  if (!_dbus_demarshal_string_array (str, byte_order, pos, &pos, &keys, &len))
+    goto error;
+
+  for (i = 0; i < len; i++)
+    {
+      int value_type;
+      
+      switch ((value_type = _dbus_string_get_byte (str, pos ++)))
+       {
+       case DBUS_TYPE_BOOLEAN:
+         {
+           dbus_bool_t value;
+
+           value = _dbus_string_get_byte (str, pos ++);
+
+           if (!dbus_dict_set_boolean (*dict, keys[i], value))
+             goto error;
+           break;
+         }
+       case DBUS_TYPE_INT32:
+         {
+           dbus_int32_t value;
+
+           value = _dbus_demarshal_int32 (str, byte_order, pos, &pos);
+
+           if (!dbus_dict_set_int32 (*dict, keys[i], value))
+             goto error;
+           
+           break;
+         }
+       case DBUS_TYPE_UINT32:
+         {
+           dbus_uint32_t value;
+
+           value = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+           if (!dbus_dict_set_uint32 (*dict, keys[i], value))
+             goto error;
+           
+           break;
+         }
+       case DBUS_TYPE_DOUBLE:
+         {
+           double value;
+
+           value = _dbus_demarshal_double (str, byte_order, pos, &pos);
+
+           if (!dbus_dict_set_double (*dict, keys[i], value))
+             goto error;
+           
+           break;
+         }
+       case DBUS_TYPE_STRING:
+         {
+           char *value;
+
+           value = _dbus_demarshal_string (str, byte_order, pos, &pos);
+
+           if (!value)
+             goto error;
+
+           if (!dbus_dict_set_string (*dict, keys[i], value))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           
+           break;
+         }
+       case DBUS_TYPE_BOOLEAN_ARRAY:
+         {
+           unsigned char *value;
+           int len;
+           
+           if (!_dbus_demarshal_byte_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_boolean_array (*dict, keys[i], value, len))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           break;
+         }
+       case DBUS_TYPE_INT32_ARRAY:
+         {
+           dbus_int32_t *value;
+           int len;
+           
+           if (!_dbus_demarshal_int32_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_int32_array (*dict, keys[i], value, len))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           break;
+         }
+       case DBUS_TYPE_UINT32_ARRAY:
+         {
+           dbus_uint32_t *value;
+           int len;
+           
+           if (!_dbus_demarshal_uint32_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_uint32_array (*dict, keys[i], value, len))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           break;
+         }
+       case DBUS_TYPE_DOUBLE_ARRAY:
+         {
+           double *value;
+           int len;
+           
+           if (!_dbus_demarshal_double_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_double_array (*dict, keys[i], value, len))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           break;
+         }
+       case DBUS_TYPE_BYTE_ARRAY:
+         {
+           unsigned char *value;
+           int len;
+           
+           if (!_dbus_demarshal_byte_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_byte_array (*dict, keys[i], value, len))
+             {
+               dbus_free (value);
+               goto error;
+             }
+
+           dbus_free (value);
+           break;
+         }
+       case DBUS_TYPE_STRING_ARRAY:
+         {
+           char **value;
+           int len;
+           
+           if (!_dbus_demarshal_string_array (str, byte_order, pos, &pos, &value, &len))
+             goto error;
+
+           if (!dbus_dict_set_string_array (*dict, keys[i], (const char **)value, len))
+             {
+               dbus_free_string_array (value);
+               goto error;
+             }
+
+           dbus_free_string_array (value);
+           break;
+         }
+       default:
+         _dbus_warn ("unknown value type %d\n", value_type);
+         _dbus_assert_not_reached ("unknown value arg");
+       }
+    }
+  
+  dbus_free_string_array (keys);
+  return TRUE;
+  
+ error:
+  dbus_free_string_array (keys);
+  dbus_dict_unref (*dict);
+  
+  return FALSE;
+}
+
+/** 
+ * Returns the position right after the end of an argument.  PERFORMS
+ * NO VALIDATION WHATSOEVER. The message must have been previously
+ * validated.
+ *
+ * @param str a string
+ * @param byte_order the byte order to use
+ * @param pos the pos where the arg starts
+ * @param end_pos pointer where the position right
+ * after the end position will follow
+ * @returns TRUE if more data exists after the arg
+ */
+dbus_bool_t
+_dbus_marshal_get_arg_end_pos (const DBusString *str,
+                               int               byte_order,
+                               int               pos,
+                               int              *end_pos)
+{
+  const char *data;
+
+  if (pos >= _dbus_string_get_length (str))
+    return FALSE;
+
+  data = _dbus_string_get_const_data_len (str, pos, 1);
   
   switch (*data)
     {
@@ -460,6 +1350,14 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
       return FALSE;
       break;
 
+    case DBUS_TYPE_NIL:
+      *end_pos = pos + 1;
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      *end_pos = pos + 2;
+      break;
+      
     case DBUS_TYPE_INT32:
       *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
 
@@ -477,39 +1375,482 @@ _dbus_marshal_get_field_end_pos (DBusString *str,
 
     case DBUS_TYPE_STRING:
       {
+       int len;
+
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
+
+       *end_pos = pos + len + 1;
+      }
+      break;
+
+    case DBUS_TYPE_BOOLEAN_ARRAY:
+    case DBUS_TYPE_BYTE_ARRAY:
+      {
+       int len;
+
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
+       
+       *end_pos = pos + len;
+      }
+      break;
+
+    case DBUS_TYPE_INT32_ARRAY:
+      {
        int len, new_pos;
 
        /* Demarshal the length */
        len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
+       
+       *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_int32_t))
+         + (len * sizeof (dbus_int32_t));
+      }
+      break;
 
-       *end_pos = new_pos + len + 1;
+    case DBUS_TYPE_UINT32_ARRAY:
+      {
+       int len, new_pos;
 
-       break;
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
+
+       *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (dbus_uint32_t))
+         + (len * sizeof (dbus_uint32_t));
       }
+      break;
 
-    case DBUS_TYPE_BYTE_ARRAY:
+    case DBUS_TYPE_DOUBLE_ARRAY:
       {
        int len, new_pos;
-
+       
        /* Demarshal the length */
        len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
+
+       *end_pos = _DBUS_ALIGN_VALUE (new_pos, sizeof (double))
+         + (len * sizeof (double));
+      }
+      break;
+      
+    case DBUS_TYPE_STRING_ARRAY:
+      {
+       int len, i;
        
-       *end_pos = new_pos + len;
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
+
+       for (i = 0; i < len; i++)
+         {
+           int str_len;
+           
+           /* Demarshal string length */
+           str_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+           pos += str_len + 1;
+         }
+
+       *end_pos = pos;
+      }
+      break;
+
+    case DBUS_TYPE_DICT:
+      {
+       int len, i;
 
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &pos);
+
+       for (i = 0; i < len; i++)
+         {
+           int str_len;
+           
+           /* Demarshal string length */
+           str_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+           pos += str_len + 1;
+         }
+
+       /* Now check the values */
+       for (i = 0; i < len; i++)
+         {
+           if (!_dbus_marshal_get_arg_end_pos (str, byte_order, pos, &pos))
+               return FALSE;
+         }
+
+       *end_pos = pos;
+       
        break;
       }
+    default:
+      _dbus_warn ("Unknown message arg type %d\n", *data);
+      _dbus_assert_not_reached ("Unknown message argument type\n");
+      return FALSE;
+    }
+
+  if (*end_pos > _dbus_string_get_length (str))
+    return FALSE;
+  
+  return TRUE;
+}
+
+/**
+ * Demarshals and validates a length; returns < 0 if the validation
+ * fails. The length is required to be small enough that
+ * len*sizeof(double) will not overflow, and small enough to fit in a
+ * signed integer. DOES NOT check whether the length points
+ * beyond the end of the string, because it doesn't know the
+ * size of array elements.
+ *
+ * @param str the string
+ * @param byte_order the byte order
+ * @param pos the unaligned string position (snap to next aligned)
+ * @param new_pos return location for new position.
+ */
+static int
+demarshal_and_validate_len (const DBusString *str,
+                            int               byte_order,
+                            int               pos,
+                            int              *new_pos)
+{
+  int align_4 = _DBUS_ALIGN_VALUE (pos, 4);
+  unsigned int len;
+
+  _dbus_assert (new_pos != NULL);
+  
+  if ((align_4 + 4) > _dbus_string_get_length (str))
+    {
+      _dbus_verbose ("not enough room in message for array length\n");
+      return -1;
+    }
+  
+  if (!_dbus_string_validate_nul (str, pos,
+                                  align_4 - pos))
+    {
+      _dbus_verbose ("array length alignment padding not initialized to nul\n");
+      return -1;
+    }
+
+  len = _dbus_demarshal_uint32 (str, byte_order, align_4, new_pos);
+
+  /* note that the len may be a number of doubles, so we need it to be
+   * at least SIZE_T_MAX / 8, but make it smaller just to keep things
+   * sane.  We end up using ints for most sizes to avoid unsigned mess
+   * so limit to maximum 32-bit signed int divided by at least 8, more
+   * for a bit of paranoia margin. INT_MAX/32 is about 65 megabytes.
+   */  
+#define MAX_ARRAY_LENGTH (((unsigned int)_DBUS_INT_MAX) / 32)
+  if (len > MAX_ARRAY_LENGTH)
+    {
+      _dbus_verbose ("array length %u exceeds maximum of %u\n",
+                     len, MAX_ARRAY_LENGTH);
+      return -1;
+    }
+  else
+    return (int) len;
+}
+
+static dbus_bool_t
+validate_string (const DBusString *str,
+                 int               pos,
+                 int               len_without_nul,
+                 int              *end_pos)
+{
+  *end_pos = pos + len_without_nul + 1;
+  
+  if (*end_pos > _dbus_string_get_length (str))
+    {
+      _dbus_verbose ("string length outside length of the message\n");
+      return FALSE;
+    }
+  
+  if (_dbus_string_get_byte (str, pos + len_without_nul) != '\0')
+    {
+      _dbus_verbose ("string arg not nul-terminated\n");
+      return FALSE;
+    }
+  
+  if (!_dbus_string_validate_utf8 (str, pos, len_without_nul))
+    {
+      _dbus_verbose ("string is not valid UTF-8\n");
+      return FALSE;
+    }
+
+  return TRUE;
+}   
+
+/** 
+ * Validates an argument, checking that it is well-formed, for example
+ * no ludicrous length fields, strings are nul-terminated, etc.
+ * Returns the end position of the argument in end_pos, and
+ * returns #TRUE if a valid arg begins at "pos"
+ *
+ * @todo security: need to audit this function.
+ * 
+ * @param str a string
+ * @param byte_order the byte order to use
+ * @param pos the pos where the arg starts (offset of its typecode)
+ * @param end_pos pointer where the position right
+ * after the end position will follow
+ * @returns #TRUE if the arg is valid.
+ */
+dbus_bool_t
+_dbus_marshal_validate_arg (const DBusString *str,
+                            int                      byte_order,
+                            int               pos,
+                            int              *end_pos)
+{
+  const char *data;
+
+  if (pos >= _dbus_string_get_length (str))
+    return FALSE;
+
+  data = _dbus_string_get_const_data_len (str, pos, 1);
+  
+  switch (*data)
+    {
+    case DBUS_TYPE_INVALID:
+      return FALSE;
+      break;
+
+    case DBUS_TYPE_NIL:
+      *end_pos = pos + 1;
+      break;
+
+    case DBUS_TYPE_BOOLEAN:
+      {
+       unsigned char c;
+
+        if (2 > _dbus_string_get_length (str) - pos)
+          {
+            _dbus_verbose ("no room for boolean value\n");
+            return FALSE;
+          }
+        
+       c = _dbus_string_get_byte (str, pos + 1);
+
+       if (c != 0 && c != 1)
+         {
+           _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c);
+           return FALSE;
+         }
+       
+      *end_pos = pos + 2;
+      break;
+      }
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+      {
+        int align_4 = _DBUS_ALIGN_VALUE (pos + 1, 4);
+        
+        if (!_dbus_string_validate_nul (str, pos + 1,
+                                        align_4 - pos - 1))
+          {
+            _dbus_verbose ("int32/uint32 alignment padding not initialized to nul\n");
+            return FALSE;
+          }
+
+        *end_pos = align_4 + 4;
+      }
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      {
+        int align_8 = _DBUS_ALIGN_VALUE (pos + 1, 8);
+
+        _dbus_verbose_bytes_of_string (str, pos, (align_8 + 8 - pos));
+        
+        if (!_dbus_string_validate_nul (str, pos + 1,
+                                        align_8 - pos - 1))
+          {
+            _dbus_verbose ("double alignment padding not initialized to nul\n");
+            return FALSE;
+          }
+
+        *end_pos = align_8 + 8;
+      }
+      break;
+
+    case DBUS_TYPE_STRING:
+      {
+       int len;
+
+       /* Demarshal the length, which does NOT include
+         * nul termination
+         */
+       len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+
+        if (!validate_string (str, pos, len, end_pos))
+          return FALSE;
+      }
+      break;
+
+    case DBUS_TYPE_BOOLEAN_ARRAY:
+      {
+       int len, i;
+
+       len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+
+        if (len > _dbus_string_get_length (str) - pos)
+          {
+            _dbus_verbose ("boolean array length outside length of the message\n");
+            return FALSE;
+          }
+        
+       i = 0;
+       while (i < len)
+         {
+           unsigned char c = _dbus_string_get_byte (str, pos + i);
+
+           if (c != 0 && c != 1)
+             {
+               _dbus_verbose ("boolean value must be either 0 or 1, not %d (pos %d)\n", c, pos);
+               return FALSE;
+             }
+
+           i++;
+         }
+       *end_pos = pos + len;
+       break;
+      }
+    case DBUS_TYPE_BYTE_ARRAY:
+      {
+       int len;
+
+       len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+       
+       *end_pos = pos + len;
+      }
+      break;
+
+    case DBUS_TYPE_INT32_ARRAY:
+    case DBUS_TYPE_UINT32_ARRAY:
+      {
+       int len;
+
+        len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+
+        _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned int) pos);
+        
+       *end_pos = pos + len * 4;
+      }
+      break;
+
+    case DBUS_TYPE_DOUBLE_ARRAY:
+      {
+       int len;
+        int align_8;
+
+        len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+
+       if (len == 0)
+         *end_pos = pos;
+       else
+         {
+           align_8 = _DBUS_ALIGN_VALUE (pos, 8);
+           if (!_dbus_string_validate_nul (str, pos,
+                                           align_8 - pos))
+             {
+               _dbus_verbose ("double array alignment padding not initialized to nul\n");
+               return FALSE;
+             }
+
+           *end_pos = align_8 + len * 8;
+         }
+      }
+      break;
       
+    case DBUS_TYPE_STRING_ARRAY:
+      {
+        int len;
+        int i;
+        
+        len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+        if (len < 0)
+          return FALSE;
+
+       for (i = 0; i < len; i++)
+         {
+           int str_len;
+           
+           str_len = demarshal_and_validate_len (str, byte_order,
+                                                  pos, &pos);
+            if (str_len < 0)
+              return FALSE;
+
+            if (!validate_string (str, pos, str_len, &pos))
+              return FALSE;            
+         }
+
+       *end_pos = pos;
+      }
+      break;
+
+      case DBUS_TYPE_DICT:
+       {
+         int len;
+         int i;
+
+         len = demarshal_and_validate_len (str, byte_order, pos + 1, &pos);
+         if (len < 0)
+           return FALSE;
+         
+         for (i = 0; i < len; i++)
+           {
+             int str_len;
+             
+             str_len = demarshal_and_validate_len (str, byte_order,
+                                                   pos, &pos);
+             if (str_len < 0)
+               return FALSE;
+             
+             if (!validate_string (str, pos, str_len, &pos))
+               return FALSE;            
+           }
+
+         /* Now validate each argument */
+         for (i = 0; i < len; i++)
+           {
+             if (pos >= _dbus_string_get_length (str))
+               {
+                 _dbus_verbose ("not enough values in dict\n");
+                 return FALSE;
+               }
+
+             if (_dbus_string_get_byte (str, pos) == DBUS_TYPE_NIL)
+               {
+                 _dbus_verbose ("can't have NIL values in dicts\n");
+                 return FALSE;
+               }
+             
+             if (!_dbus_marshal_validate_arg (str, byte_order, pos, &pos))
+               return FALSE;
+           }
+
+         *end_pos = pos;
+
+         break;
+       }
+       
     default:
-      _dbus_warn ("Unknown message field type %d\n", *data);
+      _dbus_verbose ("Unknown message arg type %d\n", *data);
       return FALSE;
     }
 
-  if (*end_pos >= _dbus_string_get_length (str))
+  if (*end_pos > _dbus_string_get_length (str))
     return FALSE;
   
   return TRUE;
 }
 
+
 /**
  * If in verbose mode, print a block of binary data.
  *
@@ -525,6 +1866,8 @@ _dbus_verbose_bytes (const unsigned char *data,
   int i;
   const unsigned char *aligned;
 
+  _dbus_assert (len >= 0);
+  
   /* Print blanks on first row if appropriate */
   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
   if (aligned > data)
@@ -533,7 +1876,7 @@ _dbus_verbose_bytes (const unsigned char *data,
 
   if (aligned != data)
     {
-      _dbus_verbose ("%5d\t%p: ", - (data - aligned), aligned); 
+      _dbus_verbose ("%4d\t%p: ", - (data - aligned), aligned); 
       while (aligned != data)
         {
           _dbus_verbose ("    ");
@@ -547,7 +1890,7 @@ _dbus_verbose_bytes (const unsigned char *data,
     {
       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
         {
-          _dbus_verbose ("%5d\t%p: ",
+          _dbus_verbose ("%4d\t%p: ",
                    i, &data[i]);
         }
       
@@ -563,9 +1906,16 @@ _dbus_verbose_bytes (const unsigned char *data,
       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
         {
           if (i > 3)
-            _dbus_verbose ("big: %d little: %d",
-                     unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
-                     unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
+            _dbus_verbose ("BE: %d LE: %d",
+                           _dbus_unpack_uint32 (DBUS_BIG_ENDIAN, &data[i-4]),
+                           _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN, &data[i-4]));
+
+          if (i > 7 && 
+              _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i])
+            {
+              _dbus_verbose (" dbl: %g",
+                             *(double*)&data[i-8]);
+            }
           
           _dbus_verbose ("\n");
         }
@@ -587,8 +1937,27 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
                                int                  len)
 {
   const char *d;
+  int real_len;
 
-  _dbus_string_get_const_data_len (str, &d, start, len);
+  real_len = _dbus_string_get_length (str);
+
+  _dbus_assert (start >= 0);
+  
+  if (start > real_len)
+    {
+      _dbus_verbose ("  [%d,%d) is not inside string of length %d\n",
+                     start, len, real_len);
+      return;
+    }
+
+  if ((start + len) > real_len)
+    {
+      _dbus_verbose ("  [%d,%d) extends outside string of length %d\n",
+                     start, len, real_len);
+      len = real_len - start;
+    }
+  
+  d = _dbus_string_get_const_data_len (str, start, len);
 
   _dbus_verbose_bytes (d, len);
 }
@@ -604,56 +1973,183 @@ _dbus_marshal_test (void)
 {
   DBusString str;
   char *tmp1, *tmp2;
-  int pos = 0;
+  dbus_int32_t array1[3] = { 0x123, 0x456, 0x789 }, *array2;
+  int pos = 0, i, len;
+  dbus_bool_t our_bool;
+  dbus_int32_t our_int;
+  dbus_uint32_t our_uint;
+  double our_double;
+  const char *our_string;
+  const unsigned char boolean_array[] = { TRUE, FALSE, FALSE, TRUE };
+  const unsigned char *our_boolean_array;
+  const dbus_int32_t int32_array[] = { 0x12345678, -1911, 0, 0xaffe, 0xedd1e };
+  const dbus_int32_t *our_int32_array;
+  const dbus_uint32_t uint32_array[] = { 0x12345678, 0, 0xdeadbeef, 0x87654321, 0xffffffff };
+  const dbus_uint32_t *our_uint32_array;
+  const double double_array[] = { 3.14159, 1.2345, 6.7890 };
+  const double *our_double_array;
+  const char *string_array[] = { "This", "Is", "A", "Test" };
+  const char **our_string_array;
+  DBusDict *dict;
   
-  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+  if (!_dbus_string_init (&str))
     _dbus_assert_not_reached ("failed to init string");
 
-
   /* Marshal doubles */
   if (!_dbus_marshal_double (&str, DBUS_BIG_ENDIAN, 3.14))
     _dbus_assert_not_reached ("could not marshal double value");
-  _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
+  if (!_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14)
+    _dbus_assert_not_reached ("demarshal failed");
 
   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
     _dbus_assert_not_reached ("could not marshal double value");
-  _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
+  if (!_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14)
+    _dbus_assert_not_reached ("demarshal failed");
   
   /* Marshal signed integers */
   if (!_dbus_marshal_int32 (&str, DBUS_BIG_ENDIAN, -12345678))
     _dbus_assert_not_reached ("could not marshal signed integer value");
-  _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678);
+  if (!_dbus_demarshal_int32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == -12345678)
+    _dbus_assert_not_reached ("demarshal failed");
 
   if (!_dbus_marshal_int32 (&str, DBUS_LITTLE_ENDIAN, -12345678))
     _dbus_assert_not_reached ("could not marshal signed integer value");
-  _dbus_assert (_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678);
+  if (!_dbus_demarshal_int32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == -12345678)
+    _dbus_assert_not_reached ("demarshal failed");
   
   /* Marshal unsigned integers */
   if (!_dbus_marshal_uint32 (&str, DBUS_BIG_ENDIAN, 0x12345678))
     _dbus_assert_not_reached ("could not marshal signed integer value");
-  _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678);
+  if (!_dbus_demarshal_uint32 (&str, DBUS_BIG_ENDIAN, pos, &pos) == 0x12345678)
+    _dbus_assert_not_reached ("demarshal failed");
   
   if (!_dbus_marshal_uint32 (&str, DBUS_LITTLE_ENDIAN, 0x12345678))
     _dbus_assert_not_reached ("could not marshal signed integer value");
-  _dbus_assert (_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678);
+  if (!_dbus_demarshal_uint32 (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 0x12345678)
+    _dbus_assert_not_reached ("demarshal failed");
 
   /* Marshal strings */
   tmp1 = "This is the dbus test string";
   if (!_dbus_marshal_string (&str, DBUS_BIG_ENDIAN, tmp1))
     _dbus_assert_not_reached ("could not marshal string");
   tmp2 = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, pos, &pos);
-  _dbus_assert (strcmp (tmp1, tmp2) == 0);
+  if (!strcmp (tmp1, tmp2) == 0)
+    _dbus_assert_not_reached ("demarshal failed");
   dbus_free (tmp2);
 
   tmp1 = "This is the dbus test string";
   if (!_dbus_marshal_string (&str, DBUS_LITTLE_ENDIAN, tmp1))
     _dbus_assert_not_reached ("could not marshal string");
   tmp2 = _dbus_demarshal_string (&str, DBUS_LITTLE_ENDIAN, pos, &pos);
-  _dbus_assert (strcmp (tmp1, tmp2) == 0);
+  if (!strcmp (tmp1, tmp2) == 0)
+    _dbus_assert_not_reached ("demarshal failed");
   dbus_free (tmp2);
 
+  /* Marshal signed integer arrays */
+  if (!_dbus_marshal_int32_array (&str, DBUS_BIG_ENDIAN, array1, 3))
+    _dbus_assert_not_reached ("could not marshal integer array");
+  if (!_dbus_demarshal_int32_array (&str, DBUS_BIG_ENDIAN, pos, &pos, &array2, &len))
+    _dbus_assert_not_reached ("could not demarshal integer array");
+
+  if (len != 3)
+    _dbus_assert_not_reached ("Signed integer array lengths differ!\n");
+  dbus_free (array2);
+  
+
+  /* Marshal dicts */
+  dict = dbus_dict_new ();
+
+  if (dbus_dict_get_value_type (dict, "foo") != DBUS_TYPE_NIL)
+    _dbus_assert_not_reached ("didn't return DBUS_TYPE_NIL for non-existant entry");
+  
+  if (!dbus_dict_set_boolean (dict, "boolean", TRUE))
+    _dbus_assert_not_reached ("could not add boolean value");
+
+  if (!dbus_dict_set_int32 (dict, "int32", 0x12345678))
+    _dbus_assert_not_reached ("could not add int32 value");
+
+  if (!dbus_dict_set_uint32 (dict, "uint32", 0x87654321))
+    _dbus_assert_not_reached ("could not add uint32 value");
+
+  if (!dbus_dict_set_double (dict, "double", 3.14159))
+    _dbus_assert_not_reached ("could not add double value");
+
+  if (!dbus_dict_set_string (dict, "string", "test string"))
+    _dbus_assert_not_reached ("could not add string value");
+
+  if (!dbus_dict_set_boolean_array (dict, "boolean_array", boolean_array, 4))
+    _dbus_assert_not_reached ("could not add boolean array");
+
+  if (!dbus_dict_set_int32_array (dict, "int32_array", int32_array, 5))
+    _dbus_assert_not_reached ("could not add int32 array");
+
+  if (!dbus_dict_set_uint32_array (dict, "uint32_array", uint32_array, 5))
+    _dbus_assert_not_reached ("could not add uint32 array");
+
+  if (!dbus_dict_set_double_array (dict, "double_array", double_array, 3))
+    _dbus_assert_not_reached ("could not add double array");
+
+  if (!dbus_dict_set_string_array (dict, "string_array", string_array, 4))
+    _dbus_assert_not_reached ("could not add string array");
+
+  if (!_dbus_marshal_dict (&str, DBUS_BIG_ENDIAN, dict))
+    _dbus_assert_not_reached ("could not marshal dict");
+  
+  dbus_dict_unref (dict);
+  
+  if (!_dbus_demarshal_dict (&str, DBUS_BIG_ENDIAN, pos, &pos, &dict))
+    _dbus_assert_not_reached ("could not demarshal dict");
+
+  if (!dbus_dict_get_boolean (dict, "boolean", &our_bool) ||
+      !our_bool)
+    _dbus_assert_not_reached ("could not get boolean value");
+
+  if (!dbus_dict_get_int32 (dict, "int32", &our_int) || our_int != 0x12345678)
+    _dbus_assert_not_reached ("could not get int32 value or int32 values differ");
+  
+  if (!dbus_dict_get_uint32 (dict, "uint32", &our_uint) || our_uint != 0x87654321)
+    _dbus_assert_not_reached ("could not get uint32 value or uint32 values differ");
+
+  if (!dbus_dict_get_double (dict, "double", &our_double)
+      || our_double != 3.14159)
+     _dbus_assert_not_reached ("could not get double value or double values differ");
+
+  if (!dbus_dict_get_string (dict, "string", &our_string) || strcmp (our_string, "test string") != 0)
+    _dbus_assert_not_reached ("could not get string value or string values differ");
+
+  if (!dbus_dict_get_boolean_array (dict, "boolean_array", &our_boolean_array, &len) ||
+      len != 4 || memcmp (boolean_array, our_boolean_array, 4) != 0)
+    _dbus_assert_not_reached ("could not get boolean array value or boolean array values differ");
+
+  if (!dbus_dict_get_int32_array (dict, "int32_array", &our_int32_array, &len) ||
+      len != 5 || memcmp (int32_array, our_int32_array, 5 * sizeof (dbus_int32_t)) != 0)
+    _dbus_assert_not_reached ("could not get int32 array value or int32 array values differ");
+
+  if (!dbus_dict_get_uint32_array (dict, "uint32_array", &our_uint32_array, &len) ||
+      len != 5 || memcmp (uint32_array, our_uint32_array, 5 * sizeof (dbus_uint32_t) ) != 0)
+    _dbus_assert_not_reached ("could not get uint32 array value or uint32 array values differ");
+
+  if (!dbus_dict_get_double_array (dict, "double_array", &our_double_array, &len) ||
+      len != 3 || memcmp (double_array, our_double_array, 3 * sizeof (double)) != 0)
+    _dbus_assert_not_reached ("could not get double array value or double array values differ");
+
+  if (!dbus_dict_get_string_array (dict, "string_array", &our_string_array, &len))
+    _dbus_assert_not_reached ("could not get string array value");
+
+  if (len != 4)
+    _dbus_assert_not_reached ("string array lengths differ");
+
+  for (i = 0; i < len; i++)
+    {
+      if (strcmp (our_string_array[i], string_array[i]) != 0)
+       _dbus_assert_not_reached ("string array fields differ");
+    }
+  
+  dbus_dict_unref (dict);
+  
   _dbus_string_free (&str);
   
+      
   return TRUE;
 }