finish off my TODO list for stuff needed to port dbus-message.c. Next
authorHavoc Pennington <hp@redhat.com>
Mon, 3 Jan 2005 07:15:38 +0000 (07:15 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 3 Jan 2005 07:15:38 +0000 (07:15 +0000)
step is to do so.

dbus/dbus-marshal-basic.c
dbus/dbus-marshal-basic.h
dbus/dbus-marshal-recursive.c
dbus/dbus-marshal-recursive.h

index 17e2964..11ebfaf 100644 (file)
@@ -553,6 +553,57 @@ _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)
+{
+  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);
+
+  array_len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos);
+
+  alignment = _dbus_type_get_alignment (element_type);
+
+  pos = _DBUS_ALIGN_VALUE (pos, alignment);
+
+  *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len);
+
+  *n_elements = array_len / alignment;
+
+  if (new_pos)
+    *new_pos = pos + array_len;
+}
+
 static dbus_bool_t
 marshal_4_octets (DBusString   *str,
                   int           insert_at,
@@ -663,7 +714,7 @@ marshal_len_followed_by_bytes (int                  marshal_as,
                               str, pos))
     goto oom;
 
-#if 1
+#if 0
   /* too expensive */
   _dbus_assert (_dbus_string_equal_substring (&value_str, 0, value_len,
                                               str, pos));
@@ -779,82 +830,83 @@ static dbus_bool_t
 marshal_1_octets_array (DBusString          *str,
                         int                  insert_at,
                         const unsigned char *value,
-                        int                  len,
+                        int                  n_elements,
                         int                  byte_order,
                         int                 *pos_after)
 {
   return marshal_len_followed_by_bytes (MARSHAL_AS_BYTE_ARRAY,
-                                        str, insert_at, value, len,
+                                        str, insert_at, value, n_elements,
                                         byte_order, pos_after);
 }
 
-static dbus_bool_t
-marshal_4_octets_array (DBusString          *str,
-                        int                  insert_at,
-                        const dbus_uint32_t *value,
-                        int                  len,
-                        int                  byte_order)
+static void
+swap_array (DBusString *str,
+            int         array_start,
+            int         n_elements,
+            int         byte_order,
+            int         alignment)
 {
-  int old_string_len;
-  int array_start;
-
-  _dbus_assert_not_reached ("FIXME insert_at");
-
-  old_string_len = _dbus_string_get_length (str);
-
-  if (!marshal_4_octets (str, insert_at, len*4, byte_order, NULL))
-    goto error;
-
-  array_start = _dbus_string_get_length (str);
-
-  if (!_dbus_string_append_len (str, (const unsigned char*) value,
-                                len * 4))
-    goto error;
+  _dbus_assert (_DBUS_ALIGN_VALUE (array_start, alignment) == (unsigned) array_start);
 
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
     {
-      const unsigned char *d;
-      const unsigned char *end;
+      unsigned char *d;
+      unsigned char *end;
 
-      d = _dbus_string_get_data (str) + array_start;
-      end = d + len * 4;
-      while (d != 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)
         {
-          *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d));
-          d += 4;
+          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;
+            }
         }
-    }
-
-  return TRUE;
-
- error:
-  /* Restore previous length */
-  _dbus_string_set_length (str, old_string_len);
+      else
+        {
+          _dbus_assert (alignment == 4);
 
-  return FALSE;
+          while (d != end)
+            {
+              *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d));
+              d += 4;
+            }
+        }
+    }
 }
 
 static dbus_bool_t
-marshal_8_octets_array (DBusString           *str,
-                        int                   insert_at,
-                        const DBusBasicValue *value,
-                        int                   len,
-                        int                   byte_order)
+marshal_fixed_array (DBusString           *str,
+                     int                   insert_at,
+                     const DBusBasicValue *value,
+                     int                   n_elements,
+                     int                   byte_order,
+                     int                   alignment,
+                     int                  *pos_after)
 {
   int old_string_len;
   int array_start;
-
-  _dbus_assert_not_reached ("FIXME insert_at");
+  DBusString t;
 
   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, len*8, byte_order, NULL))
+  if (!marshal_4_octets (str, insert_at, n_elements * alignment,
+                         byte_order, &array_start))
     goto error;
 
