summaryrefslogtreecommitdiffstats
path: root/dbus
diff options
context:
space:
mode:
Diffstat (limited to 'dbus')
-rw-r--r--dbus/dbus-marshal-recursive.c648
-rw-r--r--dbus/dbus-marshal-recursive.h29
2 files changed, 368 insertions, 309 deletions
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,
diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h
index 8e5427bd..6d0a40b4 100644
--- a/dbus/dbus-marshal-recursive.h
+++ b/dbus/dbus-marshal-recursive.h
@@ -31,23 +31,10 @@
#error "config.h not included here"
#endif
-/* Notes on my plan to implement this:
- * - also have DBusTypeWriter (heh)
- * - TypeReader has accessors for:
- * . basic type
- * . array of basic type (efficiency hack)
- * . another type reader
- * - a dict will appear to be a list of string, whatever, string, whatever
- * - a variant will contain another TypeReader
- * - a struct will be a list of whatever, whatever, whatever
- *
- * So the basic API usage is to go next, next, next; if the
- * item is a basic type or basic array then read the item;
- * if it's another type reader then process it; if it's
- * a container type (struct, array, variant, dict) then
- * recurse.
- *
- */
+typedef struct DBusTypeReader DBusTypeReader;
+typedef struct DBusTypeWriter DBusTypeWriter;
+typedef struct DBusTypeReaderClass DBusTypeReaderClass;
+typedef struct DBusTypeWriterClass DBusTypeWriterClass;
struct DBusTypeReader
{
@@ -57,8 +44,7 @@ struct DBusTypeReader
const DBusString *value_str;
int value_pos;
- /* Hmm - it might be cleaner to do TypeReaderClass *vtable for container type */
- int container_type;
+ const DBusTypeReaderClass *klass;
union
{
struct {
@@ -78,8 +64,6 @@ struct DBusTypeReader
} u;
};
-typedef struct DBusTypeReader DBusTypeReader;
-
struct DBusTypeWriter
{
int byte_order;
@@ -90,6 +74,7 @@ struct DBusTypeWriter
dbus_uint32_t inside_array : 1;
+ /* const DBusTypeWriterClass *klass; */
int container_type;
union
{
@@ -107,8 +92,6 @@ struct DBusTypeWriter
} u;
};
-typedef struct DBusTypeWriter DBusTypeWriter;
-
void _dbus_type_reader_init (DBusTypeReader *reader,
int byte_order,
const DBusString *type_str,