From 7debfd9ff56c5c2208372142e494c3e4a2defb23 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Tue, 28 Dec 2004 04:55:52 +0000 Subject: sync busted marshaling work in progress --- dbus/dbus-marshal-basic.c | 77 ++- dbus/dbus-marshal-basic.h | 21 +- dbus/dbus-marshal-recursive.c | 1064 ++++++++++++++++++++++++++++++++++++----- dbus/dbus-marshal-recursive.h | 78 ++- dbus/dbus-protocol-new.h | 16 + 5 files changed, 1103 insertions(+), 153 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index d325d5f0..d2b7b404 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -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: @@ -2438,6 +2458,47 @@ _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. * @@ -2445,10 +2506,12 @@ _dbus_type_is_valid (int typecode) * * @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); } /** diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h index e8c0b3fb..968d22cc 100644 --- a/dbus/dbus-marshal-basic.h +++ b/dbus/dbus-marshal-basic.h @@ -53,38 +53,55 @@ #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 */ +#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 */ diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 1962e629..5bd37a5a 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -29,6 +29,27 @@ * @{ */ +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; @@ -328,19 +651,131 @@ _dbus_type_writer_recurse (DBusTypeWriter *writer, return TRUE; } +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; diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h index ed70a827..57b55fcf 100644 --- a/dbus/dbus-marshal-recursive.h +++ b/dbus/dbus-marshal-recursive.h @@ -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 */ diff --git a/dbus/dbus-protocol-new.h b/dbus/dbus-protocol-new.h index 9d8c4b6f..93cc5668 100644 --- a/dbus/dbus-protocol-new.h +++ b/dbus/dbus-protocol-new.h @@ -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 */ +#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 -- cgit