-  array_start = _dbus_string_get_length (str);
+  _dbus_verbose ("marshaled len %d at %d array start %d\n", n_elements * alignment, insert_at, array_start);
 
   /* Note that we do alignment padding unconditionally
    * even if the array is empty; this means that
@@ -862,62 +914,57 @@ marshal_8_octets_array (DBusString           *str,
    * in the array.
    */
 
-  if (!_dbus_string_align_length (str, 8))
+  if (!_dbus_string_insert_alignment (str, &array_start, alignment))
     goto error;
 
-  if (!_dbus_string_append_len (str, (const unsigned char*) value,
-                                len * 8))
-    goto error;
+  _dbus_string_init_const_len (&t,
+                               (const unsigned char*) value,
+                               n_elements * alignment);
 
-  if (byte_order != DBUS_COMPILER_BYTE_ORDER)
-    {
-      const unsigned char *d;
-      const unsigned char *end;
+  if (!_dbus_string_copy (&t, 0,
+                          str, array_start))
+    goto error;
 
-      d = _dbus_string_get_data (str) + array_start;
-      end = d + len * 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;
-        }
-    }
+  swap_array (str, array_start, n_elements, byte_order, alignment);
 
   return TRUE;
 
  error:
-  /* Restore previous length */
-  _dbus_string_set_length (str, old_string_len);
+  _dbus_string_delete (str, insert_at,
+                       _dbus_string_get_length (str) - old_string_len);
 
   return FALSE;
 }
 
 /**
- * Marshals a basic type array
+ * 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.
+ *
+ * The value argument should be the adddress of an
+ * array, so e.g. "const dbus_uint32_t**"
  *
  * @param str string to marshal to
  * @param insert_at where to insert the value
  * @param element_type type of array elements
- * @param value pointer to value
- * @param len length of value data in elements
+ * @param value address of an array to marshal
+ * @param len 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_basic_array (DBusString *str,
+_dbus_marshal_write_fixed_array (DBusString *str,
                                  int         insert_at,
                                  int         element_type,
                                  const void *value,
-                                 int         len,
+                                 int         n_elements,
                                  int         byte_order,
                                  int        *pos_after)
 {
-  /* FIXME use the insert_at arg and fill in pos_after */
+  const void* vp = *(const DBusBasicValue**)value;
+
+  _dbus_assert (_dbus_type_is_fixed (element_type));
 
   switch (element_type)
     {
@@ -925,29 +972,20 @@ _dbus_marshal_write_basic_array (DBusString *str,
       /* 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, value, len, byte_order, pos_after);
+      return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after);
       break;
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
-      return marshal_4_octets_array (str, insert_at, value, len, byte_order);
+      return marshal_fixed_array (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_8_octets_array (str, insert_at, value, len, byte_order);
-      break;
-
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-      _dbus_assert_not_reached ("handle string arrays");
-      break;
-
-    case DBUS_TYPE_SIGNATURE:
-      _dbus_assert_not_reached ("handle signature");
+      return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 8, pos_after);
       break;
 
     default:
-      _dbus_assert_not_reached ("non basic type in array");
+      _dbus_assert_not_reached ("non fixed type in array write");
       break;
     }
 
@@ -1173,10 +1211,10 @@ _dbus_type_is_basic (int typecode)
  * first byte of the old and new value would be in the same location,
  * so alignment padding is not a factor.
  *
- * @returns #TRUE if the type can occupy different lengths
+ * @returns #FALSE if the type can occupy different lengths
  */
 dbus_bool_t
-_dbus_type_length_varies (int typecode)
+_dbus_type_is_fixed (int typecode)
 {
   switch (typecode)
     {
@@ -1187,9 +1225,9 @@ _dbus_type_length_varies (int typecode)
     case DBUS_TYPE_INT64:
     case DBUS_TYPE_UINT64:
     case DBUS_TYPE_DOUBLE:
-      return FALSE;
-    default:
       return TRUE;
+    default:
+      return FALSE;
     }
 }
 
@@ -1257,6 +1295,16 @@ _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",
+                             *(dbus_uint64_t*)&data[i-8]);
+#endif
+#endif
               _dbus_verbose (" dbl: %g",
                              *(double*)&data[i-8]);
             }
@@ -1312,6 +1360,17 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
 #include "dbus-test.h"
 #include <stdio.h>
 
