Revert merge of master (dbus-1.5) into dbus-1.4
[platform/upstream/dbus.git] / dbus / dbus-marshal-basic.c
index a2e3275..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,21 +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);
-}
-
 #ifndef DBUS_HAVE_INT64
 /* from ORBit */
 static void
@@ -162,6 +162,27 @@ unpack_8_octets (int                  byte_order,
 }
 #endif
 
+#ifndef _dbus_unpack_uint16
+/**
+ * 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_uint16_t
+_dbus_unpack_uint16 (int                  byte_order,
+                     const unsigned char *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 unsigned integer from a data pointer
@@ -183,18 +204,20 @@ _dbus_unpack_uint32 (int                  byte_order,
 }
 #endif /* _dbus_unpack_uint32 */
 
-/**
- * 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)
+static void
+set_2_octets (DBusString          *str,
+              int                  offset,
+              dbus_uint16_t        value,
+              int                  byte_order)
 {
-  return (dbus_int32_t) _dbus_unpack_uint32 (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
@@ -210,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
@@ -280,7 +303,7 @@ set_string (DBusString          *str,
 
   _dbus_string_init_const (&dstr, value);
 
-  _dbus_assert (_DBUS_ALIGN_VALUE (pos, 4) == pos);
+  _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));
 
@@ -372,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;
@@ -380,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)
@@ -476,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 */
       }
@@ -528,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;
     }
@@ -548,55 +607,33 @@ _dbus_marshal_read_basic (const DBusString      *str,
     *new_pos = pos;
 }
 
-/**
- * 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.
- *
- * @todo we aren't using this function (except in the test suite)
- * 
- * @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)
+static dbus_bool_t
+marshal_2_octets (DBusString   *str,
+                  int           insert_at,
+                  dbus_uint16_t value,
+                  int           byte_order,
+                  int          *pos_after)
 {
-  int array_len;
-  int alignment;
+  dbus_bool_t retval;
+  int orig_len;
 
-  _dbus_assert (_dbus_type_is_fixed (element_type));
-  _dbus_assert (_dbus_type_is_basic (element_type));
+  _dbus_assert (sizeof (value) == 2);
 
-#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);
+  if (byte_order != DBUS_COMPILER_BYTE_ORDER)
+    value = DBUS_UINT16_SWAP_LE_BE (value);
 
-  pos = _DBUS_ALIGN_VALUE (pos, alignment);
-  
-  array_len = n_elements * alignment;
+  orig_len = _dbus_string_get_length (str);
 
-  *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len);
-  if (new_pos)
-    *new_pos = pos + array_len;
+  retval = _dbus_string_insert_2_aligned (str, insert_at,
+                                          (const unsigned char *)&value);
+
+  if (pos_after)
+    {
+      *pos_after = insert_at + (_dbus_string_get_length (str) - orig_len);
+      _dbus_assert (*pos_after <= _dbus_string_get_length (str));
+    }
+
+  return retval;
 }
 
 static dbus_bool_t
@@ -689,6 +726,9 @@ marshal_len_followed_by_bytes (int                  marshal_as,
 
   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;
 
@@ -778,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;
@@ -846,6 +895,61 @@ marshal_1_octets_array (DBusString          *str,
   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
 swap_array (DBusString *str,
             int         array_start,
@@ -857,37 +961,11 @@ 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);
     }
 }
 
@@ -945,7 +1023,7 @@ marshal_fixed_multi (DBusString           *str,
 
 /**
  * Marshals a block of values of fixed-length type all at once, as an
- * optimization.  _dbus_type_is_fixed() returns #TRUE for fixed-length
+ * 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
@@ -971,7 +1049,7 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
 {
   const void* vp = *(const DBusBasicValue**)value;
   
-  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_fixed (element_type));
   _dbus_assert (n_elements >= 0);
 
 #if 0
@@ -981,14 +1059,16 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
   
   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:
+    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:
@@ -1027,11 +1107,17 @@ _dbus_marshal_skip_basic (const DBusString      *str,
   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;
@@ -1111,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:
@@ -1129,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:
@@ -1155,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:
@@ -1165,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:
@@ -1173,80 +1269,6 @@ _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 #FALSE if the type can occupy different lengths
- */
-dbus_bool_t
-_dbus_type_is_fixed (int typecode)
-{
-  switch (typecode)
-    {
-    case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
-    case DBUS_TYPE_INT32:
-    case DBUS_TYPE_UINT32:
-    case DBUS_TYPE_INT64:
-    case DBUS_TYPE_UINT64:
-    case DBUS_TYPE_DOUBLE:
-      return TRUE;
-    default:
-      return FALSE;
-    }
-}
-
 /**
  * Returns a string describing the given type.
  *
@@ -1264,10 +1286,18 @@ _dbus_type_to_string (int typecode)
       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 "double";
     case DBUS_TYPE_STRING:
@@ -1278,6 +1308,8 @@ _dbus_type_to_string (int typecode)
       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:
@@ -1286,6 +1318,12 @@ _dbus_type_to_string (int typecode)
       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 "unknown";
     }
@@ -1294,8 +1332,6 @@ _dbus_type_to_string (int typecode)
 /**
  * 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
@@ -1310,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)
@@ -1318,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 ("    ");
@@ -1355,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]);
             }
@@ -1414,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,
@@ -1538,6 +1667,7 @@ _dbus_marshal_test (void)
   DBusString str;
   int pos, dump_pos;
   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),
@@ -1546,17 +1676,21 @@ _dbus_marshal_test (void)
   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;
@@ -1580,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);
@@ -1625,8 +1767,15 @@ _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);