sync busted marshaling work in progress
authorHavoc Pennington <hp@redhat.com>
Tue, 28 Dec 2004 04:55:52 +0000 (04:55 +0000)
committerHavoc Pennington <hp@redhat.com>
Tue, 28 Dec 2004 04:55:52 +0000 (04:55 +0000)
dbus/dbus-marshal-basic.c
dbus/dbus-marshal-basic.h
dbus/dbus-marshal-recursive.c
dbus/dbus-marshal-recursive.h
dbus/dbus-protocol-new.h

index d325d5f..d2b7b40 100644 (file)
@@ -743,13 +743,25 @@ marshal_8_octets_array (DBusString          *str,
 {
   int old_string_len;
   int array_start;
-
+  
   old_string_len = _dbus_string_get_length (str);
 
+  /*  The array length is the length in bytes of the array,
+   * *excluding* alignment padding.
+   */
   if (!_dbus_marshal_uint32 (str, byte_order, len * 8))
     goto error;
 
   array_start = _dbus_string_get_length (str);
+
+  /* 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
+   * in the array.
+   */
+  
+  if (!_dbus_string_align_length (str, 8))
+    goto error;
   
   if (!_dbus_string_append_len (str, (const unsigned char*) value,
                                 len * 8))
@@ -1350,6 +1362,9 @@ demarshal_8_octets_array (const DBusString  *str,
   int byte_len;
   
   byte_len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+
+  pos = _DBUS_ALIGN_VALUE (pos, 8);
+  
   len = byte_len / 8;
 
   if (len == 0)
@@ -1827,6 +1842,8 @@ _dbus_marshal_skip_array (const DBusString  *str,
 
   len = _dbus_demarshal_uint32 (str, byte_order, *pos, pos);
 
+  /* FIXME we need to insert alignment padding according to array type */
+  
   *pos += len;
 }
 
@@ -1897,8 +1914,9 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str,
 
        /* Demarshal the length  */
        len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
-       
-       *end_pos = pos + len;
+
+        /* FIXME needs to align to the right boundary for the array type */
+       *end_pos = _DBUS_ALIGN_VALUE (pos, 4) + len;
       }
       break;
 
@@ -2428,9 +2446,11 @@ _dbus_type_is_valid (int typecode)
     case DBUS_TYPE_UINT64:
     case DBUS_TYPE_DOUBLE:
     case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_DICT:
-    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_VARIANT:
       return TRUE;
       
     default:
@@ -2439,16 +2459,59 @@ _dbus_type_is_valid (int typecode)
 }
 
 /**
+ * Gets the alignment requirement for the given type;
+ * will be 1, 4, or 8.
+ *
+ * @param typecode the type
+ * @returns alignment of 1, 4, or 8
+ */
+int
+_dbus_type_get_alignment (int typecode)
+{
+  switch (typecode)
+    {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_BOOLEAN:
+      return 1;
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+      /* this stuff is 4 since it starts with a length */
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_DICT:
+    case DBUS_TYPE_VARIANT:
+      return 4;
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+      /* struct is 8 since it could contain an 8-aligned item
+       * 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.
+       */
+    case DBUS_TYPE_STRUCT:
+      return 8;
+      
+    default:
+      _dbus_assert_not_reached ("unknown typecode in _dbus_type_get_alignment()");
+      return 0;
+    }
+}
+
+/**
  * 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
  */
 void
 _dbus_verbose_bytes (const unsigned char *data,
-                     int                  len)
+                     int                  len,
+                     int                  offset)
 {
   int i;
   const unsigned char *aligned;
@@ -2478,7 +2541,7 @@ _dbus_verbose_bytes (const unsigned char *data,
       if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
         {
           _dbus_verbose ("%4d\t%p: ",
-                         i, &data[i]);
+                         offset + i, &data[i]);
         }
       
       if (data[i] >= 32 &&
@@ -2546,7 +2609,7 @@ _dbus_verbose_bytes_of_string (const DBusString    *str,
   
   d = _dbus_string_get_const_data_len (str, start, len);
 
-  _dbus_verbose_bytes (d, len);
+  _dbus_verbose_bytes (d, len, start);
 }
 
 /**
index e8c0b3f..968d22c 100644 (file)
 #undef DBUS_TYPE_STRUCT
 #undef DBUS_NUMBER_OF_TYPES
 
+
 /* Never a legitimate type */
 #define DBUS_TYPE_INVALID       ((int) '\0')
+#define DBUS_TYPE_INVALID_AS_STRING        "\0"
 
 /* Primitive types */
 #define DBUS_TYPE_BYTE          ((int) 'y')
+#define DBUS_TYPE_BYTE_AS_STRING           "y"
 #define DBUS_TYPE_BOOLEAN       ((int) 'b')
+#define DBUS_TYPE_BOOLEAN_AS_STRING        "b"
 #define DBUS_TYPE_INT32         ((int) 'i')
+#define DBUS_TYPE_INT32_AS_STRING          "i"
 
 #define DBUS_TYPE_UINT32        ((int) 'u')
+#define DBUS_TYPE_UINT32_AS_STRING         "u"
 #define DBUS_TYPE_INT64         ((int) 'x')
+#define DBUS_TYPE_INT64_AS_STRING          "x"
 #define DBUS_TYPE_UINT64        ((int) 't')
+#define DBUS_TYPE_UINT64_AS_STRING         "t"
 
 #define DBUS_TYPE_DOUBLE        ((int) 'd')
+#define DBUS_TYPE_DOUBLE_AS_STRING         "d"
 #define DBUS_TYPE_STRING        ((int) 's')
+#define DBUS_TYPE_STRING_AS_STRING         "s"
 #define DBUS_TYPE_OBJECT_PATH   ((int) 'o')
+#define DBUS_TYPE_OBJECT_PATH_AS_STRING    "o"
 
 /* Compound types */
 #define DBUS_TYPE_ARRAY         ((int) 'a')
-#define DBUS_TYPE_DICT          ((int) 'm')
+#define DBUS_TYPE_ARRAY_AS_STRING          "a"
+#define DBUS_TYPE_DICT          ((int) 'm') /* not parameterized; always map<string,variant> */
+#define DBUS_TYPE_DICT_AS_STRING           "m"
 #define DBUS_TYPE_VARIANT       ((int) 'v')
+#define DBUS_TYPE_VARIANT_AS_STRING        "v"
 
 /* STRUCT is sort of special since its code can't appear in a type string,
  * instead DBUS_STRUCT_BEGIN_CHAR has to appear
  */
 #define DBUS_TYPE_STRUCT        ((int) 'r')
+#define DBUS_TYPE_STRUCT_AS_STRING         "r"
 
 /* Does not count INVALID */
 #define DBUS_NUMBER_OF_TYPES    (13)
 
 /* characters other than typecodes that appear in type signatures */
 #define DBUS_STRUCT_BEGIN_CHAR   ((int) '(')
+#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING   "("
 #define DBUS_STRUCT_END_CHAR     ((int) ')')
+#define DBUS_STRUCT_END_CHAR_AS_STRING     ")"
 
 static const char *
 _hack_dbus_type_to_string (int type)
@@ -442,4 +459,6 @@ dbus_bool_t _dbus_marshal_validate_arg    (const DBusString *str,
 
 dbus_bool_t _dbus_type_is_valid           (int               typecode);
 
+int         _dbus_type_get_alignment      (int               typecode);
+
 #endif /* DBUS_MARSHAL_H */
index 1962e62..5bd37a5 100644 (file)
  * @{
  */
 
+static int
+first_type_in_signature (const DBusString *str,
+                         int               pos)
+{
+  int t;
+
+  t = _dbus_string_get_byte (str, pos);
+  
+  if (t == DBUS_STRUCT_BEGIN_CHAR)
+    return DBUS_TYPE_STRUCT;
+  else
+    return t;
+}
+
+static int
+element_type_get_alignment (const DBusString *str,
+                            int               pos)
+{
+  return _dbus_type_get_alignment (first_type_in_signature (str, pos));
+}
+
 void
 _dbus_type_reader_init (DBusTypeReader    *reader,
                         int                byte_order,
@@ -42,8 +63,9 @@ _dbus_type_reader_init (DBusTypeReader    *reader,
   reader->type_pos = type_pos;
   reader->value_str = value_str;
   reader->value_pos = value_pos;
+  reader->container_type = DBUS_TYPE_INVALID;
 
-  _dbus_verbose ("type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
+  _dbus_verbose ("  type reader %p init 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));
 }
@@ -53,17 +75,51 @@ _dbus_type_reader_get_current_type (DBusTypeReader *reader)
 {
   int t;
 
-  t = _dbus_string_get_byte (reader->type_str,
-                             reader->type_pos);
+  /* for INVALID t will == DBUS_TYPE_INVALID when we
+   * reach the end of type_str, for STRUCT we have to
+   * check the finished flag
+   */
+  if (reader->container_type == DBUS_TYPE_INVALID)
+    {
+      t = first_type_in_signature (reader->type_str,
+                                   reader->type_pos);
+    }
+  else if (reader->container_type == DBUS_TYPE_STRUCT)
+    {
+      if (reader->u.strct.finished)
+        t = DBUS_TYPE_INVALID;
+      else
+        t = first_type_in_signature (reader->type_str,
+                                     reader->type_pos);
+    }
+  else if (reader->container_type == DBUS_TYPE_ARRAY)
+    {
+      /* return the array element type if elements remain, and
+       * TYPE_INVALID otherwise
+       */
+      int end_pos;
 
-  if (t == DBUS_STRUCT_BEGIN_CHAR)
-    t = DBUS_TYPE_STRUCT;
+      end_pos = reader->u.array.start_pos + reader->u.array.len;
 
-  /* this should never be a stopping place */
-  _dbus_assert (t != DBUS_STRUCT_END_CHAR);
+      _dbus_assert (reader->value_pos <= end_pos);
+      _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
+
+      if (reader->value_pos < end_pos)
+        t = reader->u.array.element_type;
+      else
+        t = DBUS_TYPE_INVALID;
+    }
+  else
+    {
+      _dbus_assert_not_reached ("reader->container_type should not be set to this");
+      t = DBUS_TYPE_INVALID; /* quiet gcc */
+    }
 
+  _dbus_assert (t != DBUS_STRUCT_END_CHAR);
+  _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
+  
 #if 0
-  _dbus_verbose ("type reader %p current type_pos = %d type = %s\n",
+  _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
                  reader, reader->type_pos,
                  _dbus_type_to_string (t));
 #endif
@@ -72,44 +128,46 @@ _dbus_type_reader_get_current_type (DBusTypeReader *reader)
 }
 
 int
-_dbus_type_reader_get_array_type (DBusTypeReader *reader)
+_dbus_type_reader_get_array_length (DBusTypeReader *reader)
 {
-  int t;
-
-  t = _dbus_type_reader_get_current_type (reader);
-
-  if (t != DBUS_TYPE_ARRAY)
-    return DBUS_TYPE_INVALID;
-
-  t = _dbus_string_get_byte (reader->type_str,
-                             reader->type_pos + 1);  
-  
-  return t;
+  /* FIXME if this is in number of elements I don't know how to compute it
+   * since we only have bytes and elements are variable-length
+   */
 }
 
 void
 _dbus_type_reader_read_basic (DBusTypeReader    *reader,
                               void              *value)
 {
-  int t;
-  int next;
-
-  t = _dbus_type_reader_get_current_type (reader);
+  if (reader->container_type == DBUS_TYPE_INVALID ||
+      reader->container_type == DBUS_TYPE_STRUCT ||
+      reader->container_type == DBUS_TYPE_ARRAY)
+    {
+      int t;
+      int next;
+      
+      t = _dbus_type_reader_get_current_type (reader);
 
-  next = reader->value_pos;
-  _dbus_demarshal_basic_type (reader->value_str,
-                              t, value,
-                              reader->byte_order,
-                              &next);
+      next = reader->value_pos;
+      _dbus_demarshal_basic_type (reader->value_str,
+                                  t, value,
+                                  reader->byte_order,
+                                  &next);
 
-  _dbus_verbose ("type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
-                 reader, reader->type_pos, reader->value_pos, next,
-                 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
 
-  _dbus_verbose_bytes_of_string (reader->value_str,
-                                 reader->value_pos,
-                                 MIN (16,
-                                      _dbus_string_get_length (reader->value_str) - reader->value_pos));
+      _dbus_verbose ("  type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
+                     reader, reader->type_pos, reader->value_pos, next,
+                     _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
+      
+      _dbus_verbose_bytes_of_string (reader->value_str,
+                                     reader->value_pos,
+                                     MIN (16,
+                                          _dbus_string_get_length (reader->value_str) - reader->value_pos));
+    }
+  else
+    {
+      _dbus_assert_not_reached ("reader->container_type should not be set to this");
+    }
 }
 
 dbus_bool_t
@@ -136,7 +194,17 @@ _dbus_type_reader_recurse (DBusTypeReader *reader,
 {
   int t;
 
-  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
+  /* FIXME are we recursing over the type signature or over the values.
+   * Arrays don't necessarily have values for each element of the type
+   * signature. Thus we get a mismatch where we need to "bail out" and
+   * return the signature of each element, but can't return an element
+   * or recurse into the element signature. Not sure how to handle this;
+   * maybe think about how we will handle variant types and do something
+   * similar since they also have the idea of a signature for the whole
+   * sub-item?
+   */
+  
+  t = first_type_in_signature (reader->type_str, reader->type_pos);
   
   /* point subreader at the same place as reader */
   _dbus_type_reader_init (sub,
@@ -146,17 +214,99 @@ _dbus_type_reader_recurse (DBusTypeReader *reader,
                           reader->value_str,
                           reader->value_pos);
 
-  _dbus_assert (t == DBUS_STRUCT_BEGIN_CHAR); /* only this works right now */
-  
-  sub->type_pos += 1;
+  if (t == DBUS_TYPE_STRUCT)
+    {
+      sub->container_type = DBUS_TYPE_STRUCT;
+      
+      sub->type_pos += 1;
+
+      /* struct has 8 byte alignment */
+      sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
+
+      sub->u.strct.finished = FALSE;
+    }
+  else if (t == DBUS_TYPE_ARRAY)
+    {
+      dbus_uint32_t array_len;
+      int alignment;
+
+      sub->container_type = DBUS_TYPE_ARRAY;
+      
+      /* point type_pos at the array element type */
+      sub->type_pos += 1;
+
+      sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
+      
+      _dbus_demarshal_basic_type (sub->value_str,
+                                  DBUS_TYPE_UINT32,
+                                  &array_len,
+                                  sub->byte_order,
+                                  &sub->value_pos);
+      
+      sub->u.array.len = array_len;
+      
+      alignment = element_type_get_alignment (sub->type_str,
+                                              sub->type_pos);
+      
+      sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
+
+      sub->u.array.element_type = first_type_in_signature (sub->type_str,
+                                                           sub->type_pos);
+      sub->u.array.start_pos = sub->value_pos;
 
-  /* no value_pos increment since the struct itself doesn't take up value space */
+      _dbus_verbose ("    type reader %p array start = %d array len = %d array element type = %s\n",
+                     reader,
+                     sub->u.array.start_pos,
+                     sub->u.array.len,
+                     _dbus_type_to_string (sub->u.array.element_type));
+    }
+  else
+    {
+      _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
+      if (t == DBUS_TYPE_INVALID)
+        _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
+      
+      _dbus_assert_not_reached ("don't yet handle recursing into this type");
+    }
 
-  _dbus_verbose ("type reader %p recursed type_pos = %d value_pos = %d remaining sig '%s'\n",
+  _dbus_verbose ("  type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
                  sub, sub->type_pos, sub->value_pos,
                  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
 }
 
+static void
+skip_one_complete_type (const DBusString *type_str,
+                        int              *type_pos)
+{
+  while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
+    *type_pos += 1;
+
+  if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
+    {
+      int depth;
+      depth = 1;
+      *type_pos += 1;
+      while (depth > 0)
+        {
+          switch (_dbus_string_get_byte (type_str, *type_pos))
+            {
+            case DBUS_STRUCT_BEGIN_CHAR:
+              depth += 1;
+              break;
+            case DBUS_STRUCT_END_CHAR:
+              depth -= 1;
+              break;
+            case DBUS_TYPE_INVALID:
+              _dbus_assert_not_reached ("unbalanced parens in signature");
+              break;
+            }
+          *type_pos += 1;
+        }
+    }
+  else
+    *type_pos += 1;
+}
+
 /**
  * Skip to the next value on this "level". e.g. the next field in a
  * struct, the next value in an array, the next key or value in a
@@ -169,65 +319,122 @@ dbus_bool_t
 _dbus_type_reader_next (DBusTypeReader *reader)
 {
   int t;
-
-  /* FIXME handled calling next when there's no next */
   
-  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
+  t = _dbus_type_reader_get_current_type (reader);
   
-  _dbus_verbose ("type reader %p next() { type_pos = %d value_pos = %d remaining sig '%s'\n",
+  _dbus_verbose ("  type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
                  reader, reader->type_pos, reader->value_pos,
-                 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
+                 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
+                 _dbus_type_to_string (t));
+
+  if (t == DBUS_TYPE_INVALID)
+    return FALSE;
   
-  switch (t)
+  if (reader->container_type == DBUS_TYPE_INVALID ||
+      reader->container_type == DBUS_TYPE_STRUCT)
     {
-    case DBUS_STRUCT_BEGIN_CHAR:
-      /* Scan forward over the entire container contents */
-      {
-        DBusTypeReader sub;
-
-        /* Recurse into the struct */
-        _dbus_type_reader_recurse (reader, &sub);
-
-        /* Skip everything in this subreader */
-        while (_dbus_type_reader_next (&sub))
+      switch (t)
+        {
+        case DBUS_TYPE_STRUCT:
+        case DBUS_TYPE_ARRAY:
+          /* Scan forward over the entire container contents */
+          /* FIXME this is super slow for arrays. We need to special
+           * case skipping all the elements at once instead of scanning.
+           */
           {
-            /* nothing */;
-          }
+            DBusTypeReader sub;
 
-        /* Now we are at the end of this container */
-        reader->type_pos = sub.type_pos;
-        reader->value_pos = sub.value_pos;
-      }
-      break;
+            /* Recurse into the struct */
+            _dbus_type_reader_recurse (reader, &sub);
 
-    default:
-      /* FIXME for array etc. this is more complicated */
-      _dbus_marshal_skip_basic_type (reader->value_str,
-                                     t, reader->byte_order,
-                                     &reader->value_pos);
-      reader->type_pos += 1;
-      break;
-    }
-
-  _dbus_verbose ("type reader %p }  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));
-
-  /* FIXME this is wrong; we need to return FALSE when we finish the
-   * container we've recursed into; even if the signature continues.
-   */
-  
-  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
+            /* Skip everything in this subreader */
+            while (_dbus_type_reader_next (&sub))
+              {
+                /* nothing */;
+              }
 
-  if (t == DBUS_STRUCT_END_CHAR)
+            /* Now we are at the end of this container */
+            reader->type_pos = sub.type_pos;
+            reader->value_pos = sub.value_pos;
+          }
+          break;
+
+        default:
+          _dbus_marshal_skip_basic_type (reader->value_str,
+                                         t, reader->byte_order,
+                                         &reader->value_pos);
+          reader->type_pos += 1;
+          break;
+        }
+
+      /* for STRUCT containers we return FALSE at the end of the struct,
+       * for INVALID we return FALSE at the end of the signature.
+       * In both cases we arrange for get_current_type() to return INVALID
+       * which is defined to happen iff we're at the end (no more next())
+       */
+      if (reader->container_type == DBUS_TYPE_STRUCT)
+        {
+          t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
+          if (t == DBUS_STRUCT_END_CHAR)
+            {
+              reader->type_pos += 1;
+              reader->u.strct.finished = TRUE;
+            }
+        }
+    }
+  else if (reader->container_type == DBUS_TYPE_ARRAY)
     {
-      reader->type_pos += 1;
-      return FALSE;
+      /* Skip one array element */
+      int end_pos;
+
+      end_pos = reader->u.array.start_pos + reader->u.array.len;
+
+      _dbus_assert (reader->value_pos < end_pos);
+      _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
+
+      if (reader->u.array.element_type == DBUS_TYPE_ARRAY ||
+          reader->u.array.element_type == DBUS_TYPE_STRUCT)
+        {
+          DBusTypeReader sub;
+          
+          /* Recurse into the array element */
+          _dbus_type_reader_recurse (reader, &sub);
+
+            /* Skip everything in this element */
+          while (_dbus_type_reader_next (&sub))
+            {
+              /* nothing */;
+            }
+
+          /* Now we are at the end of this element */
+          reader->value_pos = sub.value_pos;
+        }
+      else
+        {
+          _dbus_marshal_skip_basic_type (reader->value_str,
+                                         t, reader->byte_order,
+                                         &reader->value_pos);
+        }
+
+      _dbus_assert (reader->value_pos <= end_pos);
+      
+      if (reader->value_pos == end_pos)
+        {
+          skip_one_complete_type (reader->type_str,
+                                  &reader->type_pos);
+        }
+    }
+  else
+    {
+      _dbus_assert_not_reached ("reader->container_type should not be set to this");
     }
-  if (t == DBUS_TYPE_INVALID)
-    return FALSE;
   
-  return TRUE;
+  _dbus_verbose ("  type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
+                 reader, reader->type_pos, reader->value_pos,
+                 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
+                 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
+  
+  return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
 }
 
 void
@@ -244,6 +451,31 @@ _dbus_type_writer_init (DBusTypeWriter *writer,
   writer->value_str = value_str;
   writer->value_pos = value_pos;
   writer->container_type = DBUS_TYPE_INVALID;
+  writer->inside_array = FALSE;
+}
+
+static dbus_bool_t
+_dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
+                                           int             type,
+                                           const void     *value)
+{
+  int old_value_len;
+  int bytes_written;
+
+  old_value_len = _dbus_string_get_length (writer->value_str);
+        
+  if (!_dbus_marshal_basic_type (writer->value_str,
+                                 writer->value_pos,
+                                 type,
+                                 value,
+                                 writer->byte_order))
+    return FALSE;
+
+  bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
+  
+  writer->value_pos += bytes_written;
+
+  return TRUE;
 }
 
 dbus_bool_t
@@ -252,36 +484,33 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,
                                const void     *value)
 {
   dbus_bool_t retval;
-  int old_value_len;
-
-  old_value_len = _dbus_string_get_length (writer->value_str);
   
   /* First ensure that our type realloc will succeed */
   if (!_dbus_string_alloc_space (writer->type_str, 1))
     return FALSE;
 
   retval = FALSE;
-        
-  if (!_dbus_marshal_basic_type (writer->value_str,
-                                 writer->value_pos,
-                                 type,
-                                 value,
-                                 writer->byte_order))
-    goto out;
 
-  writer->value_pos += _dbus_string_get_length (writer->value_str) - old_value_len;
+  if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
+    goto out;
   
-  /* Now insert the type */
-  if (!_dbus_string_insert_byte (writer->type_str,
-                                 writer->type_pos,
-                                 type))
-    _dbus_assert_not_reached ("failed to insert byte after prealloc");
-
-  writer->type_pos += 1;
+  /* Now insert the type unless we're already covered by the array signature */
+  if (!writer->inside_array)
+    {
+      if (!_dbus_string_insert_byte (writer->type_str,
+                                     writer->type_pos,
+                                     type))
+        _dbus_assert_not_reached ("failed to insert byte after prealloc");
+      
+      writer->type_pos += 1;
+    }
   
   retval = TRUE;
   
  out:
+  _dbus_verbose ("  type writer %p basic type_pos = %d value_pos = %d inside_array = %d\n",
+                 writer, writer->type_pos, writer->value_pos, writer->inside_array);
+  
   return retval;
 }
 
@@ -295,10 +524,11 @@ _dbus_type_writer_write_array (DBusTypeWriter *writer,
 
 }
 
-dbus_bool_t
-_dbus_type_writer_recurse (DBusTypeWriter *writer,
-                           int             container_type,
-                           DBusTypeWriter *sub)
+static void
+writer_recurse_init_and_check (DBusTypeWriter *writer,
+                               int             container_type,
+                               const char     *array_element_type,
+                               DBusTypeWriter *sub)
 {
   _dbus_type_writer_init (sub,
                           writer->byte_order,
@@ -306,20 +536,113 @@ _dbus_type_writer_recurse (DBusTypeWriter *writer,
                           writer->type_pos,
                           writer->value_str,
                           writer->value_pos);
+  
   sub->container_type = container_type;
+
+  /* While inside an array, we never want to write to the type str.
+   * We are inside an array if we're currently recursing into one.
+   */
+  if (writer->inside_array || sub->container_type == DBUS_TYPE_ARRAY)
+    sub->inside_array = TRUE;
+  else
+    sub->inside_array = FALSE;
+
+  /* If our parent is an array, things are a little bit complicated.
+   *
+   * The parent must have a complete element type, such as
+   * "i" or "aai" or "(ii)" or "a(ii)". There can't be
+   * unclosed parens, or an "a" with no following type.
+   *
+   * To recurse, the only allowed operation is to recurse into the
+   * first type in the element type. So for "i" you can't recurse, for
+   * "ai" you can recurse into the array, for "(ii)" you can recurse
+   * into the struct.
+   *
+   * If you recurse into the array for "ai", then you must specify
+   * "i" for the element type of the array you recurse into.
+   * 
+   * While inside an array at any level, we need to avoid writing to
+   * type_str, since the type only appears once for the whole array,
+   * it does not appear for each array element.
+   */
+#ifndef DBUS_DISABLE_CHECKS
+  if (writer->container_type == DBUS_TYPE_ARRAY)
+    {
+      if ((sub->container_type == DBUS_TYPE_STRUCT &&
+           writer->u.array.element_type[0] != DBUS_STRUCT_BEGIN_CHAR) ||
+          (sub->container_type != DBUS_TYPE_STRUCT &&
+           writer->u.array.element_type[0] != sub->container_type))
+        {
+          _dbus_warn ("Recursing into an array with element type %s not allowed with container type %s\n",
+                      writer->u.array.element_type, _dbus_type_to_string (sub->container_type));
+        }
+
+      if (sub->container_type == DBUS_TYPE_ARRAY)
+        {
+          DBusString parent_elements;
+          DBusString our_elements;
+
+          _dbus_assert (writer->u.array.element_type[0] == DBUS_TYPE_ARRAY);
+          
+          _dbus_string_init_const (&parent_elements, &writer->u.array.element_type[1]);
+          _dbus_string_init_const (&our_elements, array_element_type);
+
+          if (!_dbus_string_equal (&parent_elements, &our_elements))
+            {
+              _dbus_warn ("Parent array expects elements '%s' and we are writing an array of '%s'\n",
+                          writer->u.array.element_type,
+                          array_element_type);
+            }
+        }
+    }
+#endif /* DBUS_DISABLE_CHECKS */
+
+  _dbus_verbose ("  type writer %p recurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
+                 writer, writer->type_pos, writer->value_pos, writer->inside_array,
+                 _dbus_type_to_string (writer->container_type));
+  _dbus_verbose ("  type writer %p new sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
+                 sub, sub->type_pos, sub->value_pos,
+                 sub->inside_array,
+                 _dbus_type_to_string (sub->container_type),
+                 array_element_type ? array_element_type : "n/a");
+}
+
+dbus_bool_t
+_dbus_type_writer_recurse (DBusTypeWriter *writer,
+                           int             container_type,
+                           DBusTypeWriter *sub)
+{
+  writer_recurse_init_and_check (writer, container_type, NULL, sub);
   
   switch (container_type)
     {
     case DBUS_TYPE_STRUCT:
       {
-        if (!_dbus_string_insert_byte (sub->type_str,
-                                       sub->type_pos,
-                                       DBUS_STRUCT_BEGIN_CHAR))
-          return FALSE;
+        if (!writer->inside_array)
+          {
+            /* Ensure that we'll be able to add alignment padding */
+            if (!_dbus_string_alloc_space (sub->value_str, 8))
+              return FALSE;
+            
+            if (!_dbus_string_insert_byte (sub->type_str,
+                                           sub->type_pos,
+                                           DBUS_STRUCT_BEGIN_CHAR))
+              return FALSE;
+
+            sub->type_pos += 1;
+          }
 
-        sub->type_pos += 1;
+        if (!_dbus_string_insert_bytes (sub->value_str,
+                                        sub->value_pos,
+                                        _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
+                                        '\0'))
+          _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
+        sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
       }
       break;
+    case DBUS_TYPE_ARRAY:
+      _dbus_assert_not_reached ("use recurse_array() for arrays");
+      break;
     default:
       _dbus_assert_not_reached ("container_type unhandled");
       break;
@@ -329,18 +652,130 @@ _dbus_type_writer_recurse (DBusTypeWriter *writer,
 }
 
 dbus_bool_t
+_dbus_type_writer_recurse_array (DBusTypeWriter *writer,
+                                 const char     *element_type,
+                                 DBusTypeWriter *sub)
+{
+  int element_type_len;
+  DBusString element_type_str;
+  
+  writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, element_type, sub);
+
+  _dbus_string_init_const (&element_type_str, element_type);
+  element_type_len = _dbus_string_get_length (&element_type_str);
+
+  /* 4 bytes for the array length and 4 bytes possible padding */
+  if (!_dbus_string_alloc_space (sub->value_str, 8))
+    return FALSE;
+
+  if (!writer->inside_array)
+    {
+      /* alloc space for array typecode, element signature, possible 7
+       * bytes of padding
+       */
+      if (!_dbus_string_alloc_space (sub->type_str, 1 + element_type_len + 7))
+        return FALSE;
+    }
+      
+  if (!_dbus_string_copy_data (&element_type_str,
+                               &sub->u.array.element_type))
+    return FALSE;
+
+  if (!writer->inside_array)
+    {
+      if (!_dbus_string_insert_byte (sub->type_str,
+                                     sub->type_pos,
+                                     DBUS_TYPE_ARRAY))
+        _dbus_assert_not_reached ("should not have failed to insert array typecode");
+
+      sub->type_pos += 1;
+      
+      if (!_dbus_string_copy (&element_type_str, 0,
+                              sub->type_str, sub->type_pos))
+        _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
+  
+      sub->type_pos += element_type_len;
+    }
+  
+  sub->u.array.len_pos = sub->value_pos;
+
+  {
+    dbus_uint32_t value = 0;
+    int alignment;
+    int aligned;
+    DBusString str;
+    
+    if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
+                                                    &value))
+      _dbus_assert_not_reached ("should not have failed to insert array len");
+
+    _dbus_string_init_const (&str, element_type);
+    alignment = element_type_get_alignment (&str, 0);
+
+    aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
+    if (aligned != sub->value_pos)
+      {
+        if (!_dbus_string_insert_bytes (sub->value_str,
+                                        sub->value_pos,
+                                        aligned - sub->value_pos,
+                                        '\0'))
+          _dbus_assert_not_reached ("should not have failed to insert alignment padding");
+
+        sub->value_pos = aligned;
+      }
+    sub->u.array.start_pos = sub->value_pos;
+  }
+
+  _dbus_assert (sub->u.array.start_pos == sub->value_pos);
+  _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
+  
+  /* value_pos now points to the place for array data, and len_pos to the length */
+
+  return TRUE;
+}
+
+dbus_bool_t
 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
                              DBusTypeWriter *sub)
 {
   _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
 
+  _dbus_verbose ("  type writer %p unrecurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
+                 writer, writer->type_pos, writer->value_pos, writer->inside_array,
+                 _dbus_type_to_string (writer->container_type));
+  _dbus_verbose ("  type writer %p unrecurse sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
+                 sub, sub->type_pos, sub->value_pos,
+                 sub->inside_array,
+                 _dbus_type_to_string (sub->container_type),
+                 sub->container_type == DBUS_TYPE_ARRAY ?
+                 sub->u.array.element_type : "n/a");
+  
   if (sub->container_type == DBUS_TYPE_STRUCT)
     {
-      if (!_dbus_string_insert_byte (sub->type_str,
-                                     sub->type_pos, 
-                                     DBUS_STRUCT_END_CHAR))
-        return FALSE;
-      sub->type_pos += 1;
+      if (!sub->inside_array)
+        {
+          if (!_dbus_string_insert_byte (sub->type_str,
+                                         sub->type_pos, 
+                                         DBUS_STRUCT_END_CHAR))
+            return FALSE;
+          sub->type_pos += 1;
+        }
+    }
+  else if (sub->container_type == DBUS_TYPE_ARRAY)
+    {
+      dbus_uint32_t len;
+      
+      dbus_free (sub->u.array.element_type);
+      sub->u.array.element_type = NULL;
+
+      /* Set the array length */
+      len = sub->value_pos - sub->u.array.start_pos;
+      _dbus_marshal_set_uint32 (sub->value_str,
+                                sub->byte_order,
+                                sub->u.array.len_pos,
+                                len);
+      _dbus_verbose ("    filled in sub array len to %u at len_pos %d\n",
+                     len, sub->u.array.len_pos);
     }
 
   /* Jump the parent writer to the new location */
@@ -672,12 +1107,325 @@ read_struct_of_structs_of_structs (DataBlock      *block,
   return TRUE;
 }
 
+static dbus_bool_t
+write_array_of_int32 (DataBlock      *block,
+                      DBusTypeWriter *writer)
+{
+  dbus_int32_t v;
+  DataBlockState saved;
+  DBusTypeWriter sub;
+
+  data_block_save (block, &saved);
+  
+  if (!_dbus_type_writer_recurse_array (writer,
+                                        DBUS_TYPE_INT32_AS_STRING,
+                                        &sub))
+    return FALSE;
+
+  v = SAMPLE_INT32_ALTERNATE;
+  if (!_dbus_type_writer_write_basic (&sub,
+                                      DBUS_TYPE_INT32,
+                                      &v))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  v = SAMPLE_INT32;
+  if (!_dbus_type_writer_write_basic (&sub,
+                                      DBUS_TYPE_INT32,
+                                      &v))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  v = SAMPLE_INT32;
+  if (!_dbus_type_writer_write_basic (&sub,
+                                      DBUS_TYPE_INT32,
+                                      &v))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+read_array_of_int32 (DataBlock      *block,
+                     DBusTypeReader *reader)
+{
+  dbus_int32_t v;
+  DBusTypeReader sub;
+
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+  
+  _dbus_type_reader_recurse (reader, &sub);
+
+  check_expected_type (&sub, DBUS_TYPE_INT32);
+  
+  _dbus_type_reader_read_basic (&sub,
+                                (dbus_int32_t*) &v);
+
+  _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
+
+  _dbus_type_reader_next (&sub);
+  check_expected_type (&sub, DBUS_TYPE_INT32);
+  
+  _dbus_type_reader_read_basic (&sub,
+                                (dbus_int32_t*) &v);
+
+  _dbus_assert (v == SAMPLE_INT32);
+
+  _dbus_type_reader_next (&sub);
+  check_expected_type (&sub, DBUS_TYPE_INT32);
+  
+  _dbus_type_reader_read_basic (&sub,
+                                (dbus_int32_t*) &v);
+
+  _dbus_assert (v == SAMPLE_INT32);
+  
+  return TRUE;
+}
+
+
+static dbus_bool_t
+write_array_of_int32_empty (DataBlock      *block,
+                            DBusTypeWriter *writer)
+{
+  DataBlockState saved;
+  DBusTypeWriter sub;
+
+  data_block_save (block, &saved);
+  
+  if (!_dbus_type_writer_recurse_array (writer,
+                                        DBUS_TYPE_INT32_AS_STRING,
+                                        &sub))
+    return FALSE;
+  
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+read_array_of_int32_empty (DataBlock      *block,
+                           DBusTypeReader *reader)
+{
+  DBusTypeReader sub;
+
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+  
+  _dbus_type_reader_recurse (reader, &sub);
+
+  check_expected_type (&sub, DBUS_TYPE_INVALID);
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+write_array_of_array_of_int32 (DataBlock      *block,
+                               DBusTypeWriter *writer)
+{
+  DataBlockState saved;
+  DBusTypeWriter sub;
+
+  data_block_save (block, &saved);
+  
+  if (!_dbus_type_writer_recurse_array (writer,
+                                        DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+                                        &sub))
+    return FALSE;
+
+  if (!write_array_of_int32 (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  if (!write_array_of_int32 (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  if (!write_array_of_int32_empty (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  if (!write_array_of_int32 (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+read_array_of_array_of_int32 (DataBlock      *block,
+                              DBusTypeReader *reader)
+{
+  DBusTypeReader sub;
+  
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+  
+  _dbus_type_reader_recurse (reader, &sub);
+
+  if (!read_array_of_int32 (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  if (!read_array_of_int32 (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  if (!read_array_of_int32_empty (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  if (!read_array_of_int32 (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  
+  return TRUE;
+}
+
+
+static dbus_bool_t
+write_array_of_array_of_int32_empty (DataBlock      *block,
+                                     DBusTypeWriter *writer)
+{
+  DataBlockState saved;
+  DBusTypeWriter sub;
+
+  data_block_save (block, &saved);
+  
+  if (!_dbus_type_writer_recurse_array (writer,
+                                        DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+                                        &sub))
+    return FALSE;
+
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+read_array_of_array_of_int32_empty (DataBlock      *block,
+                                    DBusTypeReader *reader)
+{
+  DBusTypeReader sub;
+  DBusTypeReader sub2;
+  
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+  
+  _dbus_type_reader_recurse (reader, &sub);
+
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+
+  _dbus_type_reader_recurse (&sub, &sub2);
+
+  check_expected_type (reader, DBUS_TYPE_INVALID);
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+write_array_of_array_of_array_of_int32 (DataBlock      *block,
+                                        DBusTypeWriter *writer)
+{
+  DataBlockState saved;
+  DBusTypeWriter sub;
+
+  data_block_save (block, &saved);
+  
+  if (!_dbus_type_writer_recurse_array (writer,
+                                        DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
+                                        &sub))
+    return FALSE;
+
+  if (!write_array_of_array_of_int32 (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  if (!write_array_of_array_of_int32 (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+
+  if (!write_array_of_array_of_int32_empty (block, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    {
+      data_block_restore (block, &saved);
+      return FALSE;
+    }
+  
+  return TRUE;
+}
+
+static dbus_bool_t
+read_array_of_array_of_array_of_int32 (DataBlock      *block,
+                                       DBusTypeReader *reader)
+{
+  DBusTypeReader sub;
+  
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+  
+  _dbus_type_reader_recurse (reader, &sub);
+
+  if (!read_array_of_array_of_int32 (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  if (!read_array_of_array_of_int32 (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  if (!read_array_of_array_of_int32_empty (block, &sub))
+    return FALSE;
+  _dbus_type_reader_next (&sub);
+  
+  return TRUE;
+}
+
 typedef enum {
   ITEM_INVALID = -1,
   ITEM_INT32 = 0,
   ITEM_STRUCT_WITH_INT32S,
   ITEM_STRUCT_OF_STRUCTS,
   ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
+  ITEM_ARRAY_OF_INT32,
+  ITEM_ARRAY_OF_INT32_EMPTY,
+  ITEM_ARRAY_OF_ARRAY_OF_INT32,
+  ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
+  ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
   ITEM_LAST
 } WhichItem;
 
@@ -705,12 +1453,25 @@ static CheckMarshalItem items[] = {
   { "struct of two structs of three structs of two int32",
     ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
     write_struct_of_structs_of_structs,
-    read_struct_of_structs_of_structs }
+    read_struct_of_structs_of_structs },
+  { "array of int32",
+    ITEM_ARRAY_OF_INT32, write_array_of_int32, read_array_of_int32 },
+  { "empty array of int32",
+    ITEM_ARRAY_OF_INT32_EMPTY, write_array_of_int32_empty, read_array_of_int32_empty },
+  { "array of array of int32",
+    ITEM_ARRAY_OF_ARRAY_OF_INT32,
+    write_array_of_array_of_int32, read_array_of_array_of_int32 },
+  { "empty array of array of int32",
+    ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
+    write_array_of_array_of_int32_empty, read_array_of_array_of_int32_empty },
+  { "array of array of array of int32",
+    ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
+    write_array_of_array_of_array_of_int32, read_array_of_array_of_array_of_int32 }
 };
 
 typedef struct
 {
-  /* Array of items in the above items[]; -1 terminated */
+  /* Array of items from the above items[]; -1 terminated */
   int items[20];
 } TestRun;
 
@@ -743,7 +1504,44 @@ static TestRun runs[] = {
   { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
   { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
   { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
-  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }
+  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+
+  /* ARRAY_OF_INT32 */
+  { { ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
+
+  /* ARRAY_OF_ARRAY_OF_INT32 */
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+
+  /* ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32 */
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
+  { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
+  { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } }
+
   
 };
 
@@ -760,6 +1558,20 @@ perform_one_run (DataBlock *block,
 
   retval = FALSE;
 
+  {
+    _dbus_verbose ("run byteorder %s items ",
+                   byte_order == DBUS_LITTLE_ENDIAN ? "little" : "big");
+    i = 0;
+    while (run->items[i] != ITEM_INVALID)
+      {
+        CheckMarshalItem *item = &items[run->items[i]];
+        
+        _dbus_verbose ("%s ", item->desc);
+        ++i;
+      }
+    _dbus_verbose (" = %d items\n", i);
+  }
+  
   data_block_save (block, &saved);
   
   data_block_init_reader_writer (block, 
@@ -771,7 +1583,7 @@ perform_one_run (DataBlock *block,
     {
       CheckMarshalItem *item = &items[run->items[i]];
 
-      _dbus_verbose ("writing %s\n", item->desc);
+      _dbus_verbose (">>writing %s\n", item->desc);
       
       if (!(* item->write_item_func) (block, &writer))
         goto out;
@@ -783,7 +1595,7 @@ perform_one_run (DataBlock *block,
     {
       CheckMarshalItem *item = &items[run->items[i]];
 
-      _dbus_verbose ("reading %s\n", item->desc);
+      _dbus_verbose (">>reading %s\n", item->desc);
       
       if (!(* item->read_item_func) (block, &reader))
         goto out;
index ed70a82..57b55fc 100644 (file)
@@ -56,6 +56,26 @@ struct DBusTypeReader
   int type_pos;
   const DBusString *value_str;
   int value_pos;
+
+  /* Hmm - it might be cleaner to do TypeReaderClass *vtable for container type */
+  int container_type;
+  union
+  {
+    struct {
+      int start_pos;
+      dbus_uint32_t len;
+      int element_type;
+    } array;
+
+    struct {
+      int len_pos;
+
+    } dict;
+
+    struct {
+      dbus_uint32_t finished : 1;
+    } strct;
+  } u;
 };
 
 typedef struct DBusTypeReader DBusTypeReader;
@@ -67,7 +87,23 @@ struct DBusTypeWriter
   int type_pos;
   DBusString *value_str;
   int value_pos;
+
+  dbus_uint32_t inside_array : 1;
+
   int container_type;
+  union
+  {
+    struct {
+      int start_pos; /* first element */
+      int len_pos;
+      char *element_type;
+    } array;
+
+    struct {
+      int len_pos;
+
+    } dict;
+  } u;
 };
 
 typedef struct DBusTypeWriter DBusTypeWriter;
@@ -79,7 +115,7 @@ void        _dbus_type_reader_init                (DBusTypeReader    *reader,
                                                    const DBusString  *value_str,
                                                    int                value_pos);
 int         _dbus_type_reader_get_current_type    (DBusTypeReader    *reader);
-int         _dbus_type_reader_get_array_type      (DBusTypeReader    *reader);
+int         _dbus_type_reader_get_array_length    (DBusTypeReader    *reader);
 void        _dbus_type_reader_read_basic          (DBusTypeReader    *reader,
                                                    void              *value);
 dbus_bool_t _dbus_type_reader_read_array_of_basic (DBusTypeReader    *reader,
@@ -90,23 +126,27 @@ void        _dbus_type_reader_recurse             (DBusTypeReader    *reader,
                                                    DBusTypeReader    *subreader);
 dbus_bool_t _dbus_type_reader_next                (DBusTypeReader    *reader);
 
-void        _dbus_type_writer_init        (DBusTypeWriter *writer,
-                                           int             byte_order,
-                                           DBusString     *type_str,
-                                           int             type_pos,
-                                           DBusString     *value_str,
-                                           int             value_pos);
-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_recurse     (DBusTypeWriter *writer,
-                                           int             container_type,
-                                           DBusTypeWriter *sub);
-dbus_bool_t _dbus_type_writer_unrecurse   (DBusTypeWriter *writer,
-                                           DBusTypeWriter *sub);
+void        _dbus_type_writer_init          (DBusTypeWriter *writer,
+                                             int             byte_order,
+                                             DBusString     *type_str,
+                                             int             type_pos,
+                                             DBusString     *value_str,
+                                             int             value_pos);
+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_recurse       (DBusTypeWriter *writer,
+                                             int             container_type,
+                                             DBusTypeWriter *sub);
+dbus_bool_t _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
+                                             const char     *element_type,
+                                             DBusTypeWriter *sub);
+dbus_bool_t _dbus_type_writer_unrecurse     (DBusTypeWriter *writer,
+                                             DBusTypeWriter *sub);
+
 
 #endif /* DBUS_MARSHAL_RECURSIVE_H */
index 9d8c4b6..93cc566 100644 (file)
@@ -42,36 +42,52 @@ extern "C" {
 
 /* Never a legitimate type */
 #define DBUS_TYPE_INVALID       ((int) '\0')
+#define DBUS_TYPE_INVALID_AS_STRING        "\0"
 
 /* Primitive types */
 #define DBUS_TYPE_BYTE          ((int) 'y')
+#define DBUS_TYPE_BYTE_AS_STRING           "y"
 #define DBUS_TYPE_BOOLEAN       ((int) 'b')
+#define DBUS_TYPE_BOOLEAN_AS_STRING        "b"
 #define DBUS_TYPE_INT32         ((int) 'i')
+#define DBUS_TYPE_INT32_AS_STRING          "i"
 
 #define DBUS_TYPE_UINT32        ((int) 'u')
+#define DBUS_TYPE_UINT32_AS_STRING         "u"
 #define DBUS_TYPE_INT64         ((int) 'x')
+#define DBUS_TYPE_INT64_AS_STRING          "x"
 #define DBUS_TYPE_UINT64        ((int) 't')
+#define DBUS_TYPE_UINT64_AS_STRING         "t"
 
 #define DBUS_TYPE_DOUBLE        ((int) 'd')
+#define DBUS_TYPE_DOUBLE_AS_STRING         "d"
 #define DBUS_TYPE_STRING        ((int) 's')
+#define DBUS_TYPE_STRING_AS_STRING         "s"
 #define DBUS_TYPE_OBJECT_PATH   ((int) 'o')
+#define DBUS_TYPE_OBJECT_PATH_AS_STRING    "o"
 
 /* Compound types */
 #define DBUS_TYPE_ARRAY         ((int) 'a')
+#define DBUS_TYPE_ARRAY_AS_STRING          "a"
 #define DBUS_TYPE_DICT          ((int) 'm') /* not parameterized; always map<string,variant> */
+#define DBUS_TYPE_DICT_AS_STRING           "m"
 #define DBUS_TYPE_VARIANT       ((int) 'v')
+#define DBUS_TYPE_VARIANT_AS_STRING        "v"
 
 /* STRUCT is sort of special since its code can't appear in a type string,
  * instead DBUS_STRUCT_BEGIN_CHAR has to appear
  */
 #define DBUS_TYPE_STRUCT        ((int) 'r')
+#define DBUS_TYPE_STRUCT_AS_STRING         "r"
 
 /* Does not count INVALID */
 #define DBUS_NUMBER_OF_TYPES    (13)
 
 /* characters other than typecodes that appear in type signatures */
 #define DBUS_STRUCT_BEGIN_CHAR   ((int) '(')
+#define DBUS_STRUCT_BEGIN_CHAR_AS_STRING   "("
 #define DBUS_STRUCT_END_CHAR     ((int) ')')
+#define DBUS_STRUCT_END_CHAR_AS_STRING     ")"
 
 /* Max length in bytes of a service or interface or member name */
 #define DBUS_MAXIMUM_NAME_LENGTH 256