+static void
+swap_test_array (void *array,
+                 int   len_bytes,
+                 int   byte_order,
+                 int   alignment)
+{
+  DBusString t;
+  _dbus_string_init_const_len (&t, array, len_bytes);
+  swap_array (&t, 0, len_bytes / alignment, byte_order, alignment);
+}
+
 #define MARSHAL_BASIC(typename, byte_order, literal)                    \
   do {                                                                  \
      v_##typename = literal;                                            \
@@ -1324,7 +1383,7 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
 #define DEMARSHAL_BASIC(typename, byte_order)                                   \
   do {                                                                          \
     _dbus_marshal_read_basic (&str, pos, DBUS_TYPE_##typename, &v_##typename,   \
-                                byte_order, &pos);                              \
+                              byte_order, &pos);                                \
   } while (0)
 
 #define DEMARSHAL_BASIC_AND_CHECK(typename, byte_order, literal)                        \
@@ -1359,19 +1418,61 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
       }                                                                                 \
   } while (0)
 
+#define MARSHAL_FIXED_ARRAY(typename, byte_order, literal)                                      \
+  do {                                                                                          \
+     v_ARRAY_##typename = literal;                                                              \
+     if (!_dbus_marshal_write_fixed_array (&str, pos, DBUS_TYPE_##typename,                     \
+                                           &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal),      \
+                                           byte_order, NULL))                                   \
+       _dbus_assert_not_reached ("no memory");                                                  \
+   } while (0)
+
+#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]));                                \
+  } while (0)
+
+#define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal)                  \
+  do {                                                                                  \
+    DEMARSHAL_FIXED_ARRAY (typename, byte_order);                                       \
+    if (memcmp (literal, v_ARRAY_##typename, sizeof (literal) != 0))                    \
+      {                                                                                 \
+        _dbus_verbose ("MARSHALED DATA\n");                                             \
+        _dbus_verbose_bytes_of_string (&str, dump_pos,                                  \
+                                      _dbus_string_get_length (&str) - dump_pos);       \
+        _dbus_verbose ("LITERAL DATA\n");                                               \
+        _dbus_verbose_bytes ((char*)literal, sizeof (literal), 0);                      \
+        _dbus_verbose ("READ DATA\n");                                                  \
+        _dbus_verbose_bytes ((char*)v_ARRAY_##typename, sizeof (literal), 0);           \
+        _dbus_assert_not_reached ("demarshaled wrong fixed array value");               \
+      }                                                                                 \
+  } while (0)
+
+#define MARSHAL_TEST_FIXED_ARRAY(typename, byte_order, literal)         \
+  do {                                                                  \
+    MARSHAL_FIXED_ARRAY (typename, byte_order, literal);                \
+    dump_pos = pos;                                                     \
+    DEMARSHAL_FIXED_ARRAY_AND_CHECK (typename, byte_order, literal);    \
+  } while (0)
+
 dbus_bool_t
 _dbus_marshal_test (void)
 {
   DBusString str;
   int pos, dump_pos;
-#if 0
-  dbus_int32_t array1[3] = { 0x123, 0x456, 0x789 }, *array2;
+  int n_elements;
+  dbus_int32_t array4[3] = { 123, 456, 789 };
 #ifdef DBUS_HAVE_INT64
-  dbus_int64_t array3[3] = { DBUS_INT64_CONSTANT (0x123ffffffff),
+  dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff),
                              DBUS_INT64_CONSTANT (0x456ffffffff),
-                             DBUS_INT64_CONSTANT (0x789ffffffff) }, *array4;
-#endif
+                             DBUS_INT64_CONSTANT (0x789ffffffff) };
+  dbus_int64_t *v_ARRAY_INT64;
 #endif
+  dbus_int32_t *v_ARRAY_INT32;
+  double *v_ARRAY_DOUBLE;
   DBusString t;
   double v_DOUBLE;
   double t_DOUBLE;
@@ -1448,6 +1549,15 @@ _dbus_marshal_test (void)
   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "a(ii)");
   MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)");
 
