From 9b0fc4e482d6d7d9d6105d876fbbd2182e7b6dd3 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Wed, 29 Dec 2004 22:22:41 +0000 Subject: switch to a vtable approach for the reader --- dbus/dbus-marshal-recursive.c | 648 +++++++++++++++++++++++------------------- 1 file changed, 362 insertions(+), 286 deletions(-) (limited to 'dbus/dbus-marshal-recursive.c') diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 292b71c6..39acd7e6 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -29,6 +29,16 @@ * @{ */ +struct DBusTypeReaderClass +{ + const char *name; + void (* recurse) (DBusTypeReader *sub, + DBusTypeReader *parent); + int (* get_current_type) (DBusTypeReader *reader); + void (* next) (DBusTypeReader *reader, + int current_type); +}; + static int first_type_in_signature (const DBusString *str, int pos) @@ -50,70 +60,357 @@ element_type_get_alignment (const DBusString *str, return _dbus_type_get_alignment (first_type_in_signature (str, pos)); } -void -_dbus_type_reader_init (DBusTypeReader *reader, - int byte_order, - const DBusString *type_str, - int type_pos, - const DBusString *value_str, - int value_pos) +static void +reader_init (DBusTypeReader *reader, + int byte_order, + const DBusString *type_str, + int type_pos, + const DBusString *value_str, + int value_pos) { reader->byte_order = byte_order; reader->type_str = type_str; 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", - reader, reader->type_pos, reader->value_pos, - _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0)); +static void +base_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + /* point subreader at the same place as parent */ + reader_init (sub, + parent->byte_order, + parent->type_str, + parent->type_pos, + parent->value_str, + parent->value_pos); } -int -_dbus_type_reader_get_current_type (DBusTypeReader *reader) +static void +struct_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 += 1; + + /* struct has 8 byte alignment */ + sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8); + + sub->u.strct.finished = FALSE; +} + +static void +array_reader_recurse (DBusTypeReader *sub, + DBusTypeReader *parent) +{ + dbus_uint32_t array_len; + int alignment; + + _dbus_assert (!_dbus_type_reader_array_is_empty (parent)); + + base_reader_recurse (sub, parent); + + /* 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; + + _dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n", + sub, + sub->u.array.start_pos, + sub->u.array.len, + _dbus_type_to_string (sub->u.array.element_type)); +} + +static int +body_reader_get_current_type (DBusTypeReader *reader) +{ + int t; + + t = first_type_in_signature (reader->type_str, + reader->type_pos); + + return t; +} + +static int +struct_reader_get_current_type (DBusTypeReader *reader) { int t; + + if (reader->u.strct.finished) + t = DBUS_TYPE_INVALID; + else + t = first_type_in_signature (reader->type_str, + reader->type_pos); + + return t; +} - /* for INVALID t will == DBUS_TYPE_INVALID when we - * reach the end of type_str, for STRUCT we have to - * check the finished flag +static int +array_reader_get_current_type (DBusTypeReader *reader) +{ + int t; + int end_pos; + + /* return the array element type if elements remain, and + * TYPE_INVALID otherwise */ - if (reader->container_type == DBUS_TYPE_INVALID) + + 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->value_pos < end_pos) + t = reader->u.array.element_type; + else + t = DBUS_TYPE_INVALID; + + return t; +} + +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) { - t = first_type_in_signature (reader->type_str, - reader->type_pos); + 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 if (reader->container_type == DBUS_TYPE_STRUCT) + else + *type_pos += 1; +} + +static void +skip_array_values (int element_type, + const DBusString *value_str, + int *value_pos, + int byte_order) +{ + dbus_uint32_t array_len; + int pos; + int alignment; + + pos = _DBUS_ALIGN_VALUE (*value_pos, 4); + + _dbus_demarshal_basic_type (value_str, + DBUS_TYPE_UINT32, + &array_len, + byte_order, + &pos); + + alignment = _dbus_type_get_alignment (element_type); + + pos = _DBUS_ALIGN_VALUE (pos, alignment); + + *value_pos = pos + array_len; +} + +static void +base_reader_next (DBusTypeReader *reader, + int current_type) +{ + switch (current_type) { - if (reader->u.strct.finished) - t = DBUS_TYPE_INVALID; - else - t = first_type_in_signature (reader->type_str, - reader->type_pos); + case DBUS_TYPE_STRUCT: + /* 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)) + { + /* nothing */; + } + + /* Now we are at the end of this container */ + reader->type_pos = sub.type_pos; + reader->value_pos = sub.value_pos; + } + break; + + case DBUS_TYPE_ARRAY: + { + skip_array_values (first_type_in_signature (reader->type_str, + reader->type_pos + 1), + reader->value_str, &reader->value_pos, reader->byte_order); + skip_one_complete_type (reader->type_str, &reader->type_pos); + } + break; + + default: + _dbus_marshal_skip_basic_type (reader->value_str, + current_type, reader->byte_order, + &reader->value_pos); + reader->type_pos += 1; + break; } - else if (reader->container_type == DBUS_TYPE_ARRAY) +} + +static void +struct_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_STRUCT_END_CHAR) { - /* return the array element type if elements remain, and - * TYPE_INVALID otherwise - */ - int end_pos; + reader->type_pos += 1; + reader->u.strct.finished = TRUE; + } +} - end_pos = reader->u.array.start_pos + reader->u.array.len; +static void +array_reader_next (DBusTypeReader *reader, + int current_type) +{ + /* Skip one array element */ + int end_pos; - _dbus_assert (reader->value_pos <= end_pos); - _dbus_assert (reader->value_pos >= reader->u.array.start_pos); + end_pos = reader->u.array.start_pos + reader->u.array.len; - if (reader->value_pos < end_pos) - t = reader->u.array.element_type; - else - t = DBUS_TYPE_INVALID; + _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_STRUCT) + { + DBusTypeReader sub; + + /* Recurse into the struct */ + _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 if (reader->u.array.element_type == DBUS_TYPE_ARRAY) + { + skip_array_values (first_type_in_signature (reader->type_str, + reader->type_pos + 1), + reader->value_str, &reader->value_pos, reader->byte_order); } else { - _dbus_assert_not_reached ("reader->container_type should not be set to this"); - t = DBUS_TYPE_INVALID; /* quiet gcc */ + _dbus_marshal_skip_basic_type (reader->value_str, + current_type, 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); } +} + +static const DBusTypeReaderClass body_reader_class = { + "body", + NULL, /* body is always toplevel, so doesn't get recursed into */ + body_reader_get_current_type, + base_reader_next +}; + +static const DBusTypeReaderClass struct_reader_class = { + "struct", + struct_reader_recurse, + struct_reader_get_current_type, + struct_reader_next +}; + +static const DBusTypeReaderClass array_reader_class = { + "array", + array_reader_recurse, + array_reader_get_current_type, + array_reader_next +}; + +void +_dbus_type_reader_init (DBusTypeReader *reader, + int byte_order, + const DBusString *type_str, + int type_pos, + const DBusString *value_str, + int value_pos) +{ + reader->klass = &body_reader_class; + + reader_init (reader, byte_order, type_str, type_pos, + value_str, value_pos); + + _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)); +} + +int +_dbus_type_reader_get_current_type (DBusTypeReader *reader) +{ + int t; + + t = (* reader->klass->get_current_type) (reader); _dbus_assert (t != DBUS_STRUCT_END_CHAR); _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR); @@ -151,30 +448,21 @@ void _dbus_type_reader_read_basic (DBusTypeReader *reader, void *value) { - 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); - - - _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)); - } - else - { - _dbus_assert_not_reached ("reader->container_type should not be set to this"); - } + 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); + + + _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_bool_t @@ -206,65 +494,16 @@ _dbus_type_reader_recurse (DBusTypeReader *reader, int t; t = first_type_in_signature (reader->type_str, reader->type_pos); - - /* point subreader at the same place as reader */ - _dbus_type_reader_init (sub, - reader->byte_order, - reader->type_str, - reader->type_pos, - reader->value_str, - reader->value_pos); - 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; - - _dbus_return_if_fail (!_dbus_type_reader_array_is_empty (reader)); - - 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; - - _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 + switch (t) { + case DBUS_TYPE_STRUCT: + sub->klass = &struct_reader_class; + break; + case DBUS_TYPE_ARRAY: + sub->klass = &array_reader_class; + break; + default: _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t)); #ifndef DBUS_DISABLE_CHECKS if (t == DBUS_TYPE_INVALID) @@ -274,69 +513,13 @@ _dbus_type_reader_recurse (DBusTypeReader *reader, _dbus_assert_not_reached ("don't yet handle recursing into this type"); } + (* sub->klass->recurse) (sub, reader); + _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; -} - -static void -skip_array_values (int element_type, - const DBusString *value_str, - int *value_pos, - int byte_order) -{ - dbus_uint32_t array_len; - int pos; - int alignment; - - pos = _DBUS_ALIGN_VALUE (*value_pos, 4); - - _dbus_demarshal_basic_type (value_str, - DBUS_TYPE_UINT32, - &array_len, - byte_order, - &pos); - - alignment = _dbus_type_get_alignment (element_type); - - pos = _DBUS_ALIGN_VALUE (pos, alignment); - - *value_pos = pos + array_len; -} - /** * 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 @@ -359,115 +542,8 @@ _dbus_type_reader_next (DBusTypeReader *reader) if (t == DBUS_TYPE_INVALID) return FALSE; - - if (reader->container_type == DBUS_TYPE_INVALID || - reader->container_type == DBUS_TYPE_STRUCT) - { - switch (t) - { - case DBUS_TYPE_STRUCT: - /* 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)) - { - /* nothing */; - } - - /* Now we are at the end of this container */ - reader->type_pos = sub.type_pos; - reader->value_pos = sub.value_pos; - } - break; - - case DBUS_TYPE_ARRAY: - { - skip_array_values (first_type_in_signature (reader->type_str, - reader->type_pos + 1), - reader->value_str, &reader->value_pos, reader->byte_order); - skip_one_complete_type (reader->type_str, &reader->type_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) - { - /* 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_STRUCT) - { - DBusTypeReader sub; - - /* Recurse into the struct */ - _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 if (reader->u.array.element_type == DBUS_TYPE_ARRAY) - { - skip_array_values (first_type_in_signature (reader->type_str, - reader->type_pos + 1), - reader->value_str, &reader->value_pos, reader->byte_order); - } - 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"); - } + (* reader->klass->next) (reader, t); _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, -- cgit