2005-01-28 Havoc Pennington <hp@redhat.com>
authorHavoc Pennington <hp@redhat.com>
Fri, 28 Jan 2005 05:30:53 +0000 (05:30 +0000)
committerHavoc Pennington <hp@redhat.com>
Fri, 28 Jan 2005 05:30:53 +0000 (05:30 +0000)
* doc/dbus-specification.xml: update to describe 16-bit types and
dict entries

* dbus/dbus-marshal-basic.c (_dbus_unpack_uint16): fix broken
assertion

* dbus/dbus-protocol.h (DBUS_TYPE_DICT_ENTRY): add DICT_ENTRY as a
type

* dbus/dbus-marshal-recursive.c: implement

ChangeLog
dbus/dbus-marshal-basic.c
dbus/dbus-marshal-byteswap.c
dbus/dbus-marshal-recursive-util.c
dbus/dbus-marshal-recursive.c
dbus/dbus-marshal-validate.c
dbus/dbus-marshal-validate.h
dbus/dbus-message.c
dbus/dbus-protocol.h
doc/TODO
doc/dbus-specification.xml

index 137ebe2..5d948f1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2005-01-28  Havoc Pennington  <hp@redhat.com>
+
+       * doc/dbus-specification.xml: update to describe 16-bit types and
+       dict entries
+
+       * dbus/dbus-marshal-basic.c (_dbus_unpack_uint16): fix broken
+       assertion
+
+       * dbus/dbus-protocol.h (DBUS_TYPE_DICT_ENTRY): add DICT_ENTRY as a
+       type
+
+       * dbus/dbus-marshal-recursive.c: implement
+
 2005-01-27  Havoc Pennington  <hp@redhat.com>
 
        * dbus/dbus-arch-deps.h.in: add 16/32-bit types
index e4f6720..84a9cca 100644 (file)
@@ -172,7 +172,7 @@ dbus_uint16_t
 _dbus_unpack_uint16 (int                  byte_order,
                      const unsigned char *data)
 {
-  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 2) == data);
 
   if (byte_order == DBUS_LITTLE_ENDIAN)
     return DBUS_UINT16_FROM_LE (*(dbus_uint16_t*)data);
@@ -1245,8 +1245,10 @@ _dbus_type_get_alignment (int typecode)
        * and it's simpler to just always align structs to 8;
        * we want the amount of padding in a struct of a given
        * type to be predictable, not location-dependent.
+       * DICT_ENTRY is always the same as struct.
        */
     case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
       return 8;
 
     default:
@@ -1283,6 +1285,7 @@ _dbus_type_is_valid (int typecode)
     case DBUS_TYPE_SIGNATURE:
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
     case DBUS_TYPE_VARIANT:
       return TRUE;
 
@@ -1294,6 +1297,7 @@ _dbus_type_is_valid (int typecode)
 /** macro that checks whether a typecode is a container type */
 #define TYPE_IS_CONTAINER(typecode)             \
     ((typecode) == DBUS_TYPE_STRUCT ||          \
+     (typecode) == DBUS_TYPE_DICT_ENTRY ||      \
      (typecode) == DBUS_TYPE_VARIANT ||         \
      (typecode) == DBUS_TYPE_ARRAY)
 
@@ -1403,6 +1407,8 @@ _dbus_type_to_string (int typecode)
       return "signature";
     case DBUS_TYPE_STRUCT:
       return "struct";
+    case DBUS_TYPE_DICT_ENTRY:
+      return "dict_entry";
     case DBUS_TYPE_ARRAY:
       return "array";
     case DBUS_TYPE_VARIANT:
@@ -1411,6 +1417,10 @@ _dbus_type_to_string (int typecode)
       return "begin_struct";
     case DBUS_STRUCT_END_CHAR:
       return "end_struct";
+    case DBUS_DICT_ENTRY_BEGIN_CHAR:
+      return "begin_dict_entry";
+    case DBUS_DICT_ENTRY_END_CHAR:
+      return "end_dict_entry";
     default:
       return "unknown";
     }
@@ -1559,8 +1569,14 @@ _dbus_first_type_in_signature (const DBusString *str,
 
   if (t == DBUS_STRUCT_BEGIN_CHAR)
     return DBUS_TYPE_STRUCT;
+  else if (t == DBUS_DICT_ENTRY_BEGIN_CHAR)
+    return DBUS_TYPE_DICT_ENTRY;
   else
-    return t;
+    {
+      _dbus_assert (t != DBUS_STRUCT_END_CHAR);
+      _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
+      return t;
+    }
 }
 
 /** @} */