+  /* Arrays */
+  MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4);
+  MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4);
+
+#ifdef DBUS_HAVE_INT64
+  MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8);
+  MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8);
+#endif
+
 #if 0
 
   /*
index 529ada5..bf75cbe 100644 (file)
@@ -275,11 +275,11 @@ dbus_bool_t   _dbus_marshal_write_basic       (DBusString       *str,
                                                const void       *value,
                                                int               byte_order,
                                                int              *pos_after);
-dbus_bool_t   _dbus_marshal_write_basic_array (DBusString       *str,
+dbus_bool_t   _dbus_marshal_write_fixed_array (DBusString       *str,
                                                int               insert_at,
                                                int               element_type,
                                                const void       *value,
-                                               int               len,
+                                               int               n_elements,
                                                int               byte_order,
                                                int              *pos_after);
 void          _dbus_marshal_read_basic        (const DBusString *str,
@@ -288,6 +288,13 @@ void          _dbus_marshal_read_basic        (const DBusString *str,
                                                void             *value,
                                                int               byte_order,
                                                int              *new_pos);
+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);
 void          _dbus_marshal_skip_basic        (const DBusString *str,
                                                int               type,
                                                int               byte_order,
@@ -308,7 +315,7 @@ dbus_bool_t   _dbus_type_is_valid             (int               typecode);
 int           _dbus_type_get_alignment        (int               typecode);
 dbus_bool_t   _dbus_type_is_basic             (int               typecode);
 dbus_bool_t   _dbus_type_is_container         (int               typecode);
-dbus_bool_t   _dbus_type_length_varies        (int               typecode);
+dbus_bool_t   _dbus_type_is_fixed             (int               typecode);
 
 
 
index 58cab0c..a3ef021 100644 (file)
@@ -764,14 +764,60 @@ _dbus_type_reader_read_basic (const DBusTypeReader    *reader,
 #endif
 }
 
-dbus_bool_t
-_dbus_type_reader_read_array_of_basic (const DBusTypeReader    *reader,
-                                       int                      type,
-                                       void                   **array,
-                                       int                     *array_len)
+/**
+ * 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.
+ *
+ * @param reader the reader to read from
+ * @param value place to return the array
+ * @param n_elements place to return number of array elements
+ */
+void
+_dbus_type_reader_read_fixed_array (const DBusTypeReader  *reader,
+                                    void                  *value,
+                                    int                   *n_elements)
 {
+  int element_type;
+  int end_pos;
+  int remaining_len;
+  int alignment;
+
   _dbus_assert (!reader->klass->types_only);
+  _dbus_assert (reader->klass == &array_reader_class);
+
+  element_type = first_type_in_signature (reader->type_str,
+                                          reader->type_pos);
+
+  _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
+  _dbus_assert (_dbus_type_is_fixed (element_type));
+
+  alignment = _dbus_type_get_alignment (element_type);
 
+  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
+  remaining_len = end_pos - reader->value_pos;
+
+  if (remaining_len == 0)
+    *(const DBusBasicValue**) value = NULL;
+  else
+    *(const DBusBasicValue**) value =
+      (void*) _dbus_string_get_const_data_len (reader->value_str,
+                                               reader->value_pos,
+                                               remaining_len);
+
+  *n_elements = remaining_len / alignment;
+  _dbus_assert ((remaining_len % alignment) == 0);
+
+#if RECURSIVE_MARSHAL_TRACE
+  _dbus_verbose ("  type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",
+                 reader, reader->type_pos, reader->value_pos,
+                 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
+#endif
 }
 
 /**
@@ -925,7 +971,106 @@ _dbus_type_reader_get_signature (const DBusTypeReader  *reader,
   *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
 }
 
+typedef struct
+{
+  DBusString replacement;
+  int padding;
+} ReplacementBlock;
+
+static dbus_bool_t
+replacement_block_init (ReplacementBlock *block,
+                        DBusTypeReader   *reader)
+{
+  if (!_dbus_string_init (&block->replacement))
+    return FALSE;
 
+  /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 -
+   * ALIGN_OFFSET is the padding to have the same align properties in
+   * our replacement string as we do at the position being replaced
+   */
+  block->padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8);
+  _dbus_assert (block->padding >= 0);
+
+  if (!_dbus_string_lengthen (&block->replacement, block->padding))
+    goto oom;
+
+  return TRUE;
+
+ oom:
+  _dbus_string_free (&block->replacement);
+  return FALSE;
+}
+
+static dbus_bool_t
+replacement_block_replace (ReplacementBlock     *block,
+                           DBusTypeReader       *reader,
+                           const DBusTypeReader *realign_root)
+{
+  DBusTypeWriter writer;
+  DBusTypeReader realign_reader;
+  DBusList *fixups;
+  int orig_len;
+
+  _dbus_assert (realign_root != NULL);
+
+  orig_len = _dbus_string_get_length (&block->replacement);
+
+  realign_reader = *realign_root;
+
+  _dbus_type_writer_init_values_only (&writer,
+                                      realign_reader.byte_order,
+                                      realign_reader.type_str,
+                                      realign_reader.type_pos,
+                                      &block->replacement,
+                                      _dbus_string_get_length (&block->replacement));
+
+  fixups = NULL;
+  if (!_dbus_type_writer_write_reader_partial (&writer,
+                                               &realign_reader,
+                                               reader,
+                                               block->padding,
+                                               _dbus_string_get_length (&block->replacement) - block->padding,
+                                               &fixups))
+    goto oom;
+
+#if RECURSIVE_MARSHAL_TRACE
+  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", padding,
+                 _dbus_string_get_length (&block->replacement) - padding);
+  _dbus_verbose_bytes_of_string (&block->replacement, padding,
+                                 _dbus_string_get_length (&block->replacement) - padding);
+  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d\n",
+                 reader->value_pos, (int) (8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8)),
+                 realign_reader.value_pos - reader->value_pos);
+  _dbus_verbose_bytes_of_string (reader->value_str,
+                                 reader->value_pos,
+                                 realign_reader.value_pos - reader->value_pos);
+#endif
+
+  /* Move the replacement into position
+   * (realign_reader should now be at the end of the block to be replaced)
+   */
+  if (!_dbus_string_replace_len (&block->replacement, block->padding,
+                                 _dbus_string_get_length (&block->replacement) - block->padding,
+                                 (DBusString*) reader->value_str,
+                                 reader->value_pos,
+                                 realign_reader.value_pos - reader->value_pos))
+    goto oom;
+
+  /* Process our fixups now that we can't have an OOM error */
+  apply_and_free_fixups (&fixups, reader);
+
+  return TRUE;
+
+ oom:
+  _dbus_string_set_length (&block->replacement, orig_len);
+  return FALSE;
+}
+
+static void
+replacement_block_free (ReplacementBlock *block)
+{
+  _dbus_string_free (&block->replacement);
+}
 
 /* In the variable-length case, we have to fix alignment after we insert.
  * The strategy is as follows:
@@ -957,92 +1102,37 @@ reader_set_basic_variable_length (DBusTypeReader       *reader,
                                   const DBusTypeReader *realign_root)
 {
   dbus_bool_t retval;
-  DBusString replacement;
-  int padding;
+  ReplacementBlock block;
   DBusTypeWriter writer;
-  DBusTypeReader realign_reader;
-  DBusList *fixups;
 
   _dbus_assert (realign_root != NULL);
 
   retval = FALSE;
 
-  if (!_dbus_string_init (&replacement))
+  if (!replacement_block_init (&block, reader))
     return FALSE;
 
-  /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 -
-   * ALIGN_OFFSET is the padding to have the same align properties in
-   * our replacement string as we do at the position being replaced
-   */
-  padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8);
-  _dbus_assert (padding >= 0);
-
-  if (!_dbus_string_lengthen (&replacement, padding))
-    goto out;
-
   /* Write the new basic value */
 
   _dbus_type_writer_init_values_only (&writer,
                                       reader->byte_order,
                                       reader->type_str,
                                       reader->type_pos,
-                                      &replacement,
-                                      _dbus_string_get_length (&replacement));
+                                      &block.replacement,
+                                      _dbus_string_get_length (&block.replacement));
 
   if (!_dbus_type_writer_write_basic (&writer, current_type, value))
     goto out;
 
