Revert merge of master (dbus-1.5) into dbus-1.4
[platform/upstream/dbus.git] / dbus / dbus-marshal-basic.c
index 11ebfaf..3cbc721 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-marshal-basic.c  Marshalling routines for basic (primitive) types
  *
  * Copyright (C) 2002 CodeFactory AB
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
 #include "dbus-internals.h"
 #include "dbus-marshal-basic.h"
+#include "dbus-signature.h"
 
 #include <string.h>
 
  */
 
 static void
+pack_2_octets (dbus_uint16_t   value,
+               int             byte_order,
+               unsigned char  *data)
+{
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data);
+
+  if ((byte_order) == DBUS_LITTLE_ENDIAN)
+    *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_LE (value);
+  else
+    *((dbus_uint16_t*)(data)) = DBUS_UINT16_TO_BE (value);
+}
+
+static void
 pack_4_octets (dbus_uint32_t   value,
                int             byte_order,
                unsigned char  *data)
@@ -88,33 +103,6 @@ _dbus_pack_uint32 (dbus_uint32_t   value,
   pack_4_octets (value, byte_order, data);
 }
 
-/**
- * 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)
-{
-  pack_4_octets ((dbus_uint32_t) value, byte_order, data);
-}
-
-static dbus_uint32_t
-unpack_4_octets (int                  byte_order,
-                 const unsigned char *data)
-{
-  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
-
-  if (byte_order == DBUS_LITTLE_ENDIAN)
-    return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
-  else
-    return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
-}
-
 #ifndef DBUS_HAVE_INT64
 /* from ORBit */
 static void
@@ -150,6 +138,7 @@ swap_8_octets (DBusBasicValue    *value,
     }
 }
 
+#if 0
 static DBusBasicValue
 unpack_8_octets (int                  byte_order,
                  const unsigned char *data)
@@ -171,33 +160,64 @@ unpack_8_octets (int                  byte_order,
 
   return r;
 }
+#endif
 
+#ifndef _dbus_unpack_uint16
 /**
- * Unpacks a 32 bit unsigned integer from a data pointer
+ * Unpacks a 16 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,
+dbus_uint16_t
+_dbus_unpack_uint16 (int                  byte_order,
                      const unsigned char *data)
 {
-  return unpack_4_octets (byte_order, data);
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data);
+
+  if (byte_order == DBUS_LITTLE_ENDIAN)
+    return DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)data);
+  else
+    return DBUS_UINT16_FROM_BE (*(dbus_uint16_t*)data);
 }
+#endif /* _dbus_unpack_uint16 */
 
+#ifndef _dbus_unpack_uint32
 /**
- * Unpacks a 32 bit signed integer from a data pointer
+ * 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_int32_t
-_dbus_unpack_int32 (int                  byte_order,
-                    const unsigned char *data)
+dbus_uint32_t
+_dbus_unpack_uint32 (int                  byte_order,
+                     const unsigned char *data)
+{
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
+
+  if (byte_order == DBUS_LITTLE_ENDIAN)
+    return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
+  else
+    return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
+}
+#endif /* _dbus_unpack_uint32 */
+
+static void
+set_2_octets (DBusString          *str,
+              int                  offset,
+              dbus_uint16_t        value,
+              int                  byte_order)
 {
-  return (dbus_int32_t) unpack_4_octets (byte_order, data);
+  char *data;
+
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+
+  data = _dbus_string_get_data_len (str, offset, 2);
+
+  pack_2_octets (value, byte_order, data);
 }
 
 static void
@@ -213,7 +233,7 @@ set_4_octets (DBusString          *str,
 
   data = _dbus_string_get_data_len (str, offset, 4);
 
-  _dbus_pack_uint32 (value, byte_order, data);
+  pack_4_octets (value, byte_order, data);
 }
 
 static void
@@ -283,7 +303,9 @@ set_string (DBusString          *str,
 
   _dbus_string_init_const (&dstr, value);
 
-  old_len = _dbus_marshal_read_uint32 (str, pos, byte_order, NULL);
+  _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == (unsigned) pos);
+  old_len = _dbus_unpack_uint32 (byte_order,
+                                 _dbus_string_get_const_data_len (str, pos, 4));
 
   new_len = _dbus_string_get_length (&dstr);
 
