Revert merge of master (dbus-1.5) into dbus-1.4
[platform/upstream/dbus.git] / dbus / dbus-marshal-basic.c
index 84a9cca..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>
 
@@ -413,6 +415,7 @@ _dbus_marshal_set_basic (DBusString       *str,
     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)
@@ -507,59 +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:
-      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->u16 = *(dbus_uint16_t *)(str_data + pos);
+      *vp = *(dbus_uint16_t *)(str_data + pos);
       if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-       vp->u16 = DBUS_UINT16_SWAP_LE_BE (vp->u16);
+       *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 */
       }
@@ -567,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;
     }
@@ -587,57 +607,6 @@ _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)
-{
-  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 dbus_bool_t
 marshal_2_octets (DBusString   *str,
                   int           insert_at,
@@ -757,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;
 
@@ -846,7 +818,7 @@ _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;
 
@@ -870,6 +842,7 @@ _dbus_marshal_write_basic (DBusString *str,
       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;
@@ -1050,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
@@ -1076,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
@@ -1092,11 +1065,10 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
     case DBUS_TYPE_INT16:
     case DBUS_TYPE_UINT16:
       return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 2, pos_after);
-      /* FIXME: we canonicalize to 0 or 1 for the single boolean case
-       * should we here too ? */
     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:
@@ -1145,6 +1117,7 @@ _dbus_marshal_skip_basic (const DBusString      *str,
     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;
@@ -1233,6 +1206,7 @@ _dbus_type_get_alignment (int typecode)
     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:
@@ -1287,6 +1261,7 @@ _dbus_type_is_valid (int typecode)
     case DBUS_TYPE_STRUCT:
     case DBUS_TYPE_DICT_ENTRY:
     case DBUS_TYPE_VARIANT:
+    case DBUS_TYPE_UNIX_FD:
       return TRUE;
 
     default:
@@ -1294,84 +1269,6 @@ _dbus_type_is_valid (int typecode)
     }
 }
 
-/** macro that checks whether a typecode is a container type */
-#define TYPE_IS_CONTAINER(typecode)             \
-    ((typecode) == DBUS_TYPE_STRUCT ||          \
-     (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
-     (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_INT16:
-    case DBUS_TYPE_UINT16:
-    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.
  *
@@ -1397,6 +1294,10 @@ _dbus_type_to_string (int typecode)
       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:
@@ -1421,6 +1322,8 @@ _dbus_type_to_string (int typecode)
       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";
     }
@@ -1429,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
@@ -1445,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)
@@ -1453,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 ("    ");
@@ -1490,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]);
             }
@@ -1549,6 +1447,21 @@ _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
@@ -1563,20 +1476,22 @@ int
 _dbus_first_type_in_signature (const DBusString *str,
                                int               pos)
 {
-  unsigned char t;
-
-  t = _dbus_string_get_byte (str, pos);
+  return map_type_char_to_type (_dbus_string_get_byte (str, pos));
+}
 
-  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;
-    }
+/**
+ * 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]);
 }
 
 /** @} */
@@ -1585,6 +1500,55 @@ _dbus_first_type_in_signature (const DBusString *str,
 #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,
@@ -1716,7 +1680,6 @@ _dbus_marshal_test (void)
   dbus_uint16_t *v_ARRAY_UINT16;
   dbus_int32_t *v_ARRAY_INT32;
   dbus_uint32_t *v_ARRAY_UINT32;
-  double *v_ARRAY_DOUBLE;
   DBusString t;
   double v_DOUBLE;
   double t_DOUBLE;