+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
_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);
* 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:
case DBUS_TYPE_SIGNATURE:
case DBUS_TYPE_ARRAY:
case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
case DBUS_TYPE_VARIANT:
return TRUE;
/** 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)
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:
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";
}
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;
+ }
}
/** @} */
break;
case DBUS_TYPE_STRUCT:
+ case DBUS_TYPE_DICT_ENTRY:
{
DBusTypeReader sub;
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,
static void container_destroy (TestTypeNode *node);
+
static const TestTypeNodeClass int16_class = {
DBUS_TYPE_INT16,
sizeof (TestTypeNode),
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 = {
&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
*/
_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;
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)
{
}
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);
}
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)
{
}
}
}
+ 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;
{
switch (current_type)
{
+ case DBUS_TYPE_DICT_ENTRY:
case DBUS_TYPE_STRUCT:
case DBUS_TYPE_VARIANT:
/* Scan forward over the entire container contents */
}
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)
{
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:
{
static const DBusTypeReaderClass struct_reader_class = {
"struct", 2,
FALSE,
- struct_reader_recurse,
+ struct_or_dict_entry_reader_recurse,
NULL,
struct_reader_next,
NULL
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,
};
static const DBusTypeReaderClass array_types_only_reader_class = {
- "array types", 5,
+ "array types", 7,
TRUE,
array_types_only_reader_recurse,
NULL,
};
static const DBusTypeReaderClass variant_reader_class = {
- "variant", 6,
+ "variant", 8,
FALSE,
variant_reader_recurse,
NULL,
&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
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,
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;
}
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
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)
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,
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 */
* 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 */
* 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
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);
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)
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;
}
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;
}
}
break;
+ case DBUS_TYPE_DICT_ENTRY:
case DBUS_TYPE_STRUCT:
{
DBusTypeReader sub;
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,
* 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.
_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;
#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
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
===
<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>