@@ -373,7 +395,6 @@ _dbus_marshal_set_basic (DBusString       *str,
   switch (type)
     {
     case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
       _dbus_string_set_byte (str, pos, vp->byt);
       if (old_end_pos)
         *old_end_pos = pos + 1;
@@ -381,8 +402,20 @@ _dbus_marshal_set_basic (DBusString       *str,
         *new_end_pos = pos + 1;
       return TRUE;
       break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      pos = _DBUS_ALIGN_VALUE (pos, 2);
+      set_2_octets (str, pos, vp->u16, byte_order);
+      if (old_end_pos)
+        *old_end_pos = pos + 2;
+      if (new_end_pos)
+        *new_end_pos = pos + 2;
+      return TRUE;
+      break;
+    case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UNIX_FD:
       pos = _DBUS_ALIGN_VALUE (pos, 4);
       set_4_octets (str, pos, vp->u32, byte_order);
       if (old_end_pos)
@@ -404,10 +437,13 @@ _dbus_marshal_set_basic (DBusString       *str,
       break;
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
+      pos = _DBUS_ALIGN_VALUE (pos, 4);
+      _dbus_assert (vp->str != NULL);
       return set_string (str, pos, vp->str, byte_order,
                          old_end_pos, new_end_pos);
       break;
     case DBUS_TYPE_SIGNATURE:
+      _dbus_assert (vp->str != NULL);
       return set_signature (str, pos, vp->str, byte_order,
                             old_end_pos, new_end_pos);
       break;
@@ -418,21 +454,6 @@ _dbus_marshal_set_basic (DBusString       *str,
     }
 }
 
-static dbus_uint32_t
-read_4_octets (const DBusString *str,
-               int               pos,
-               int               byte_order,
-               int              *new_pos)
-{
-  pos = _DBUS_ALIGN_VALUE (pos, 4);
-
-  if (new_pos)
-    *new_pos = pos + 4;
-
-  return unpack_4_octets (byte_order,
-                          _dbus_string_get_const_data (str) + pos);
-}
-
 /**
  * Convenience function to demarshal a 32 bit unsigned integer.
  *
@@ -448,7 +469,15 @@ _dbus_marshal_read_uint32  (const DBusString *str,
                             int               byte_order,
                             int              *new_pos)
 {
-  return read_4_octets (str, pos, byte_order, new_pos);
+  pos = _DBUS_ALIGN_VALUE (pos, 4);
+
+  if (new_pos)
+    *new_pos = pos + 4;
+
+  _dbus_assert (pos + 4 <= _dbus_string_get_length (str));
+  
+  return _dbus_unpack_uint32 (byte_order,
+                              _dbus_string_get_const_data (str) + pos);
 }
 
 /**
@@ -481,51 +510,75 @@ _dbus_marshal_read_basic (const DBusString      *str,
                           int                   *new_pos)
 {
   const char *str_data;
-  DBusBasicValue *vp;
 
-  _dbus_assert (_dbus_type_is_basic (type));
+  _dbus_assert (dbus_type_is_basic (type));
 
   str_data = _dbus_string_get_const_data (str);
-  vp = value;
 
+  /* Below we volatile types to avoid aliasing issues;
+   * see http://bugs.freedesktop.org/show_bug.cgi?id=20137
+   */
+  
   switch (type)
     {
     case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
-      vp->byt = _dbus_string_get_byte (str, pos);
+      {
+      volatile unsigned char *vp = value;
+      *vp = (unsigned char) _dbus_string_get_byte (str, pos);
       (pos)++;
+      }
+      break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      {
+      volatile dbus_uint16_t *vp = value;
+      pos = _DBUS_ALIGN_VALUE (pos, 2);
+      *vp = *(dbus_uint16_t *)(str_data + pos);
+      if (byte_order != DBUS_COMPILER_BYTE_ORDER)
+       *vp = DBUS_UINT16_SWAP_LE_BE (*vp);
+      pos += 2;
+      }
       break;
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_UNIX_FD:
+      {
+      volatile dbus_uint32_t *vp = value;
       pos = _DBUS_ALIGN_VALUE (pos, 4);
-      vp->u32 = *(dbus_uint32_t *)(str_data + pos);
+      *vp = *(dbus_uint32_t *)(str_data + pos);
       if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-       vp->u32 = DBUS_UINT32_SWAP_LE_BE (vp->u32);
+       *vp = DBUS_UINT32_SWAP_LE_BE (*vp);
       pos += 4;
+      }
       break;
     case DBUS_TYPE_INT64:
     case DBUS_TYPE_UINT64:
     case DBUS_TYPE_DOUBLE:
+      {
+      volatile dbus_uint64_t *vp = value;
       pos = _DBUS_ALIGN_VALUE (pos, 8);
 #ifdef DBUS_HAVE_INT64
       if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-        vp->u64 = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t*)(str_data + pos));
+        *vp = DBUS_UINT64_SWAP_LE_BE (*(dbus_uint64_t*)(str_data + pos));
       else
-        vp->u64 = *(dbus_uint64_t*)(str_data + pos);
+        *vp = *(dbus_uint64_t*)(str_data + pos);
 #else
-      vp->u64 = *(DBus8ByteStruct*) (str_data + pos);
+      *vp = *(DBus8ByteStruct*) (str_data + pos);
       swap_8_octets (vp, byte_order);
 #endif
       pos += 8;
+      }
       break;
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
       {
         int len;
+        volatile char **vp = value;
 
         len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos);
 
-        vp->str = (char*) str_data + pos;
+        *vp = (char*) str_data + pos;
 
         pos += len + 1; /* length plus nul */
       }
@@ -533,18 +586,19 @@ _dbus_marshal_read_basic (const DBusString      *str,
     case DBUS_TYPE_SIGNATURE:
       {
         int len;
+        volatile char **vp = value;
 
         len = _dbus_string_get_byte (str, pos);
         pos += 1;
 
-        vp->str = (char*) str_data + pos;
+        *vp = (char*) str_data + pos;
 
         pos += len + 1; /* length plus nul */
       }
       break;
     default:
-      _dbus_warn ("type %s not a basic type\n",
-                  _dbus_type_to_string (type));
+      _dbus_warn_check_failed ("type %s %d not a basic type\n",
+                               _dbus_type_to_string (type), type);
       _dbus_assert_not_reached ("not a basic type");
       break;
     }
@@ -553,55 +607,33 @@ _dbus_marshal_read_basic (const DBusString      *str,
     *new_pos = pos;
 }
 
-/**
- * Reads an array of fixed-length basic values.  Does not work for
- * arrays of string or container types.
- *
- * This function returns the array in-place; it does not make a copy,
- * and it does not swap the bytes.
- *
- * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back
- * and the "value" argument should be a "const double**" and so on.
- *
- * @todo last I checked only the test suite uses this function
- *
- * @param str the string to read from
- * @param pos position to read from
- * @param element_type type of array elements
- * @param value place to return the array
- * @param n_elements place to return number of array elements
- * @param byte_order the byte order, used to read the array length
- * @param new_pos #NULL or location to store a position after the elements
- */
-void
-_dbus_marshal_read_fixed_array  (const DBusString *str,
-                                 int               pos,
-                                 int               element_type,
-                                 void             *value,
-                                 int              *n_elements,
-                                 int               byte_order,
-                                 int              *new_pos)
+static dbus_bool_t
+marshal_2_octets (DBusString   *str,
+                  int           insert_at,
+                  dbus_uint16_t value,
+                  int           byte_order,
+                  int          *pos_after)
 {
-  dbus_uint32_t array_len;
-  int alignment;
-
-  _dbus_assert (_dbus_type_is_fixed (element_type));
-  _dbus_assert (_dbus_type_is_basic (element_type));
-
-  pos = _DBUS_ALIGN_VALUE (pos, 4);
+  dbus_bool_t retval;
+  int orig_len;
 
-  array_len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos);
+  _dbus_assert (sizeof (value) == 2);
 
-  alignment = _dbus_type_get_alignment (element_type);
+  if (byte_order != DBUS_COMPILER_BYTE_ORDER)
+    value = DBUS_UINT16_SWAP_LE_BE (value);
 
-  pos = _DBUS_ALIGN_VALUE (pos, alignment);
+  orig_len = _dbus_string_get_length (str);
 
-  *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len);
+  retval = _dbus_string_insert_2_aligned (str, insert_at,
+                                          (const unsigned char *)&value);
 