-  /* Rewrite the values following the new basic value, which should
-   * fix their alignment
-   */
-  realign_reader = *realign_root;
-
-  _dbus_type_writer_init_values_only (&writer,
-                                      realign_reader.byte_order,
-                                      realign_reader.type_str,
-                                      realign_reader.type_pos,
-                                      &replacement,
-                                      _dbus_string_get_length (&replacement));
-
-  fixups = NULL;
-  if (!_dbus_type_writer_write_reader_partial (&writer,
-                                               &realign_reader,
-                                               reader,
-                                               padding,
-                                               _dbus_string_get_length (&replacement) - padding,
-                                               &fixups))
+  if (!replacement_block_replace (&block,
+                                  reader,
+                                  realign_root))
     goto out;
 
-#if RECURSIVE_MARSHAL_TRACE
-  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", padding,
-                 _dbus_string_get_length (&replacement) - padding);
-  _dbus_verbose_bytes_of_string (&replacement, padding,
-                                 _dbus_string_get_length (&replacement) - padding);
-  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d\n",
-                 reader->value_pos, (int) (8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8)),
-                 realign_reader.value_pos - reader->value_pos);
-  _dbus_verbose_bytes_of_string (reader->value_str,
-                                 reader->value_pos,
-                                 realign_reader.value_pos - reader->value_pos);
-#endif
-
-  /* Move the replacement into position
-   * (realign_reader should now be at the end of the block to be replaced)
-   */
-  if (!_dbus_string_replace_len (&replacement, padding,
-                                 _dbus_string_get_length (&replacement) - padding,
-                                 (DBusString*) reader->value_str,
-                                 reader->value_pos,
-                                 realign_reader.value_pos - reader->value_pos))
-    goto out;
-
-  /* Process our fixups now that we can't have an OOM error */
-  apply_and_free_fixups (&fixups, reader);
-
   retval = TRUE;
 
  out:
-  _dbus_string_free (&replacement);
+  replacement_block_free (&block);
   return retval;
 }
 
@@ -1060,10 +1150,10 @@ reader_set_basic_fixed_length (DBusTypeReader *reader,
 }
 
 /**
- * Sets a new value for the basic type pointed to by the reader,
- * leaving the reader valid to continue reading. Any other readers may
- * of course be invalidated if you set a variable-length type such as
- * string.
+ * Sets a new value for the basic type value pointed to by the reader,
+ * leaving the reader valid to continue reading. Any other readers
+ * will be invalidated if you set a variable-length type such as a
+ * string.
  *
  * The provided realign_root is the reader to start from when
  * realigning the data that follows the newly-set value. The reader
@@ -1084,6 +1174,10 @@ reader_set_basic_fixed_length (DBusTypeReader *reader,
  * DBusTypeMark. But since DBusMessage is effectively that object for
  * D-BUS it doesn't seem worth creating some random object.)
  *
+ * @todo optimize this by only rewriting until the old and new values
+ * are at the same alignment. Frequently this should result in only
+ * replacing the value that's immediately at hand.
+ *
  * @param reader reader indicating where to set a new value
  * @param value address of the value to set
  * @param realign_root realign from here
@@ -1096,6 +1190,8 @@ _dbus_type_reader_set_basic (DBusTypeReader       *reader,
 {
   int current_type;
 
+  _dbus_assert (!reader->klass->types_only);
+
   current_type = _dbus_type_reader_get_current_type (reader);
 
 #if RECURSIVE_MARSHAL_TRACE
@@ -1109,20 +1205,64 @@ _dbus_type_reader_set_basic (DBusTypeReader       *reader,
 
   _dbus_assert (_dbus_type_is_basic (current_type));
 
-  if (_dbus_type_length_varies (current_type))
+  if (_dbus_type_is_fixed (current_type))
     {
-      _dbus_assert (realign_root != NULL);
-      return reader_set_basic_variable_length (reader, current_type,
-                                               value, realign_root);
+      reader_set_basic_fixed_length (reader, current_type, value);
+      return TRUE;
     }
   else
     {
-      reader_set_basic_fixed_length (reader, current_type, value);
-      return TRUE;
+      _dbus_assert (realign_root != NULL);
+      return reader_set_basic_variable_length (reader, current_type,
+                                               value, realign_root);
     }
 }
 
 /**
+ * Recursively deletes any value pointed to by the reader, leaving the
+ * reader valid to continue reading. Any other readers will be
+ * invalidated.
+ *
+ * The provided realign_root is the reader to start from when
+ * realigning the data that follows the newly-set value.
+ * See _dbus_type_reader_set_basic() for more details on the
+ * realign_root paramter.
+ *
+ * @todo for now this does not delete the typecodes associated with
+ * the value, so this function should only be used for array elements.
+ *
+ * @param reader reader indicating where to delete a value
+ * @param realign_root realign from here
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_type_reader_delete (DBusTypeReader        *reader,
+                          const DBusTypeReader  *realign_root)
+{
+  dbus_bool_t retval;
+  ReplacementBlock block;
+
+  _dbus_assert (realign_root != NULL);
+  _dbus_assert (reader->klass == &array_reader_class);
+
+  retval = FALSE;
+
+  if (!replacement_block_init (&block, reader))
+    return FALSE;
+
+  if (!replacement_block_replace (&block,
+                                  reader,
+                                  realign_root))
+    goto out;
+
+  retval = TRUE;
+
+ out:
+  replacement_block_free (&block);
+  return retval;
+}
+
+/**
  * Compares two readers, which must be iterating over the same value data.
  * Returns #TRUE if the first parameter is further along than the second parameter.
  *
@@ -1844,14 +1984,50 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,
   return retval;
 }
 
+/**
+ * Writes an array of fixed-length basic values, i.e. those that
+ * are both _dbus_type_is_fixed() and _dbus_type_is_basic().
+ *
+ * The value parameter should be the address of said array of values,
+ * so e.g. if it's an array of double, pass in "const double**"
+ *
+ * @param writer the writer
+ * @param element_type type of stuff in the array
+ * @param value address of the array
+ * @param n_elements number of elements in the array
+ * @returns #FALSE if no memory
+ */
 dbus_bool_t