index 7670ec4..c8ec894 100644 (file)
@@ -175,6 +175,7 @@ byteswap_body_helper (DBusTypeReader       *reader,
           break;
 
         case DBUS_TYPE_STRUCT:
+        case DBUS_TYPE_DICT_ENTRY:
           {
             DBusTypeReader sub;
 
index c607b04..6e8af18 100644 (file)
@@ -526,6 +526,19 @@ static dbus_bool_t struct_set_value        (TestTypeNode   *node,
                                             int             seed);
 static dbus_bool_t struct_build_signature  (TestTypeNode   *node,
                                             DBusString     *str);
+static dbus_bool_t dict_write_value        (TestTypeNode   *node,
+                                            DataBlock      *block,
+                                            DBusTypeWriter *writer,
+                                            int             seed);
+static dbus_bool_t dict_read_value         (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            int             seed);
+static dbus_bool_t dict_set_value          (TestTypeNode   *node,
+                                            DBusTypeReader *reader,
+                                            DBusTypeReader *realign_root,
+                                            int             seed);
+static dbus_bool_t dict_build_signature    (TestTypeNode   *node,
+                                            DBusString     *str);
 static dbus_bool_t array_write_value       (TestTypeNode   *node,
                                             DataBlock      *block,
                                             DBusTypeWriter *writer,
@@ -553,6 +566,7 @@ static dbus_bool_t variant_set_value       (TestTypeNode   *node,
 static void        container_destroy       (TestTypeNode   *node);
 
 
+
 static const TestTypeNodeClass int16_class = {
   DBUS_TYPE_INT16,
   sizeof (TestTypeNode),
@@ -793,6 +807,20 @@ static const TestTypeNodeClass struct_2_class = {
   NULL
 };
 
+static const TestTypeNodeClass dict_1_class = {
+  DBUS_TYPE_ARRAY, /* this is correct, a dict is an array of dict entry */
+  sizeof (TestTypeNodeContainer),
+  1, /* number of entries */
+  NULL,
+  container_destroy,
+  dict_write_value,
+  dict_read_value,
+  dict_set_value,
+  dict_build_signature,
+  NULL,
+  NULL
+};
+
 static dbus_bool_t arrays_write_fixed_in_blocks = FALSE;
 
 static const TestTypeNodeClass array_0_class = {
@@ -892,7 +920,8 @@ container_nodes[] = {
   &struct_2_class,
   &array_0_class,
   &array_2_class,
-  &variant_class
+  &variant_class,
+  &dict_1_class /* last since we want struct and array before it */
   /* array_9_class is omitted on purpose, it's too slow;
    * we only use it in one hardcoded test below
    */
@@ -2157,8 +2186,8 @@ int16_read_multi (TestTypeNode   *node,
   _dbus_assert (n_elements == count);
 
   for (i = 0; i < count; i++)
-    _dbus_assert (((int)_dbus_unpack_uint16 (reader->byte_order,
-                                             (const unsigned char*)values + (i * 2))) ==
+    _dbus_assert (((dbus_int16_t)_dbus_unpack_uint16 (reader->byte_order,
+                                                      (const unsigned char*)values + (i * 2))) ==
                   int16_from_seed (seed + i));
 
   return TRUE;
@@ -3298,6 +3327,233 @@ variant_set_value (TestTypeNode   *node,
   return variant_read_or_set_value (node, reader, realign_root, seed);
 }
 
+static dbus_bool_t
+dict_write_value (TestTypeNode   *node,
+                  DataBlock      *block,
+                  DBusTypeWriter *writer,
+                  int             seed)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  DataBlockState saved;
+  DBusTypeWriter sub;
+  DBusString entry_value_signature;
+  DBusString dict_entry_signature;
+  int i;
+  int n_entries;
+  int entry_value_type;
+  TestTypeNode *child;
+
+  n_entries = node->klass->subclass_detail;
+
+  _dbus_assert (container->children != NULL);
+
+  data_block_save (block, &saved);
+
+  if (!_dbus_string_init (&entry_value_signature))
+    return FALSE;
+
+  if (!_dbus_string_init (&dict_entry_signature))
+    {
+      _dbus_string_free (&entry_value_signature);
+      return FALSE;
+    }
+  
+  child = _dbus_list_get_first (&container->children);
+
+  if (!node_build_signature (child,
+                             &entry_value_signature))
+    goto oom;
+
+  if (!_dbus_string_append (&dict_entry_signature,
+                            DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                            DBUS_TYPE_INT32_AS_STRING))
+    goto oom;
+
+  if (!_dbus_string_copy (&entry_value_signature, 0,
+                          &dict_entry_signature,
+                          _dbus_string_get_length (&dict_entry_signature)))
+    goto oom;
+
+  if (!_dbus_string_append_byte (&dict_entry_signature,
+                                 DBUS_DICT_ENTRY_END_CHAR))
+    goto oom;
+  
+  entry_value_type = _dbus_first_type_in_signature (&entry_value_signature, 0);
+  
+  if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
+                                  &dict_entry_signature, 0,
+                                  &sub))
+    goto oom;
+
+  i = 0;
+  while (i < n_entries)
+    {
+      DBusTypeWriter entry_sub;
+      dbus_int32_t key;
+
+      if (!_dbus_type_writer_recurse (&sub, DBUS_TYPE_DICT_ENTRY,
+                                      NULL, 0,
+                                      &entry_sub))
+        goto oom;
+
+      key = int32_from_seed (seed + i);
+
+      if (!_dbus_type_writer_write_basic (&entry_sub,
+                                          DBUS_TYPE_INT32,
+                                          &key))
+        goto oom;
+      
+      if (!node_write_value (child, block, &entry_sub, seed + i))
+        goto oom;
+
+      if (!_dbus_type_writer_unrecurse (&sub, &entry_sub))
+        goto oom;
+      
+      ++i;
+    }
+
+  if (!_dbus_type_writer_unrecurse (writer, &sub))
+    goto oom;
+  
+  _dbus_string_free (&entry_value_signature);
+  _dbus_string_free (&dict_entry_signature);
+  return TRUE;
+
+ oom:
+  data_block_restore (block, &saved);
+  _dbus_string_free (&entry_value_signature);
+  _dbus_string_free (&dict_entry_signature);
+  return FALSE;
+}
+
+static dbus_bool_t
+dict_read_or_set_value (TestTypeNode   *node,
+                        DBusTypeReader *reader,
+                        DBusTypeReader *realign_root,
+                        int             seed)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  DBusTypeReader sub;
+  int i;
+  int n_entries;
+  TestTypeNode *child;
+
+  n_entries = node->klass->subclass_detail;
+
+  check_expected_type (reader, DBUS_TYPE_ARRAY);
+
+  child = _dbus_list_get_first (&container->children);
+
+  if (n_entries > 0)
+    {
+      _dbus_type_reader_recurse (reader, &sub);
+
+      check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY);
+      
+      i = 0;
+      while (i < n_entries)
+        {
+          DBusTypeReader entry_sub;
+
+          check_expected_type (&sub, DBUS_TYPE_DICT_ENTRY);
+          
+          _dbus_type_reader_recurse (&sub, &entry_sub);
+          
+          if (realign_root == NULL)
+            {
+              dbus_int32_t v;
+              
+              check_expected_type (&entry_sub, DBUS_TYPE_INT32);
+
+              _dbus_type_reader_read_basic (&entry_sub,
+                                            (dbus_int32_t*) &v);
+
+              _dbus_assert (v == int32_from_seed (seed + i));
+
+              NEXT_EXPECTING_TRUE (&entry_sub);
+              
+              if (!node_read_value (child, &entry_sub, seed + i))
+                return FALSE;
+
+              NEXT_EXPECTING_FALSE (&entry_sub);
+            }
+          else
+            {
+              dbus_int32_t v;
+              
+              v = int32_from_seed (seed + i);
+              
+              if (!_dbus_type_reader_set_basic (&entry_sub,
+                                                &v,
+                                                realign_root))
+                return FALSE;
+
+              NEXT_EXPECTING_TRUE (&entry_sub);
+              
+              if (!node_set_value (child, &entry_sub, realign_root, seed + i))
+                return FALSE;
+
+              NEXT_EXPECTING_FALSE (&entry_sub);
+            }
+          
+          if (i == (n_entries - 1))
+            NEXT_EXPECTING_FALSE (&sub);
+          else
+            NEXT_EXPECTING_TRUE (&sub);
+
+          ++i;
+        }
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+dict_read_value (TestTypeNode   *node,
+                 DBusTypeReader *reader,
+                 int             seed)
+{
+  return dict_read_or_set_value (node, reader, NULL, seed);
+}
+
+static dbus_bool_t
+dict_set_value (TestTypeNode   *node,
+                DBusTypeReader *reader,
+                DBusTypeReader *realign_root,
+                int             seed)
+{
+  return dict_read_or_set_value (node, reader, realign_root, seed);
+}
+
+static dbus_bool_t
+dict_build_signature (TestTypeNode   *node,
+                      DBusString     *str)
+{
+  TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
+  int orig_len;
+
+  orig_len = _dbus_string_get_length (str);
+
+  if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
+    goto oom;
+
+  if (!_dbus_string_append (str, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_INT32_AS_STRING))
+    goto oom;
+  
+  if (!node_build_signature (_dbus_list_get_first (&container->children),
+                             str))
+    goto oom;
+
+  if (!_dbus_string_append_byte (str, DBUS_DICT_ENTRY_END_CHAR))
+    goto oom;
+
+  return TRUE;
+
+ oom:
+  _dbus_string_set_length (str, orig_len);
+  return FALSE;
+}
+
 static void
 container_destroy (TestTypeNode *node)
 {
index 09bf174..738edd9 100644 (file)
@@ -159,24 +159,26 @@ base_reader_recurse (DBusTypeReader *sub,
 }
 
 static void
-struct_types_only_reader_recurse (DBusTypeReader *sub,
-                                  DBusTypeReader *parent)
+struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub,
+                                                DBusTypeReader *parent)
 {
   base_reader_recurse (sub, parent);
-
+  
   _dbus_assert (_dbus_string_get_byte (sub->type_str,
-                                       sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
+                                       sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR ||
+                _dbus_string_get_byte (sub->type_str,
+                                       sub->type_pos) == DBUS_DICT_ENTRY_BEGIN_CHAR);
 
   sub->type_pos += 1;
 }
 
 static void
-struct_reader_recurse (DBusTypeReader *sub,
-                       DBusTypeReader *parent)
+struct_or_dict_entry_reader_recurse (DBusTypeReader *sub,
+                                     DBusTypeReader *parent)
 {
-  struct_types_only_reader_recurse (sub, parent);
+  struct_or_dict_entry_types_only_reader_recurse (sub, parent);
 
-  /* struct has 8 byte alignment */
+  /* struct and dict entry have 8 byte alignment */
   sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
 }
 
@@ -321,11 +323,13 @@ skip_one_complete_type (const DBusString *type_str,
   p = start + *type_pos;
 
   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
+  _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
   
   while (*p == DBUS_TYPE_ARRAY)
     ++p;
 
   _dbus_assert (*p != DBUS_STRUCT_END_CHAR);
+  _dbus_assert (*p != DBUS_DICT_ENTRY_END_CHAR);
   
   if (*p == DBUS_STRUCT_BEGIN_CHAR)
     {
@@ -354,6 +358,33 @@ skip_one_complete_type (const DBusString *type_str,
             }
         }
     }
+  else if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
+    {
+      int depth;
+
+      depth = 1;
+
+      while (TRUE)
+        {
+          _dbus_assert (*p != DBUS_TYPE_INVALID);
+
+          ++p;
+
+          _dbus_assert (*p != DBUS_TYPE_INVALID);
+
+          if (*p == DBUS_DICT_ENTRY_BEGIN_CHAR)
+            depth += 1;
+          else if (*p == DBUS_DICT_ENTRY_END_CHAR)
+            {
+              depth -= 1;
+              if (depth == 0)
+                {
+                  ++p;
+                  break;
+                }
+            }
+        }
+    }
   else
     {
       ++p;
@@ -381,6 +412,7 @@ base_reader_next (DBusTypeReader *reader,
 {
   switch (current_type)
     {
+    case DBUS_TYPE_DICT_ENTRY:
     case DBUS_TYPE_STRUCT:
     case DBUS_TYPE_VARIANT:
       /* Scan forward over the entire container contents */
@@ -461,6 +493,27 @@ struct_reader_next (DBusTypeReader *reader,
 }
 
 static void
+dict_entry_reader_next (DBusTypeReader *reader,
+                        int             current_type)
+{
+  int t;
+
+  base_reader_next (reader, current_type);
+
+  /* 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())
+   */
+  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
+  if (t == DBUS_DICT_ENTRY_END_CHAR)
+    {
+      reader->type_pos += 1;
+      reader->finished = TRUE;
+    }
+}
+
+static void
 array_types_only_reader_next (DBusTypeReader *reader,
                               int             current_type)
 {
@@ -495,6 +548,7 @@ array_reader_next (DBusTypeReader *reader,
   switch (_dbus_first_type_in_signature (reader->type_str,
                                    reader->type_pos))
     {
+    case DBUS_TYPE_DICT_ENTRY:
     case DBUS_TYPE_STRUCT:
     case DBUS_TYPE_VARIANT:
       {
@@ -582,7 +636,7 @@ static const DBusTypeReaderClass body_types_only_reader_class = {
 static const DBusTypeReaderClass struct_reader_class = {
   "struct", 2,
   FALSE,
-  struct_reader_recurse,
+  struct_or_dict_entry_reader_recurse,
   NULL,
   struct_reader_next,
   NULL
@@ -591,14 +645,32 @@ static const DBusTypeReaderClass struct_reader_class = {
 static const DBusTypeReaderClass struct_types_only_reader_class = {
   "struct types", 3,
   TRUE,
-  struct_types_only_reader_recurse,
+  struct_or_dict_entry_types_only_reader_recurse,
   NULL,
   struct_reader_next,
   NULL
 };
 
+static const DBusTypeReaderClass dict_entry_reader_class = {
+  "dict_entry", 4,
+  FALSE,
+  struct_or_dict_entry_reader_recurse,
+  NULL,
+  dict_entry_reader_next,
+  NULL
+};
+
+static const DBusTypeReaderClass dict_entry_types_only_reader_class = {
+  "dict_entry types", 5,
+  TRUE,
+  struct_or_dict_entry_types_only_reader_recurse,
+  NULL,
+  dict_entry_reader_next,
+  NULL
+};
+
 static const DBusTypeReaderClass array_reader_class = {
-  "array", 4,
+  "array", 6,
   FALSE,
   array_reader_recurse,
   array_reader_check_finished,
@@ -607,7 +679,7 @@ static const DBusTypeReaderClass array_reader_class = {
 };
 
 static const DBusTypeReaderClass array_types_only_reader_class = {
-  "array types", 5,
+  "array types", 7,
   TRUE,
   array_types_only_reader_recurse,
   NULL,
@@ -616,7 +688,7 @@ static const DBusTypeReaderClass array_types_only_reader_class = {
 };
 
 static const DBusTypeReaderClass variant_reader_class = {
-  "variant", 6,
+  "variant", 8,
   FALSE,
   variant_reader_recurse,
   NULL,
@@ -630,6 +702,8 @@ all_reader_classes[] = {
   &body_types_only_reader_class,
   &struct_reader_class,
   &struct_types_only_reader_class,
+  &dict_entry_reader_class,
+  &dict_entry_types_only_reader_class,
   &array_reader_class,
   &array_types_only_reader_class,
   &variant_reader_class
@@ -798,11 +872,13 @@ _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
     t = DBUS_TYPE_INVALID;
   else
     t = _dbus_first_type_in_signature (reader->type_str,
-                                 reader->type_pos);
+                                       reader->type_pos);
 
   _dbus_assert (t != DBUS_STRUCT_END_CHAR);
   _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
-
+  _dbus_assert (t != DBUS_DICT_ENTRY_END_CHAR);
+  _dbus_assert (t != DBUS_DICT_ENTRY_BEGIN_CHAR);
+  
 #if 0
   _dbus_verbose ("  type reader %p current type_pos = %d type = %s\n",
                  reader, reader->type_pos,
@@ -989,6 +1065,12 @@ _dbus_type_reader_recurse (DBusTypeReader *reader,
       else
         sub->klass = &struct_reader_class;
       break;
+    case DBUS_TYPE_DICT_ENTRY:
+      if (reader->klass->types_only)
+        sub->klass = &dict_entry_types_only_reader_class;
+      else
+        sub->klass = &dict_entry_reader_class;
+      break;
     case DBUS_TYPE_ARRAY:
       if (reader->klass->types_only)
         sub->klass = &array_types_only_reader_class;
@@ -1734,11 +1816,12 @@ write_or_verify_typecode (DBusTypeWriter *writer,
 }
 
 static dbus_bool_t
-writer_recurse_struct (DBusTypeWriter   *writer,
-                       const DBusString *contained_type,
-                       int               contained_type_start,
-                       int               contained_type_len,
-                       DBusTypeWriter   *sub)
+writer_recurse_struct_or_dict_entry (DBusTypeWriter   *writer,
+                                     int               begin_char,
+                                     const DBusString *contained_type,
+                                     int               contained_type_start,
+                                     int               contained_type_len,
+                                     DBusTypeWriter   *sub)
 {
   /* FIXME right now contained_type is ignored; we could probably
    * almost trivially fix the code so if it's present we
@@ -1752,7 +1835,7 @@ writer_recurse_struct (DBusTypeWriter   *writer,
         return FALSE;
     }
 
-  if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
+  if (!write_or_verify_typecode (sub, begin_char))
     _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
 
   if (writer->enabled)
@@ -2027,9 +2110,18 @@ _dbus_type_writer_recurse_contained_len (DBusTypeWriter   *writer,
   switch (container_type)
     {
     case DBUS_TYPE_STRUCT:
-      return writer_recurse_struct (writer,
-                                    contained_type, contained_type_start, contained_type_len,
-                                    sub);
+      return writer_recurse_struct_or_dict_entry (writer,
+                                                  DBUS_STRUCT_BEGIN_CHAR,
+                                                  contained_type,
+                                                  contained_type_start, contained_type_len,
+                                                  sub);
+      break;
+    case DBUS_TYPE_DICT_ENTRY:
+      return writer_recurse_struct_or_dict_entry (writer,
+                                                  DBUS_DICT_ENTRY_BEGIN_CHAR,
+                                                  contained_type,
+                                                  contained_type_start, contained_type_len,
+                                                  sub);
       break;
     case DBUS_TYPE_ARRAY:
       return writer_recurse_array (writer,
@@ -2151,6 +2243,11 @@ _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
       if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
         return FALSE;
     }
+  else if (sub->container_type == DBUS_TYPE_DICT_ENTRY)
+    {
+      if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))
+        return FALSE;
+    }
   else if (sub->container_type == DBUS_TYPE_ARRAY)
     {
       if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */
@@ -2217,11 +2314,16 @@ _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
    *   parent makes no difference since there's only one value
    *   and we just finished writing it and won't use type_pos again
    *       writer->type_pos should remain as-is
+   *
+   *
+   * For all these, DICT_ENTRY is the same as STRUCT
    */
   if (writer->type_str != NULL)
     {
-      if (sub->container_type == DBUS_TYPE_STRUCT &&
+      if ((sub->container_type == DBUS_TYPE_STRUCT ||
+           sub->container_type == DBUS_TYPE_DICT_ENTRY) &&
           (writer->container_type == DBUS_TYPE_STRUCT ||
+           writer->container_type == DBUS_TYPE_DICT_ENTRY ||
            writer->container_type == DBUS_TYPE_INVALID))
         {
           /* Advance the parent to the next struct field */
index b26adb2..e57be5c 100644 (file)
  * The range passed in should NOT include the terminating
  * nul/DBUS_TYPE_INVALID.
  *
+ * @todo verify that dict entries have exactly two fields
+ * 
+ * @todo require that dict entries are in an array
+ *
  * @param type_str the string
  * @param type_pos where the typecodes start
  * @param len length of typecodes
@@ -55,6 +59,7 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
   int last;
   int struct_depth;
   int array_depth;
+  int dict_entry_depth;
 
   _dbus_assert (type_str != NULL);
   _dbus_assert (type_pos < _DBUS_INT32_MAX - len);
@@ -68,6 +73,7 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
   end = _dbus_string_get_const_data_len (type_str, type_pos + len, 0);
   struct_depth = 0;
   array_depth = 0;
+  dict_entry_depth = 0;
   last = DBUS_TYPE_INVALID;
 
   while (p != end)
@@ -112,7 +118,28 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
           struct_depth -= 1;
           break;
 
-        case DBUS_TYPE_STRUCT: /* doesn't appear in signatures */
+        case DBUS_DICT_ENTRY_BEGIN_CHAR:
+          if (last != DBUS_TYPE_ARRAY)
+            return DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY;
+          
+          dict_entry_depth += 1;
+
+          if (dict_entry_depth > DBUS_MAXIMUM_TYPE_RECURSION_DEPTH)
+            return DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION;
+          break;
+
+        case DBUS_DICT_ENTRY_END_CHAR:
+          if (dict_entry_depth == 0)
+            return DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED;
+          
+          if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
+            return DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS;
+
+          dict_entry_depth -= 1;
+          break;
+          
+        case DBUS_TYPE_STRUCT:     /* doesn't appear in signatures */
+        case DBUS_TYPE_DICT_ENTRY: /* ditto */
         default:
           return DBUS_INVALID_UNKNOWN_TYPECODE;
         }
@@ -130,6 +157,9 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
   if (struct_depth > 0)
     return DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED;
 
+  if (dict_entry_depth > 0)
+    return DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED;
+  
   return DBUS_VALID;
 }
 
@@ -377,6 +407,7 @@ validate_body_helper (DBusTypeReader       *reader,
           }
           break;
 
+        case DBUS_TYPE_DICT_ENTRY:
         case DBUS_TYPE_STRUCT:
           {
             DBusTypeReader sub;
index 94b7798..55739d3 100644 (file)
@@ -100,7 +100,14 @@ typedef enum
   DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES = 46,
   DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL = 47,
   DBUS_INVALID_STRING_MISSING_NUL = 48,
-  DBUS_INVALID_SIGNATURE_MISSING_NUL = 49
+  DBUS_INVALID_SIGNATURE_MISSING_NUL = 49,
+  DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION = 50,
+  DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED = 51,
+  DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED = 52,
+  DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS = 53,
+  DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD = 54,
+  DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS = 55,
+  DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY = 56
 } DBusValidity;
 
 DBusValidity _dbus_validate_signature_with_reason (const DBusString *type_str,
index 38ae317..8525200 100644 (file)
@@ -2112,10 +2112,10 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter,
  * dbus_message_iter_close_container(). Container types are for
  * example struct, variant, and array. For variants, the
  * contained_signature should be the type of the single value inside
- * the variant. For structs, contained_signature should be #NULL; it
- * will be set to whatever types you write into the struct.  For
- * arrays, contained_signature should be the type of the array
- * elements.
+ * the variant. For structs and dict entries, contained_signature
+ * should be #NULL; it will be set to whatever types you write into
+ * the struct.  For arrays, contained_signature should be the type of
+ * the array elements.
  *
  * @todo If this fails due to lack of memory, the message is hosed and
  * you have to start over building the whole message.
@@ -2142,7 +2142,21 @@ dbus_message_iter_open_container (DBusMessageIter *iter,
   _dbus_return_val_if_fail (sub != NULL, FALSE);
   _dbus_return_val_if_fail ((type == DBUS_TYPE_STRUCT &&
                              contained_signature == NULL) ||
+                            (type == DBUS_TYPE_DICT_ENTRY &&
+                             contained_signature == NULL) ||
                             contained_signature != NULL, FALSE);
+  _dbus_return_val_if_fail (type != DBUS_TYPE_DICT_ENTRY ||
+                            dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_ARRAY,
+                            FALSE);
+  
+#if 0
+  /* FIXME this would fail if the contained_signature is a dict entry,
+   * since dict entries are invalid signatures standalone (they must be in
+   * an array)
+   */
+  _dbus_return_val_if_fail (contained_signature == NULL ||
+                            _dbus_check_is_valid_signature (contained_signature));
+#endif
 
   if (!_dbus_message_iter_open_signature (real))
     return FALSE;
index d0a3d64..8191262 100644 (file)
@@ -77,20 +77,27 @@ extern "C" {
 #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
+/* STRUCT and DICT_ENTRY are sort of special since their codes can't
+ * appear in a type string, instead
+ * DBUS_STRUCT_BEGIN_CHAR/DBUS_DICT_ENTRY_BEGIN_CHAR have to appear
  */
 #define DBUS_TYPE_STRUCT        ((int) 'r')
 #define DBUS_TYPE_STRUCT_AS_STRING         "r"
+#define DBUS_TYPE_DICT_ENTRY    ((int) 'e')
+#define DBUS_TYPE_DICT_ENTRY_AS_STRING     "e"
 
 /* Does not count INVALID */
-#define DBUS_NUMBER_OF_TYPES    (15)
+#define DBUS_NUMBER_OF_TYPES    (16)
 
 /* 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     ")"
+#define DBUS_DICT_ENTRY_BEGIN_CHAR   ((int) '{')
+#define DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING   "{"
+#define DBUS_DICT_ENTRY_END_CHAR     ((int) '}')
+#define DBUS_DICT_ENTRY_END_CHAR_AS_STRING     "}"
 
 /* Max length in bytes of a bus name, interface, or member (not object
  * path, paths are unlimited). This is limited because lots of stuff
index c2586c4..631b771 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -36,14 +36,15 @@ Important for 1.0
    yourself; is it an error, or allowed? If allowed, 
    we need to have a test for it in the test suite.
 
- - array lengths should probably be returned as size_t rather than int
-   (though they are kind of a pita to pass in as size_t with the 
-    varargs, so maybe not - what does glib do with g_object_get()?)
-
  - add string array support back to append_args()
 
+ - validate dict entry number of fields
+
  - just before 1.0, try a HAVE_INT64=0 build and be sure it runs
 
+ - the spec and implementation should probably require dict keys
+   to be basic types
+
 Important for 1.0 GLib Bindings
 ===
 
index c0be80f..f72434b 100644 (file)
@@ -7,8 +7,8 @@
 <article id="index">
   <articleinfo>
     <title>D-BUS Specification</title>
-    <releaseinfo>Version 0.9</releaseinfo>
-    <date>17 January 2005</date>
+    <releaseinfo>Version 0.10</releaseinfo>
+    <date>28 January 2005</date>
     <authorgroup>
       <author>
        <firstname>Havoc</firstname>
       </para>
 
       <para>
+        A <literal>DICT_ENTRY</literal> works exactly like a struct, but rather
+        than parentheses it uses curly braces, and it has more restrictions.
+        The restrictions are: it occurs only as an array element type; and it
+        has exactly two single complete types inside the curly
+        braces. Implementations must not accept dict entries outside of arrays,
+        and must not accept dict entries with zero, one, or more than two
+        fields. A dict entry is always a key-value pair.
+      </para>
+      
+      <para>
+        The first field in the <literal>DICT_ENTRY</literal> is always the key.
+        A message is considered corrupt if the same key occurs twice in the same
+        array of <literal>DICT_ENTRY</literal>. However, for performance reasons
+        implementations are not required to reject dicts with duplicate keys.
+      </para>
+
+      <para>
+        In most languages, an array of dict entry would be represented as a 
+        map, hash table, or dict object.
+      </para>
+
+      <para>
         The following table summarizes the D-BUS types.
         <informaltable>
           <tgroup cols="3">
                <entry>98 (ASCII 'b')</entry>
                <entry>Boolean value, 0 is <literal>FALSE</literal> and 1 is <literal>TRUE</literal>. Everything else is invalid.</entry>
              </row><row>
+                <entry><literal>INT16</literal></entry>
+                <entry>110 (ASCII 'n')</entry>
+                <entry>16-bit signed integer</entry>
+              </row><row>
+                <entry><literal>UINT16</literal></entry>
+                <entry>113 (ASCII 'q')</entry>
+                <entry>16-bit unsigned integer</entry>
+             </row><row>
                 <entry><literal>INT32</literal></entry>
                 <entry>105 (ASCII 'i')</entry>
                 <entry>32-bit signed integer</entry>
                 <entry><literal>VARIANT</literal></entry>
                 <entry>118 (ASCII 'v') </entry>
                 <entry>Variant type (the type of the value is part of the value itself)</entry>
+              </row><row>
+                <entry><literal>DICT_ENTRY</literal></entry>
+                <entry>101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') </entry>
+                <entry>Entry in a dict or map (array of key-value pairs)</entry>
               </row>
             </tbody>
           </tgroup>
                 <entry>As for <literal>UINT32</literal>, but only 0 and 1 are valid values.</entry>
                 <entry>4</entry>
               </row><row>
+                <entry><literal>INT16</literal></entry>
+                <entry>16-bit signed integer in the message's byte order.</entry>
+                <entry>2</entry>
+              </row><row>
+                <entry><literal>UINT16</literal></entry>
+                <entry>16-bit unsigned integer in the message's byte order.</entry>
+                <entry>2</entry>
+              </row><row>
                 <entry><literal>INT32</literal></entry>
                 <entry>32-bit signed integer in the message's byte order.</entry>
                 <entry>4</entry>
                 <entry>
                   1 (alignment of the signature)
                 </entry>
+             </row><row>
+                <entry><literal>DICT_ENTRY</literal></entry>
+                <entry>
+                  Identical to STRUCT.
+                </entry>
+                <entry>
+                  8
+                </entry>
              </row>
             </tbody>
           </tgroup>