-  *n_elements = array_len / alignment;
+  if (pos_after)
+    {
+      *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len);
+      _dbus_assert (*pos_after <= _dbus_string_get_length (str));
+    }
 
-  if (new_pos)
-    *new_pos = pos + array_len;
+  return retval;
 }
 
 static dbus_bool_t
@@ -682,22 +714,21 @@ marshal_len_followed_by_bytes (int                  marshal_as,
   if (insert_at > _dbus_string_get_length (str))
     _dbus_warn ("insert_at = %d string len = %d data_len = %d\n",
                 insert_at, _dbus_string_get_length (str), data_len);
-
+  
   if (marshal_as == MARSHAL_AS_BYTE_ARRAY)
     value_len = data_len;
   else
     value_len = data_len + 1; /* value has a nul */
 
-  /* FIXME this is probably broken for byte arrays because
-   * DBusString wants strings to be nul-terminated?
-   * Maybe I planned on this when writing init_const_len though
-   */
   _dbus_string_init_const_len (&value_str, value, value_len);
 
   pos = insert_at;
 
   if (marshal_as == MARSHAL_AS_SIGNATURE)
     {
+      _dbus_assert (data_len <= DBUS_MAXIMUM_SIGNATURE_LENGTH);
+      _dbus_assert (data_len <= 255); /* same as max sig len right now */
+      
       if (!_dbus_string_insert_byte (str, pos, data_len))
         goto oom;
 
@@ -787,22 +818,31 @@ _dbus_marshal_write_basic (DBusString *str,
 {
   const DBusBasicValue *vp;
 
-  _dbus_assert (_dbus_type_is_basic (type));
+  _dbus_assert (dbus_type_is_basic (type));
 
   vp = value;
 
   switch (type)
     {
     case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
       if (!_dbus_string_insert_byte (str, insert_at, vp->byt))
         return FALSE;
       if (pos_after)
         *pos_after = insert_at + 1;
       return TRUE;
       break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      return marshal_2_octets (str, insert_at, vp->u16,
+                               byte_order, pos_after);
+      break;
+    case DBUS_TYPE_BOOLEAN:
+      return marshal_4_octets (str, insert_at, vp->u32 != FALSE,
+                               byte_order, pos_after);
+      break;
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UNIX_FD:
       return marshal_4_octets (str, insert_at, vp->u32,
                                byte_order, pos_after);
       break;
@@ -814,9 +854,11 @@ _dbus_marshal_write_basic (DBusString *str,
 
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
+      _dbus_assert (vp->str != NULL);
       return marshal_string (str, insert_at, vp->str, byte_order, pos_after);
       break;
     case DBUS_TYPE_SIGNATURE:
+      _dbus_assert (vp->str != NULL);
       return marshal_signature (str, insert_at, vp->str, pos_after);
       break;
     default:
@@ -834,9 +876,78 @@ marshal_1_octets_array (DBusString          *str,
                         int                  byte_order,
                         int                 *pos_after)
 {
-  return marshal_len_followed_by_bytes (MARSHAL_AS_BYTE_ARRAY,
-                                        str, insert_at, value, n_elements,
-                                        byte_order, pos_after);
+  int pos;
+  DBusString value_str;
+
+  _dbus_string_init_const_len (&value_str, value, n_elements);
+
+  pos = insert_at;
+
+  if (!_dbus_string_copy_len (&value_str, 0, n_elements,
+                              str, pos))
+    return FALSE;
+
+  pos += n_elements;
+
+  if (pos_after)
+    *pos_after = pos;
+
+  return TRUE;
+}
+
+/**
+ * Swaps the elements of an array to the opposite byte order
+ *
+ * @param data start of array
+ * @param n_elements number of elements
+ * @param alignment size of each element
+ */
+void
+_dbus_swap_array (unsigned char *data,
+                  int            n_elements,
+                  int            alignment)
+{
+  unsigned char *d;
+  unsigned char *end;
+
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, alignment) == data);
+
+  /* we use const_data and cast it off so DBusString can be a const string
+   * for the unit tests. don't ask.
+   */
+  d = data;
+  end = d + (n_elements * alignment);
+  
+  if (alignment == 8)
+    {
+      while (d != end)
+        {
+#ifdef DBUS_HAVE_INT64
+          *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d));
+#else
+          swap_8_bytes ((DBusBasicValue*) d);
+#endif
+          d += 8;
+        }
+    }
+  else if (alignment == 4)
+    {
+      while (d != end)
+        {
+          *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d));
+          d += 4;
+        }
+    }
+  else
+    {
+      _dbus_assert (alignment == 2);
+      
+      while (d != end)
+        {
+          *((dbus_uint16_t*)d) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)d));
+          d += 2;
+        }
+    }
 }
 
 static void