-_dbus_type_writer_write_array (DBusTypeWriter *writer,
-                               int             type,
-                               const void     *array,
-                               int             array_len)
+_dbus_type_writer_write_fixed_array (DBusTypeWriter        *writer,
+                                     int                    element_type,
+                                     const void            *value,
+                                     int                    n_elements)
 {
+  _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
+  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (writer->type_pos_is_expectation);
+
+  if (!write_or_verify_typecode (writer, element_type))
+    _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");
+
+  if (writer->enabled)
+    {
+      if (!_dbus_marshal_write_fixed_array (writer->value_str,
+                                            writer->value_pos,
+                                            element_type,
+                                            value,
+                                            n_elements,
+                                            writer->byte_order,
+                                            &writer->value_pos))
+        return FALSE;
+    }
 
+#if RECURSIVE_MARSHAL_TRACE
+  _dbus_verbose ("  type writer %p fixed array type_pos = %d value_pos = %d\n",
+                 writer, writer->type_pos, writer->value_pos);
+#endif
 
+  return TRUE;
 }
 
 static void
index 025c3e0..765ee56 100644 (file)
@@ -151,10 +151,9 @@ int         _dbus_type_reader_get_current_type          (const DBusTypeReader  *
 dbus_bool_t _dbus_type_reader_array_is_empty            (const DBusTypeReader  *reader);
 void        _dbus_type_reader_read_basic                (const DBusTypeReader  *reader,
                                                          void                  *value);
-dbus_bool_t _dbus_type_reader_read_array_of_basic       (const DBusTypeReader  *reader,
-                                                         int                    type,
-                                                         void                 **array,
-                                                         int                   *array_len);
+void        _dbus_type_reader_read_fixed_array          (const DBusTypeReader  *reader,
+                                                         void                  *value,
+                                                         int                   *n_elements);
 void        _dbus_type_reader_recurse                   (DBusTypeReader        *reader,
                                                          DBusTypeReader        *subreader);
 dbus_bool_t _dbus_type_reader_next                      (DBusTypeReader        *reader);
@@ -166,6 +165,8 @@ void        _dbus_type_reader_get_signature             (const DBusTypeReader  *
 dbus_bool_t _dbus_type_reader_set_basic                 (DBusTypeReader        *reader,
                                                          const void            *value,
                                                          const DBusTypeReader  *realign_root);
+dbus_bool_t _dbus_type_reader_delete                    (DBusTypeReader        *reader,
+                                                         const DBusTypeReader  *realign_root);
 dbus_bool_t _dbus_type_reader_greater_than              (const DBusTypeReader  *lhs,
                                                          const DBusTypeReader  *rhs);
 
@@ -184,10 +185,10 @@ void        _dbus_type_writer_init_values_only     (DBusTypeWriter        *write
 dbus_bool_t _dbus_type_writer_write_basic          (DBusTypeWriter        *writer,
                                                     int                    type,
                                                     const void            *value);
-dbus_bool_t _dbus_type_writer_write_array          (DBusTypeWriter        *writer,
-                                                    int                    type,
-                                                    const void            *array,
-                                                    int                    array_len);
+dbus_bool_t _dbus_type_writer_write_fixed_array    (DBusTypeWriter        *writer,
+                                                    int                    element_type,
+                                                    const void            *value,
+                                                    int                    n_elements);
 dbus_bool_t _dbus_type_writer_recurse              (DBusTypeWriter        *writer,
                                                     int                    container_type,
                                                     const DBusString      *contained_type,