From c7816d45e82ba8dd7e1e969c2cb6c3a27577cf68 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 28 Jan 2005 05:30:53 +0000 Subject: 2005-01-28 Havoc Pennington * 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 | 13 ++ dbus/dbus-marshal-basic.c | 20 ++- dbus/dbus-marshal-byteswap.c | 1 + dbus/dbus-marshal-recursive-util.c | 262 ++++++++++++++++++++++++++++++++++++- dbus/dbus-marshal-recursive.c | 152 +++++++++++++++++---- dbus/dbus-marshal-validate.c | 33 ++++- dbus/dbus-marshal-validate.h | 9 +- dbus/dbus-message.c | 22 +++- dbus/dbus-protocol.h | 13 +- doc/TODO | 9 +- doc/dbus-specification.xml | 54 +++++++- 11 files changed, 543 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index 137ebe26..5d948f12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-01-28 Havoc Pennington + + * 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 * dbus/dbus-arch-deps.h.in: add 16/32-bit types diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index e4f6720c..84a9ccaf 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -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; + } } /** @} */ diff --git a/dbus/dbus-marshal-byteswap.c b/dbus/dbus-marshal-byteswap.c index 7670ec45..c8ec8942 100644 --- a/dbus/dbus-marshal-byteswap.c +++ b/dbus/dbus-marshal-byteswap.c @@ -175,6 +175,7 @@ byteswap_body_helper (DBusTypeReader *reader, break; case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: { DBusTypeReader sub; diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c index c607b046..6e8af18a 100644 --- a/dbus/dbus-marshal-recursive-util.c +++ b/dbus/dbus-marshal-recursive-util.c @@ -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) { diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 09bf1742..738edd91 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -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 */ @@ -460,6 +492,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 */ diff --git a/dbus/dbus-marshal-validate.c b/dbus/dbus-marshal-validate.c index b26adb2c..e57be5c7 100644 --- a/dbus/dbus-marshal-validate.c +++ b/dbus/dbus-marshal-validate.c @@ -40,6 +40,10 @@ * 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; diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h index 94b77989..55739d31 100644 --- a/dbus/dbus-marshal-validate.h +++ b/dbus/dbus-marshal-validate.h @@ -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, diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 38ae317a..85252005 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -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; diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index d0a3d64e..81912622 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -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 diff --git a/doc/TODO b/doc/TODO index c2586c43..631b7719 100644 --- 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 === diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml index c0be80fb..f72434b3 100644 --- a/doc/dbus-specification.xml +++ b/doc/dbus-specification.xml @@ -7,8 +7,8 @@
D-BUS Specification - Version 0.9 - 17 January 2005 + Version 0.10 + 28 January 2005 Havoc @@ -262,6 +262,28 @@ marshaled value of that type. + + A DICT_ENTRY 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. + + + + The first field in the DICT_ENTRY is always the key. + A message is considered corrupt if the same key occurs twice in the same + array of DICT_ENTRY. However, for performance reasons + implementations are not required to reject dicts with duplicate keys. + + + + In most languages, an array of dict entry would be represented as a + map, hash table, or dict object. + + The following table summarizes the D-BUS types. @@ -286,6 +308,14 @@ BOOLEAN 98 (ASCII 'b') Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid. + + INT16 + 110 (ASCII 'n') + 16-bit signed integer + + UINT16 + 113 (ASCII 'q') + 16-bit unsigned integer INT32 105 (ASCII 'i') @@ -330,6 +360,10 @@ VARIANT 118 (ASCII 'v') Variant type (the type of the value is part of the value itself) + + DICT_ENTRY + 101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') + Entry in a dict or map (array of key-value pairs) @@ -391,6 +425,14 @@ BOOLEAN As for UINT32, but only 0 and 1 are valid values. 4 + + INT16 + 16-bit signed integer in the message's byte order. + 2 + + UINT16 + 16-bit unsigned integer in the message's byte order. + 2 INT32 32-bit signed integer in the message's byte order. @@ -478,6 +520,14 @@ 1 (alignment of the signature) + + DICT_ENTRY + + Identical to STRUCT. + + + 8 + -- cgit