@@ -850,42 +961,16 @@ swap_array (DBusString *str,
 
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
     {
-      unsigned char *d;
-      unsigned char *end;
-
       /* we use const_data and cast it off so DBusString can be a const string
        * for the unit tests. don't ask.
        */
-      d = (unsigned char*) _dbus_string_get_const_data (str) + array_start;
-      end = d + n_elements * alignment;
-
-      if (alignment == 8)
-        {
-          while (d != end)
-            {
-#ifdef DBUS_HAVE_INT64
-              *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d));
-#else
-              swap_8_bytes ((DBusBasicValue*) d);
-#endif
-              d += 8;
-            }
-        }
-      else
-        {
-          _dbus_assert (alignment == 4);
-
-          while (d != end)
-            {
-              *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d));
-              d += 4;
-            }
-        }
+      _dbus_swap_array ((unsigned char*) (_dbus_string_get_const_data (str) + array_start),
+                        n_elements, alignment);
     }
 }
 
 static dbus_bool_t
-marshal_fixed_array (DBusString           *str,
+marshal_fixed_multi (DBusString           *str,
                      int                   insert_at,
                      const DBusBasicValue *value,
                      int                   n_elements,
@@ -896,18 +981,15 @@ marshal_fixed_array (DBusString           *str,
   int old_string_len;
   int array_start;
   DBusString t;
+  int len_in_bytes;
 
+  _dbus_assert (n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / alignment);
+  
   old_string_len = _dbus_string_get_length (str);
 
-  /*  The array length is the length in bytes of the array,
-   * *excluding* alignment padding.
-   */
-  if (!marshal_4_octets (str, insert_at, n_elements * alignment,
-                         byte_order, &array_start))
-    goto error;
-
-  _dbus_verbose ("marshaled len %d at %d array start %d\n", n_elements * alignment, insert_at, array_start);
-
+  len_in_bytes = n_elements * alignment;
+  array_start = insert_at;
+  
   /* Note that we do alignment padding unconditionally
    * even if the array is empty; this means that
    * padding + len is always equal to the number of bytes
@@ -919,7 +1001,7 @@ marshal_fixed_array (DBusString           *str,
 
   _dbus_string_init_const_len (&t,
                                (const unsigned char*) value,
-                               n_elements * alignment);
+                               len_in_bytes);
 
   if (!_dbus_string_copy (&t, 0,
                           str, array_start))
@@ -927,6 +1009,9 @@ marshal_fixed_array (DBusString           *str,
 
   swap_array (str, array_start, n_elements, byte_order, alignment);
 
+  if (pos_after)
+    *pos_after = array_start + len_in_bytes;
+  
   return TRUE;
 
  error:
@@ -937,9 +1022,9 @@ marshal_fixed_array (DBusString           *str,
 }
 
 /**
- * Marshals an array of values of fixed-length type.
- * _dbus_type_is_fixed() returns #TRUE for these types,
- * which are the basic types minus the string-like types.
+ * Marshals a block of values of fixed-length type all at once, as an
+ * optimization.  dbus_type_is_fixed() returns #TRUE for fixed-length
+ * types, which are the basic types minus the string-like types.
  *
  * The value argument should be the adddress of an
  * array, so e.g. "const dbus_uint32_t**"
@@ -948,13 +1033,13 @@ marshal_fixed_array (DBusString           *str,
  * @param insert_at where to insert the value
  * @param element_type type of array elements
  * @param value address of an array to marshal
- * @param len number of elements in the array
+ * @param n_elements number of elements in the array
  * @param byte_order byte order
  * @param pos_after #NULL or the position after the type
  * @returns #TRUE on success
  **/
 dbus_bool_t
-_dbus_marshal_write_fixed_array (DBusString *str,
+_dbus_marshal_write_fixed_multi (DBusString *str,
                                  int         insert_at,
                                  int         element_type,
                                  const void *value,
@@ -963,25 +1048,33 @@ _dbus_marshal_write_fixed_array (DBusString *str,
                                  int        *pos_after)
 {
   const void* vp = *(const DBusBasicValue**)value;
+  
+  _dbus_assert (dbus_type_is_fixed (element_type));
+  _dbus_assert (n_elements >= 0);
 
-  _dbus_assert (_dbus_type_is_fixed (element_type));
-
+#if 0
+  _dbus_verbose ("writing %d elements of %s\n",
+                 n_elements, _dbus_type_to_string (element_type));
+#endif
+  
   switch (element_type)
     {
-    case DBUS_TYPE_BOOLEAN:
-      /* FIXME: we canonicalize to 0 or 1 for the single boolean case
-       * should we here too ? */
     case DBUS_TYPE_BYTE:
       return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after);
       break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 2, pos_after);
+    case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
-      return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 4, pos_after);
+    case DBUS_TYPE_UNIX_FD:
+      return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 4, pos_after);
       break;
     case DBUS_TYPE_INT64:
     case DBUS_TYPE_UINT64:
     case DBUS_TYPE_DOUBLE:
-      return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 8, pos_after);
+      return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 8, pos_after);
       break;
 
     default:
@@ -1008,14 +1101,23 @@ _dbus_marshal_skip_basic (const DBusString      *str,
                           int                    byte_order,
                           int                   *pos)
 {
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+  
   switch (type)
     {
     case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
       (*pos)++;
       break;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      *pos = _DBUS_ALIGN_VALUE (*pos, 2);
+      *pos += 2;
+      break;
+    case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UNIX_FD:
       *pos = _DBUS_ALIGN_VALUE (*pos, 4);
       *pos += 4;
       break;
@@ -1031,7 +1133,7 @@ _dbus_marshal_skip_basic (const DBusString      *str,
         int len;
 
         len = _dbus_marshal_read_uint32 (str, *pos, byte_order, pos);
-
+        
         *pos += len + 1; /* length plus nul */
       }
       break;
@@ -1095,12 +1197,16 @@ _dbus_type_get_alignment (int typecode)
   switch (typecode)
     {
     case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_VARIANT:
     case DBUS_TYPE_SIGNATURE:
       return 1;
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+      return 2;
+    case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_UNIX_FD:
       /* this stuff is 4 since it starts with a length */
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
@@ -1113,8 +1219,10 @@ _dbus_type_get_alignment (int typecode)
        * and it's simpler to just always align structs to 8;
        * we want the amount of padding in a struct of a given
        * type to be predictable, not location-dependent.
+       * DICT_ENTRY is always the same as struct.
        */
     case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
       return 8;
 
     default:
@@ -1139,6 +1247,8 @@ _dbus_type_is_valid (int typecode)
     {
     case DBUS_TYPE_BYTE:
     case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
     case DBUS_TYPE_INT64:
@@ -1149,7 +1259,9 @@ _dbus_type_is_valid (int typecode)
     case DBUS_TYPE_SIGNATURE:
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
     case DBUS_TYPE_VARIANT:
+    case DBUS_TYPE_UNIX_FD:
       return TRUE;
 
     default:
@@ -1157,85 +1269,69 @@ _dbus_type_is_valid (int typecode)
     }
 }
 
-#define TYPE_IS_CONTAINER(typecode)             \
-    ((typecode) == DBUS_TYPE_STRUCT ||          \
-     (typecode) == DBUS_TYPE_VARIANT ||         \
-     (typecode) == DBUS_TYPE_ARRAY)
-
-/**
- * A "container type" can contain basic types, or nested
- * container types. #DBUS_TYPE_INVALID is not a container type.
- * This function will crash if passed a typecode that isn't
- * in dbus-protocol.h
- *
- * @returns #TRUE if type is a container
- */
-dbus_bool_t
-_dbus_type_is_container (int typecode)
-{
-  /* only reasonable (non-line-noise) typecodes are allowed */
-  _dbus_assert (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID);
-  return TYPE_IS_CONTAINER (typecode);
-}
-
-/**
- * A "basic type" is a somewhat arbitrary concept, but the intent
- * is to include those types that are fully-specified by a single
- * typecode, with no additional type information or nested
- * values. So all numbers and strings are basic types and
- * structs, arrays, and variants are not basic types.
- * #DBUS_TYPE_INVALID is not a basic type.
- *
- * This function is defined to return #TRUE for exactly those
- * types that can be written with _dbus_marshal_basic_type()
- * and read with _dbus_marshal_read_basic().
- *
- * This function will crash if passed a typecode that isn't
- * in dbus-protocol.h
- *
- * @returns #TRUE if type is basic
- */
-dbus_bool_t
-_dbus_type_is_basic (int typecode)
-{
-  /* only reasonable (non-line-noise) typecodes are allowed */
-  _dbus_assert (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID);
-
-  /* everything that isn't invalid or a container */
-  return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
-}
-
 /**
- * Tells you whether values of this type can change length if you set
- * them to some other value. For this purpose, you assume that the
- * first byte of the old and new value would be in the same location,
- * so alignment padding is not a factor.
+ * Returns a string describing the given type.
  *
- * @returns #FALSE if the type can occupy different lengths
+ * @param typecode the type to describe
+ * @returns a constant string describing the type
  */
-dbus_bool_t
-_dbus_type_is_fixed (int typecode)
+const char *
+_dbus_type_to_string (int typecode)
 {
   switch (typecode)
     {
-    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_INVALID:
+      return "invalid";
     case DBUS_TYPE_BOOLEAN:
+      return "boolean";
+    case DBUS_TYPE_BYTE:
+      return "byte";
+    case DBUS_TYPE_INT16:
+      return "int16";
+    case DBUS_TYPE_UINT16:
+      return "uint16";
     case DBUS_TYPE_INT32:
+      return "int32";
     case DBUS_TYPE_UINT32:
+      return "uint32";
     case DBUS_TYPE_INT64:
+      return "int64";
     case DBUS_TYPE_UINT64:
+      return "uint64";      
     case DBUS_TYPE_DOUBLE:
-      return TRUE;
+      return "double";
+    case DBUS_TYPE_STRING:
+      return "string";
+    case DBUS_TYPE_OBJECT_PATH:
+      return "object_path";
+    case DBUS_TYPE_SIGNATURE:
+      return "signature";
+    case DBUS_TYPE_STRUCT:
+      return "struct";
+    case DBUS_TYPE_DICT_ENTRY:
+      return "dict_entry";
+    case DBUS_TYPE_ARRAY:
+      return "array";
+    case DBUS_TYPE_VARIANT:
+      return "variant";
+    case DBUS_STRUCT_BEGIN_CHAR:
+      return "begin_struct";
+    case DBUS_STRUCT_END_CHAR:
+      return "end_struct";
+    case DBUS_DICT_ENTRY_BEGIN_CHAR:
+      return "begin_dict_entry";
+    case DBUS_DICT_ENTRY_END_CHAR:
+      return "end_dict_entry";
+    case DBUS_TYPE_UNIX_FD:
+      return "unix_fd";
     default:
-      return FALSE;
+      return "unknown";
     }
 }
 
 /**
  * If in verbose mode, print a block of binary data.
  *
- * @todo right now it prints even if not in verbose mode
- *
  * @param data the data
  * @param len the length of the data
  * @param offset where to start counting for byte indexes
@@ -1250,6 +1346,9 @@ _dbus_verbose_bytes (const unsigned char *data,
 
   _dbus_assert (len >= 0);
 
+  if (!_dbus_is_verbose())
+    return;
+
   /* Print blanks on first row if appropriate */
   aligned = _DBUS_ALIGN_ADDRESS (data, 4);
   if (aligned > data)
@@ -1258,7 +1357,7 @@ _dbus_verbose_bytes (const unsigned char *data,
 
   if (aligned != data)
     {
-      _dbus_verbose ("%4d\t%p: ", - (data - aligned), aligned);
+      _dbus_verbose ("%4ld\t%p: ", - (long)(data - aligned), aligned);
       while (aligned != data)
         {
           _dbus_verbose ("    ");
@@ -1295,16 +1394,10 @@ _dbus_verbose_bytes (const unsigned char *data,
           if (i > 7 &&
               _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i])
             {
-#ifdef DBUS_HAVE_INT64
-              /* I think I probably mean "GNU libc printf" and not "GNUC"
-               * but we'll wait until someone complains. If you hit this,
-               * just turn off verbose mode as a workaround.
-               */
-#if __GNUC__
-              _dbus_verbose (" u64: 0x%llx",
+#ifdef DBUS_INT64_PRINTF_MODIFIER
+              _dbus_verbose (" u64: 0x%" DBUS_INT64_PRINTF_MODIFIER "x",
                              *(dbus_uint64_t*)&data[i-8]);
 #endif
-#endif
               _dbus_verbose (" dbl: %g",
                              *(double*)&data[i-8]);
             }
@@ -1354,12 +1447,108 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
   _dbus_verbose_bytes (d, len, start);
 }
 
+static int
+map_type_char_to_type (int t)
+{
+  if (t == DBUS_STRUCT_BEGIN_CHAR)
+    return DBUS_TYPE_STRUCT;
+  else if (t == DBUS_DICT_ENTRY_BEGIN_CHAR)
+    return DBUS_TYPE_DICT_ENTRY;
+  else
+    {
+      _dbus_assert (t != DBUS_STRUCT_END_CHAR);
+      _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
+      return t;
+    }
+}
+
+/**
+ * Get the first type in the signature. The difference between this
+ * and just getting the first byte of the signature is that you won't
+ * get DBUS_STRUCT_BEGIN_CHAR, you'll get DBUS_TYPE_STRUCT
+ * instead.
+ *
+ * @param str string containing signature
+ * @param pos where the signature starts
+ * @returns the first type in the signature
+ */
+int
+_dbus_first_type_in_signature (const DBusString *str,
+                               int               pos)
+{
+  return map_type_char_to_type (_dbus_string_get_byte (str, pos));
+}
+
+/**
+ * Similar to #_dbus_first_type_in_signature, but operates
+ * on a C string buffer.
+ *
+ * @param str a C string buffer
+ * @param pos where the signature starts
+ * @returns the first type in the signature
+ */
+int
+_dbus_first_type_in_signature_c_str (const char       *str,
+                                    int               pos)
+{
+  return map_type_char_to_type (str[pos]);
+}
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-test.h"
 #include <stdio.h>
 
+/**
+ * Reads a block of fixed-length basic values, as an optimization
+ * vs. reading each one individually into a new buffer.
+ *
+ * This function returns the data in-place; it does not make a copy,
+ * and it does not swap the bytes.
+ *
+ * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back
+ * and the "value" argument should be a "const double**" and so on.
+ *
+ * @param str the string to read from
+ * @param pos position to read from
+ * @param element_type type of array elements
+ * @param value place to return the array
+ * @param n_elements number of array elements to read
+ * @param byte_order the byte order, used to read the array length
+ * @param new_pos #NULL or location to store a position after the elements
+ */
+void
+_dbus_marshal_read_fixed_multi  (const DBusString *str,
+                                 int               pos,
+                                 int               element_type,
+                                 void             *value,
+                                 int               n_elements,
+                                 int               byte_order,
+                                 int              *new_pos)
+{
+  int array_len;
+  int alignment;
+
+  _dbus_assert (dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_basic (element_type));
+
+#if 0
+  _dbus_verbose ("reading %d elements of %s\n",
+                 n_elements, _dbus_type_to_string (element_type));
+#endif
+  
+  alignment = _dbus_type_get_alignment (element_type);
+
+  pos = _DBUS_ALIGN_VALUE (pos, alignment);
+  
+  array_len = n_elements * alignment;
+
+  *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len);
+  if (new_pos)
+    *new_pos = pos + array_len;
+}
+
 static void
 swap_test_array (void *array,
                  int   len_bytes,
@@ -1367,6 +1556,10 @@ swap_test_array (void *array,
                  int   alignment)
 {
   DBusString t;
+
+  if (alignment == 1)
+    return;
+  
   _dbus_string_init_const_len (&t, array, len_bytes);
   swap_array (&t, 0, len_bytes / alignment, byte_order, alignment);
 }
@@ -1420,8 +1613,13 @@ swap_test_array (void *array,
 
 #define MARSHAL_FIXED_ARRAY(typename, byte_order, literal)                                      \
   do {                                                                                          \
+     int next;                                                                                  \
+     v_UINT32 = sizeof(literal);                                                                \
+     if (!_dbus_marshal_write_basic (&str, pos, DBUS_TYPE_UINT32, &v_UINT32,                    \
+                                     byte_order, &next))                                        \
+       _dbus_assert_not_reached ("no memory");                                                  \
      v_ARRAY_##typename = literal;                                                              \
-     if (!_dbus_marshal_write_fixed_array (&str, pos, DBUS_TYPE_##typename,                     \
+     if (!_dbus_marshal_write_fixed_multi (&str, next, DBUS_TYPE_##typename,                    \
                                            &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal),      \
                                            byte_order, NULL))                                   \
        _dbus_assert_not_reached ("no memory");                                                  \
@@ -1429,10 +1627,14 @@ swap_test_array (void *array,
 
 #define DEMARSHAL_FIXED_ARRAY(typename, byte_order)                                             \
   do {                                                                                          \
-    _dbus_marshal_read_fixed_array (&str, pos, DBUS_TYPE_##typename, &v_ARRAY_##typename,       \
-                                    &n_elements, byte_order, &pos);                             \
-    swap_test_array (v_ARRAY_##typename, n_elements * sizeof(v_ARRAY_##typename[0]),            \
-                     byte_order, sizeof(v_ARRAY_##typename[0]));                                \
+    int next;                                                                                   \
+    alignment = _dbus_type_get_alignment (DBUS_TYPE_##typename);                                \
+    v_UINT32 = _dbus_marshal_read_uint32 (&str, dump_pos, byte_order, &next);                   \
+    _dbus_marshal_read_fixed_multi (&str, next, DBUS_TYPE_##typename, &v_ARRAY_##typename,      \
+                                    v_UINT32/alignment,                                         \
+                                    byte_order, NULL);                                          \
+    swap_test_array (v_ARRAY_##typename, v_UINT32,                                              \
+                     byte_order, alignment);                                                    \
   } while (0)
 
 #define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal)                  \
@@ -1461,9 +1663,11 @@ swap_test_array (void *array,
 dbus_bool_t
 _dbus_marshal_test (void)
 {
+  int alignment;
   DBusString str;
   int pos, dump_pos;
-  int n_elements;
+  unsigned char array1[5] = { 3, 4, 0, 1, 9 };
+  dbus_int16_t array2[3] = { 124, 457, 780 };
   dbus_int32_t array4[3] = { 123, 456, 789 };
 #ifdef DBUS_HAVE_INT64
   dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff),
@@ -1471,17 +1675,22 @@ _dbus_marshal_test (void)
                              DBUS_INT64_CONSTANT (0x789ffffffff) };
   dbus_int64_t *v_ARRAY_INT64;
 #endif
+  unsigned char *v_ARRAY_BYTE;
+  dbus_int16_t *v_ARRAY_INT16;
+  dbus_uint16_t *v_ARRAY_UINT16;
   dbus_int32_t *v_ARRAY_INT32;
-  double *v_ARRAY_DOUBLE;
+  dbus_uint32_t *v_ARRAY_UINT32;
   DBusString t;
   double v_DOUBLE;
   double t_DOUBLE;
+  dbus_int16_t v_INT16;
+  dbus_uint16_t v_UINT16;
   dbus_int32_t v_INT32;
   dbus_uint32_t v_UINT32;
   dbus_int64_t v_INT64;
   dbus_uint64_t v_UINT64;
   unsigned char v_BYTE;
-  unsigned char v_BOOLEAN;
+  dbus_bool_t v_BOOLEAN;
   const char *v_STRING;
   const char *v_SIGNATURE;
   const char *v_OBJECT_PATH;
@@ -1505,6 +1714,14 @@ _dbus_marshal_test (void)
   if (!_DBUS_DOUBLES_BITWISE_EQUAL (t_DOUBLE, v_DOUBLE))
     _dbus_assert_not_reached ("got wrong double value");
 
+  /* Marshal signed 16 integers */
+  MARSHAL_TEST (INT16, DBUS_BIG_ENDIAN, -12345);
+  MARSHAL_TEST (INT16, DBUS_LITTLE_ENDIAN, -12345);
+
+  /* Marshal unsigned 16 integers */
+  MARSHAL_TEST (UINT16, DBUS_BIG_ENDIAN, 0x1234);
+  MARSHAL_TEST (UINT16, DBUS_LITTLE_ENDIAN, 0x1234);
+  
   /* Marshal signed integers */
   MARSHAL_TEST (INT32, DBUS_BIG_ENDIAN, -12345678);
   MARSHAL_TEST (INT32, DBUS_LITTLE_ENDIAN, -12345678);
@@ -1550,9 +1767,19 @@ _dbus_marshal_test (void)
   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)");
 
   /* Arrays */
+  MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_BIG_ENDIAN, array2);
+  MARSHAL_TEST_FIXED_ARRAY (INT16, DBUS_LITTLE_ENDIAN, array2);
+  MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_BIG_ENDIAN, array2);
+  MARSHAL_TEST_FIXED_ARRAY (UINT16, DBUS_LITTLE_ENDIAN, array2);
+  
   MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4);
   MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4);
+  MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_BIG_ENDIAN, array4);
+  MARSHAL_TEST_FIXED_ARRAY (UINT32, DBUS_LITTLE_ENDIAN, array4);
 
+  MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_BIG_ENDIAN, array1);
+  MARSHAL_TEST_FIXED_ARRAY (BYTE, DBUS_LITTLE_ENDIAN, array1);
+  
 #ifdef DBUS_HAVE_INT64
   MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8);
   MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8);
@@ -1675,16 +1902,18 @@ _dbus_marshal_test (void)
                                     _dbus_string_get_const_data (&str)));
 
   /* unsigned little */
-  _dbus_marshal_set_uint32 (&str, DBUS_LITTLE_ENDIAN,
-                            0, 0x123456);
+  _dbus_marshal_set_uint32 (&str,
+                            0, 0x123456,
+                            DBUS_LITTLE_ENDIAN);
 
   _dbus_assert (0x123456 ==
                 _dbus_unpack_uint32 (DBUS_LITTLE_ENDIAN,
                                      _dbus_string_get_const_data (&str)));
 
   /* unsigned big */
-  _dbus_marshal_set_uint32 (&str, DBUS_BIG_ENDIAN,
-                            0, 0x123456);
+  _dbus_marshal_set_uint32 (&str,
+                            0, 0x123456,
+                            DBUS_BIG_ENDIAN);
 
   _dbus_assert (0x123456 ==
                 _dbus_unpack_uint32 (DBUS_BIG_ENDIAN,