From c7e05f9ca4ff7ab0c8499b2059004dd38d2c8784 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Mon, 3 Jan 2005 07:15:38 +0000 Subject: finish off my TODO list for stuff needed to port dbus-message.c. Next step is to do so. --- dbus/dbus-marshal-basic.c | 308 ++++++++++++++++++++++++++------------ dbus/dbus-marshal-basic.h | 13 +- dbus/dbus-marshal-recursive.c | 340 ++++++++++++++++++++++++++++++++---------- dbus/dbus-marshal-recursive.h | 17 ++- 4 files changed, 486 insertions(+), 192 deletions(-) diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c index 17e2964d..11ebfaf1 100644 --- a/dbus/dbus-marshal-basic.c +++ b/dbus/dbus-marshal-basic.c @@ -553,6 +553,57 @@ _dbus_marshal_read_basic (const DBusString *str, *new_pos = pos; } +/** + * Reads an array of fixed-length basic values. Does not work for + * arrays of string or container types. + * + * This function returns the array in-place; it does not make a copy, + * and it does not swap the bytes. + * + * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back + * and the "value" argument should be a "const double**" and so on. + * + * @todo last I checked only the test suite uses this function + * + * @param str the string to read from + * @param pos position to read from + * @param element_type type of array elements + * @param value place to return the array + * @param n_elements place to return number of array elements + * @param byte_order the byte order, used to read the array length + * @param new_pos #NULL or location to store a position after the elements + */ +void +_dbus_marshal_read_fixed_array (const DBusString *str, + int pos, + int element_type, + void *value, + int *n_elements, + int byte_order, + int *new_pos) +{ + dbus_uint32_t array_len; + int alignment; + + _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (_dbus_type_is_basic (element_type)); + + pos = _DBUS_ALIGN_VALUE (pos, 4); + + array_len = _dbus_marshal_read_uint32 (str, pos, byte_order, &pos); + + alignment = _dbus_type_get_alignment (element_type); + + pos = _DBUS_ALIGN_VALUE (pos, alignment); + + *(const DBusBasicValue**) value = (void*) _dbus_string_get_const_data_len (str, pos, array_len); + + *n_elements = array_len / alignment; + + if (new_pos) + *new_pos = pos + array_len; +} + static dbus_bool_t marshal_4_octets (DBusString *str, int insert_at, @@ -663,7 +714,7 @@ marshal_len_followed_by_bytes (int marshal_as, str, pos)) goto oom; -#if 1 +#if 0 /* too expensive */ _dbus_assert (_dbus_string_equal_substring (&value_str, 0, value_len, str, pos)); @@ -779,82 +830,83 @@ static dbus_bool_t marshal_1_octets_array (DBusString *str, int insert_at, const unsigned char *value, - int len, + int n_elements, int byte_order, int *pos_after) { return marshal_len_followed_by_bytes (MARSHAL_AS_BYTE_ARRAY, - str, insert_at, value, len, + str, insert_at, value, n_elements, byte_order, pos_after); } -static dbus_bool_t -marshal_4_octets_array (DBusString *str, - int insert_at, - const dbus_uint32_t *value, - int len, - int byte_order) +static void +swap_array (DBusString *str, + int array_start, + int n_elements, + int byte_order, + int alignment) { - int old_string_len; - int array_start; - - _dbus_assert_not_reached ("FIXME insert_at"); - - old_string_len = _dbus_string_get_length (str); - - if (!marshal_4_octets (str, insert_at, len*4, byte_order, NULL)) - goto error; - - array_start = _dbus_string_get_length (str); - - if (!_dbus_string_append_len (str, (const unsigned char*) value, - len * 4)) - goto error; + _dbus_assert (_DBUS_ALIGN_VALUE (array_start, alignment) == (unsigned) array_start); if (byte_order != DBUS_COMPILER_BYTE_ORDER) { - const unsigned char *d; - const unsigned char *end; + unsigned char *d; + unsigned char *end; - d = _dbus_string_get_data (str) + array_start; - end = d + len * 4; - while (d != end) + /* we use const_data and cast it off so DBusString can be a const string + * for the unit tests. don't ask. + */ + d = (unsigned char*) _dbus_string_get_const_data (str) + array_start; + end = d + n_elements * alignment; + + if (alignment == 8) { - *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d)); - d += 4; + while (d != end) + { +#ifdef DBUS_HAVE_INT64 + *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); +#else + swap_8_bytes ((DBusBasicValue*) d); +#endif + d += 8; + } } - } - - return TRUE; - - error: - /* Restore previous length */ - _dbus_string_set_length (str, old_string_len); + else + { + _dbus_assert (alignment == 4); - return FALSE; + while (d != end) + { + *((dbus_uint32_t*)d) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)d)); + d += 4; + } + } + } } static dbus_bool_t -marshal_8_octets_array (DBusString *str, - int insert_at, - const DBusBasicValue *value, - int len, - int byte_order) +marshal_fixed_array (DBusString *str, + int insert_at, + const DBusBasicValue *value, + int n_elements, + int byte_order, + int alignment, + int *pos_after) { int old_string_len; int array_start; - - _dbus_assert_not_reached ("FIXME insert_at"); + DBusString t; old_string_len = _dbus_string_get_length (str); /* The array length is the length in bytes of the array, * *excluding* alignment padding. */ - if (!marshal_4_octets (str, insert_at, len*8, byte_order, NULL)) + if (!marshal_4_octets (str, insert_at, n_elements * alignment, + byte_order, &array_start)) goto error; - array_start = _dbus_string_get_length (str); + _dbus_verbose ("marshaled len %d at %d array start %d\n", n_elements * alignment, insert_at, array_start); /* Note that we do alignment padding unconditionally * even if the array is empty; this means that @@ -862,62 +914,57 @@ marshal_8_octets_array (DBusString *str, * in the array. */ - if (!_dbus_string_align_length (str, 8)) + if (!_dbus_string_insert_alignment (str, &array_start, alignment)) goto error; - if (!_dbus_string_append_len (str, (const unsigned char*) value, - len * 8)) - goto error; + _dbus_string_init_const_len (&t, + (const unsigned char*) value, + n_elements * alignment); - if (byte_order != DBUS_COMPILER_BYTE_ORDER) - { - const unsigned char *d; - const unsigned char *end; + if (!_dbus_string_copy (&t, 0, + str, array_start)) + goto error; - d = _dbus_string_get_data (str) + array_start; - end = d + len * 8; - while (d != end) - { -#ifdef DBUS_HAVE_INT64 - *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d)); -#else - swap_8_bytes ((DBusBasicValue*) d); -#endif - d += 8; - } - } + swap_array (str, array_start, n_elements, byte_order, alignment); return TRUE; error: - /* Restore previous length */ - _dbus_string_set_length (str, old_string_len); + _dbus_string_delete (str, insert_at, + _dbus_string_get_length (str) - old_string_len); return FALSE; } /** - * Marshals a basic type array + * Marshals an array of values of fixed-length type. + * _dbus_type_is_fixed() returns #TRUE for these types, + * which are the basic types minus the string-like types. + * + * The value argument should be the adddress of an + * array, so e.g. "const dbus_uint32_t**" * * @param str string to marshal to * @param insert_at where to insert the value * @param element_type type of array elements - * @param value pointer to value - * @param len length of value data in elements + * @param value address of an array to marshal + * @param len number of elements in the array * @param byte_order byte order * @param pos_after #NULL or the position after the type * @returns #TRUE on success **/ dbus_bool_t -_dbus_marshal_write_basic_array (DBusString *str, +_dbus_marshal_write_fixed_array (DBusString *str, int insert_at, int element_type, const void *value, - int len, + int n_elements, int byte_order, int *pos_after) { - /* FIXME use the insert_at arg and fill in pos_after */ + const void* vp = *(const DBusBasicValue**)value; + + _dbus_assert (_dbus_type_is_fixed (element_type)); switch (element_type) { @@ -925,29 +972,20 @@ _dbus_marshal_write_basic_array (DBusString *str, /* FIXME: we canonicalize to 0 or 1 for the single boolean case * should we here too ? */ case DBUS_TYPE_BYTE: - return marshal_1_octets_array (str, insert_at, value, len, byte_order, pos_after); + return marshal_1_octets_array (str, insert_at, vp, n_elements, byte_order, pos_after); break; case DBUS_TYPE_INT32: case DBUS_TYPE_UINT32: - return marshal_4_octets_array (str, insert_at, value, len, byte_order); + return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 4, pos_after); break; case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: - return marshal_8_octets_array (str, insert_at, value, len, byte_order); - break; - - case DBUS_TYPE_STRING: - case DBUS_TYPE_OBJECT_PATH: - _dbus_assert_not_reached ("handle string arrays"); - break; - - case DBUS_TYPE_SIGNATURE: - _dbus_assert_not_reached ("handle signature"); + return marshal_fixed_array (str, insert_at, vp, n_elements, byte_order, 8, pos_after); break; default: - _dbus_assert_not_reached ("non basic type in array"); + _dbus_assert_not_reached ("non fixed type in array write"); break; } @@ -1173,10 +1211,10 @@ _dbus_type_is_basic (int typecode) * first byte of the old and new value would be in the same location, * so alignment padding is not a factor. * - * @returns #TRUE if the type can occupy different lengths + * @returns #FALSE if the type can occupy different lengths */ dbus_bool_t -_dbus_type_length_varies (int typecode) +_dbus_type_is_fixed (int typecode) { switch (typecode) { @@ -1187,9 +1225,9 @@ _dbus_type_length_varies (int typecode) case DBUS_TYPE_INT64: case DBUS_TYPE_UINT64: case DBUS_TYPE_DOUBLE: - return FALSE; - default: return TRUE; + default: + return FALSE; } } @@ -1257,6 +1295,16 @@ _dbus_verbose_bytes (const unsigned char *data, if (i > 7 && _DBUS_ALIGN_ADDRESS (&data[i], 8) == &data[i]) { +#ifdef DBUS_HAVE_INT64 + /* I think I probably mean "GNU libc printf" and not "GNUC" + * but we'll wait until someone complains. If you hit this, + * just turn off verbose mode as a workaround. + */ +#if __GNUC__ + _dbus_verbose (" u64: 0x%llx", + *(dbus_uint64_t*)&data[i-8]); +#endif +#endif _dbus_verbose (" dbl: %g", *(double*)&data[i-8]); } @@ -1312,6 +1360,17 @@ _dbus_verbose_bytes_of_string (const DBusString *str, #include "dbus-test.h" #include +static void +swap_test_array (void *array, + int len_bytes, + int byte_order, + int alignment) +{ + DBusString t; + _dbus_string_init_const_len (&t, array, len_bytes); + swap_array (&t, 0, len_bytes / alignment, byte_order, alignment); +} + #define MARSHAL_BASIC(typename, byte_order, literal) \ do { \ v_##typename = literal; \ @@ -1324,7 +1383,7 @@ _dbus_verbose_bytes_of_string (const DBusString *str, #define DEMARSHAL_BASIC(typename, byte_order) \ do { \ _dbus_marshal_read_basic (&str, pos, DBUS_TYPE_##typename, &v_##typename, \ - byte_order, &pos); \ + byte_order, &pos); \ } while (0) #define DEMARSHAL_BASIC_AND_CHECK(typename, byte_order, literal) \ @@ -1359,19 +1418,61 @@ _dbus_verbose_bytes_of_string (const DBusString *str, } \ } while (0) +#define MARSHAL_FIXED_ARRAY(typename, byte_order, literal) \ + do { \ + v_ARRAY_##typename = literal; \ + if (!_dbus_marshal_write_fixed_array (&str, pos, DBUS_TYPE_##typename, \ + &v_ARRAY_##typename, _DBUS_N_ELEMENTS(literal), \ + byte_order, NULL)) \ + _dbus_assert_not_reached ("no memory"); \ + } while (0) + +#define DEMARSHAL_FIXED_ARRAY(typename, byte_order) \ + do { \ + _dbus_marshal_read_fixed_array (&str, pos, DBUS_TYPE_##typename, &v_ARRAY_##typename, \ + &n_elements, byte_order, &pos); \ + swap_test_array (v_ARRAY_##typename, n_elements * sizeof(v_ARRAY_##typename[0]), \ + byte_order, sizeof(v_ARRAY_##typename[0])); \ + } while (0) + +#define DEMARSHAL_FIXED_ARRAY_AND_CHECK(typename, byte_order, literal) \ + do { \ + DEMARSHAL_FIXED_ARRAY (typename, byte_order); \ + if (memcmp (literal, v_ARRAY_##typename, sizeof (literal) != 0)) \ + { \ + _dbus_verbose ("MARSHALED DATA\n"); \ + _dbus_verbose_bytes_of_string (&str, dump_pos, \ + _dbus_string_get_length (&str) - dump_pos); \ + _dbus_verbose ("LITERAL DATA\n"); \ + _dbus_verbose_bytes ((char*)literal, sizeof (literal), 0); \ + _dbus_verbose ("READ DATA\n"); \ + _dbus_verbose_bytes ((char*)v_ARRAY_##typename, sizeof (literal), 0); \ + _dbus_assert_not_reached ("demarshaled wrong fixed array value"); \ + } \ + } while (0) + +#define MARSHAL_TEST_FIXED_ARRAY(typename, byte_order, literal) \ + do { \ + MARSHAL_FIXED_ARRAY (typename, byte_order, literal); \ + dump_pos = pos; \ + DEMARSHAL_FIXED_ARRAY_AND_CHECK (typename, byte_order, literal); \ + } while (0) + dbus_bool_t _dbus_marshal_test (void) { DBusString str; int pos, dump_pos; -#if 0 - dbus_int32_t array1[3] = { 0x123, 0x456, 0x789 }, *array2; + int n_elements; + dbus_int32_t array4[3] = { 123, 456, 789 }; #ifdef DBUS_HAVE_INT64 - dbus_int64_t array3[3] = { DBUS_INT64_CONSTANT (0x123ffffffff), + dbus_int64_t array8[3] = { DBUS_INT64_CONSTANT (0x123ffffffff), DBUS_INT64_CONSTANT (0x456ffffffff), - DBUS_INT64_CONSTANT (0x789ffffffff) }, *array4; -#endif + DBUS_INT64_CONSTANT (0x789ffffffff) }; + dbus_int64_t *v_ARRAY_INT64; #endif + dbus_int32_t *v_ARRAY_INT32; + double *v_ARRAY_DOUBLE; DBusString t; double v_DOUBLE; double t_DOUBLE; @@ -1448,6 +1549,15 @@ _dbus_marshal_test (void) MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_BIG_ENDIAN, "a(ii)"); MARSHAL_TEST_STRCMP (SIGNATURE, DBUS_LITTLE_ENDIAN, "a(ii)"); + /* Arrays */ + MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_BIG_ENDIAN, array4); + MARSHAL_TEST_FIXED_ARRAY (INT32, DBUS_LITTLE_ENDIAN, array4); + +#ifdef DBUS_HAVE_INT64 + MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_BIG_ENDIAN, array8); + MARSHAL_TEST_FIXED_ARRAY (INT64, DBUS_LITTLE_ENDIAN, array8); +#endif + #if 0 /* diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h index 529ada5d..bf75cbef 100644 --- a/dbus/dbus-marshal-basic.h +++ b/dbus/dbus-marshal-basic.h @@ -275,11 +275,11 @@ dbus_bool_t _dbus_marshal_write_basic (DBusString *str, const void *value, int byte_order, int *pos_after); -dbus_bool_t _dbus_marshal_write_basic_array (DBusString *str, +dbus_bool_t _dbus_marshal_write_fixed_array (DBusString *str, int insert_at, int element_type, const void *value, - int len, + int n_elements, int byte_order, int *pos_after); void _dbus_marshal_read_basic (const DBusString *str, @@ -288,6 +288,13 @@ void _dbus_marshal_read_basic (const DBusString *str, void *value, int byte_order, int *new_pos); +void _dbus_marshal_read_fixed_array (const DBusString *str, + int pos, + int element_type, + void *value, + int *n_elements, + int byte_order, + int *new_pos); void _dbus_marshal_skip_basic (const DBusString *str, int type, int byte_order, @@ -308,7 +315,7 @@ dbus_bool_t _dbus_type_is_valid (int typecode); int _dbus_type_get_alignment (int typecode); dbus_bool_t _dbus_type_is_basic (int typecode); dbus_bool_t _dbus_type_is_container (int typecode); -dbus_bool_t _dbus_type_length_varies (int typecode); +dbus_bool_t _dbus_type_is_fixed (int typecode); diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c index 58cab0c2..a3ef0217 100644 --- a/dbus/dbus-marshal-recursive.c +++ b/dbus/dbus-marshal-recursive.c @@ -764,14 +764,60 @@ _dbus_type_reader_read_basic (const DBusTypeReader *reader, #endif } -dbus_bool_t -_dbus_type_reader_read_array_of_basic (const DBusTypeReader *reader, - int type, - void **array, - int *array_len) +/** + * Reads an array of fixed-length basic values. Does not work for + * arrays of string or container types. + * + * This function returns the array in-place; it does not make a copy, + * and it does not swap the bytes. + * + * If you ask for #DBUS_TYPE_DOUBLE you will get a "const double*" back + * and the "value" argument should be a "const double**" and so on. + * + * @param reader the reader to read from + * @param value place to return the array + * @param n_elements place to return number of array elements + */ +void +_dbus_type_reader_read_fixed_array (const DBusTypeReader *reader, + void *value, + int *n_elements) { + int element_type; + int end_pos; + int remaining_len; + int alignment; + _dbus_assert (!reader->klass->types_only); + _dbus_assert (reader->klass == &array_reader_class); + + element_type = first_type_in_signature (reader->type_str, + reader->type_pos); + + _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */ + _dbus_assert (_dbus_type_is_fixed (element_type)); + + alignment = _dbus_type_get_alignment (element_type); + end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader); + remaining_len = end_pos - reader->value_pos; + + if (remaining_len == 0) + *(const DBusBasicValue**) value = NULL; + else + *(const DBusBasicValue**) value = + (void*) _dbus_string_get_const_data_len (reader->value_str, + reader->value_pos, + remaining_len); + + *n_elements = remaining_len / alignment; + _dbus_assert ((remaining_len % alignment) == 0); + +#if RECURSIVE_MARSHAL_TRACE + _dbus_verbose (" type reader %p read fixed array 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)); +#endif } /** @@ -925,7 +971,106 @@ _dbus_type_reader_get_signature (const DBusTypeReader *reader, *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos); } +typedef struct +{ + DBusString replacement; + int padding; +} ReplacementBlock; + +static dbus_bool_t +replacement_block_init (ReplacementBlock *block, + DBusTypeReader *reader) +{ + if (!_dbus_string_init (&block->replacement)) + return FALSE; + /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 - + * ALIGN_OFFSET is the padding to have the same align properties in + * our replacement string as we do at the position being replaced + */ + block->padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8); + _dbus_assert (block->padding >= 0); + + if (!_dbus_string_lengthen (&block->replacement, block->padding)) + goto oom; + + return TRUE; + + oom: + _dbus_string_free (&block->replacement); + return FALSE; +} + +static dbus_bool_t +replacement_block_replace (ReplacementBlock *block, + DBusTypeReader *reader, + const DBusTypeReader *realign_root) +{ + DBusTypeWriter writer; + DBusTypeReader realign_reader; + DBusList *fixups; + int orig_len; + + _dbus_assert (realign_root != NULL); + + orig_len = _dbus_string_get_length (&block->replacement); + + realign_reader = *realign_root; + + _dbus_type_writer_init_values_only (&writer, + realign_reader.byte_order, + realign_reader.type_str, + realign_reader.type_pos, + &block->replacement, + _dbus_string_get_length (&block->replacement)); + + fixups = NULL; + if (!_dbus_type_writer_write_reader_partial (&writer, + &realign_reader, + reader, + block->padding, + _dbus_string_get_length (&block->replacement) - block->padding, + &fixups)) + goto oom; + +#if RECURSIVE_MARSHAL_TRACE + _dbus_verbose ("REPLACEMENT at padding %d len %d\n", padding, + _dbus_string_get_length (&block->replacement) - padding); + _dbus_verbose_bytes_of_string (&block->replacement, padding, + _dbus_string_get_length (&block->replacement) - padding); + _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d\n", + reader->value_pos, (int) (8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8)), + realign_reader.value_pos - reader->value_pos); + _dbus_verbose_bytes_of_string (reader->value_str, + reader->value_pos, + realign_reader.value_pos - reader->value_pos); +#endif + + /* Move the replacement into position + * (realign_reader should now be at the end of the block to be replaced) + */ + if (!_dbus_string_replace_len (&block->replacement, block->padding, + _dbus_string_get_length (&block->replacement) - block->padding, + (DBusString*) reader->value_str, + reader->value_pos, + realign_reader.value_pos - reader->value_pos)) + goto oom; + + /* Process our fixups now that we can't have an OOM error */ + apply_and_free_fixups (&fixups, reader); + + return TRUE; + + oom: + _dbus_string_set_length (&block->replacement, orig_len); + return FALSE; +} + +static void +replacement_block_free (ReplacementBlock *block) +{ + _dbus_string_free (&block->replacement); +} /* In the variable-length case, we have to fix alignment after we insert. * The strategy is as follows: @@ -957,92 +1102,37 @@ reader_set_basic_variable_length (DBusTypeReader *reader, const DBusTypeReader *realign_root) { dbus_bool_t retval; - DBusString replacement; - int padding; + ReplacementBlock block; DBusTypeWriter writer; - DBusTypeReader realign_reader; - DBusList *fixups; _dbus_assert (realign_root != NULL); retval = FALSE; - if (!_dbus_string_init (&replacement)) + if (!replacement_block_init (&block, reader)) return FALSE; - /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 - - * ALIGN_OFFSET is the padding to have the same align properties in - * our replacement string as we do at the position being replaced - */ - padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8); - _dbus_assert (padding >= 0); - - if (!_dbus_string_lengthen (&replacement, padding)) - goto out; - /* Write the new basic value */ _dbus_type_writer_init_values_only (&writer, reader->byte_order, reader->type_str, reader->type_pos, - &replacement, - _dbus_string_get_length (&replacement)); + &block.replacement, + _dbus_string_get_length (&block.replacement)); if (!_dbus_type_writer_write_basic (&writer, current_type, value)) goto out; - /* Rewrite the values following the new basic value, which should - * fix their alignment - */ - realign_reader = *realign_root; - - _dbus_type_writer_init_values_only (&writer, - realign_reader.byte_order, - realign_reader.type_str, - realign_reader.type_pos, - &replacement, - _dbus_string_get_length (&replacement)); - - fixups = NULL; - if (!_dbus_type_writer_write_reader_partial (&writer, - &realign_reader, - reader, - padding, - _dbus_string_get_length (&replacement) - padding, - &fixups)) + if (!replacement_block_replace (&block, + reader, + realign_root)) goto out; -#if RECURSIVE_MARSHAL_TRACE - _dbus_verbose ("REPLACEMENT at padding %d len %d\n", padding, - _dbus_string_get_length (&replacement) - padding); - _dbus_verbose_bytes_of_string (&replacement, padding, - _dbus_string_get_length (&replacement) - padding); - _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d\n", - reader->value_pos, (int) (8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8)), - realign_reader.value_pos - reader->value_pos); - _dbus_verbose_bytes_of_string (reader->value_str, - reader->value_pos, - realign_reader.value_pos - reader->value_pos); -#endif - - /* Move the replacement into position - * (realign_reader should now be at the end of the block to be replaced) - */ - if (!_dbus_string_replace_len (&replacement, padding, - _dbus_string_get_length (&replacement) - padding, - (DBusString*) reader->value_str, - reader->value_pos, - realign_reader.value_pos - reader->value_pos)) - goto out; - - /* Process our fixups now that we can't have an OOM error */ - apply_and_free_fixups (&fixups, reader); - retval = TRUE; out: - _dbus_string_free (&replacement); + replacement_block_free (&block); return retval; } @@ -1060,10 +1150,10 @@ reader_set_basic_fixed_length (DBusTypeReader *reader, } /** - * Sets a new value for the basic type pointed to by the reader, - * leaving the reader valid to continue reading. Any other readers may - * of course be invalidated if you set a variable-length type such as - * a string. + * Sets a new value for the basic type value pointed to by the reader, + * leaving the reader valid to continue reading. Any other readers + * will be invalidated if you set a variable-length type such as a + * string. * * The provided realign_root is the reader to start from when * realigning the data that follows the newly-set value. The reader @@ -1084,6 +1174,10 @@ reader_set_basic_fixed_length (DBusTypeReader *reader, * DBusTypeMark. But since DBusMessage is effectively that object for * D-BUS it doesn't seem worth creating some random object.) * + * @todo optimize this by only rewriting until the old and new values + * are at the same alignment. Frequently this should result in only + * replacing the value that's immediately at hand. + * * @param reader reader indicating where to set a new value * @param value address of the value to set * @param realign_root realign from here @@ -1096,6 +1190,8 @@ _dbus_type_reader_set_basic (DBusTypeReader *reader, { int current_type; + _dbus_assert (!reader->klass->types_only); + current_type = _dbus_type_reader_get_current_type (reader); #if RECURSIVE_MARSHAL_TRACE @@ -1109,19 +1205,63 @@ _dbus_type_reader_set_basic (DBusTypeReader *reader, _dbus_assert (_dbus_type_is_basic (current_type)); - if (_dbus_type_length_varies (current_type)) + if (_dbus_type_is_fixed (current_type)) { - _dbus_assert (realign_root != NULL); - return reader_set_basic_variable_length (reader, current_type, - value, realign_root); + reader_set_basic_fixed_length (reader, current_type, value); + return TRUE; } else { - reader_set_basic_fixed_length (reader, current_type, value); - return TRUE; + _dbus_assert (realign_root != NULL); + return reader_set_basic_variable_length (reader, current_type, + value, realign_root); } } +/** + * Recursively deletes any value pointed to by the reader, leaving the + * reader valid to continue reading. Any other readers will be + * invalidated. + * + * The provided realign_root is the reader to start from when + * realigning the data that follows the newly-set value. + * See _dbus_type_reader_set_basic() for more details on the + * realign_root paramter. + * + * @todo for now this does not delete the typecodes associated with + * the value, so this function should only be used for array elements. + * + * @param reader reader indicating where to delete a value + * @param realign_root realign from here + * @returns #FALSE if not enough memory + */ +dbus_bool_t +_dbus_type_reader_delete (DBusTypeReader *reader, + const DBusTypeReader *realign_root) +{ + dbus_bool_t retval; + ReplacementBlock block; + + _dbus_assert (realign_root != NULL); + _dbus_assert (reader->klass == &array_reader_class); + + retval = FALSE; + + if (!replacement_block_init (&block, reader)) + return FALSE; + + if (!replacement_block_replace (&block, + reader, + realign_root)) + goto out; + + retval = TRUE; + + out: + replacement_block_free (&block); + return retval; +} + /** * Compares two readers, which must be iterating over the same value data. * Returns #TRUE if the first parameter is further along than the second parameter. @@ -1844,14 +1984,50 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer, return retval; } +/** + * Writes an array of fixed-length basic values, i.e. those that + * are both _dbus_type_is_fixed() and _dbus_type_is_basic(). + * + * The value parameter should be the address of said array of values, + * so e.g. if it's an array of double, pass in "const double**" + * + * @param writer the writer + * @param element_type type of stuff in the array + * @param value address of the array + * @param n_elements number of elements in the array + * @returns #FALSE if no memory + */ dbus_bool_t -_dbus_type_writer_write_array (DBusTypeWriter *writer, - int type, - const void *array, - int array_len) +_dbus_type_writer_write_fixed_array (DBusTypeWriter *writer, + int element_type, + const void *value, + int n_elements) { + _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY); + _dbus_assert (_dbus_type_is_fixed (element_type)); + _dbus_assert (writer->type_pos_is_expectation); + + if (!write_or_verify_typecode (writer, element_type)) + _dbus_assert_not_reached ("OOM should not happen if only verifying typecode"); + + if (writer->enabled) + { + if (!_dbus_marshal_write_fixed_array (writer->value_str, + writer->value_pos, + element_type, + value, + n_elements, + writer->byte_order, + &writer->value_pos)) + return FALSE; + } +#if RECURSIVE_MARSHAL_TRACE + _dbus_verbose (" type writer %p fixed array type_pos = %d value_pos = %d\n", + writer, writer->type_pos, writer->value_pos); +#endif + return TRUE; } static void diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h index 025c3e04..765ee56b 100644 --- a/dbus/dbus-marshal-recursive.h +++ b/dbus/dbus-marshal-recursive.h @@ -151,10 +151,9 @@ int _dbus_type_reader_get_current_type (const DBusTypeReader * dbus_bool_t _dbus_type_reader_array_is_empty (const DBusTypeReader *reader); void _dbus_type_reader_read_basic (const DBusTypeReader *reader, void *value); -dbus_bool_t _dbus_type_reader_read_array_of_basic (const DBusTypeReader *reader, - int type, - void **array, - int *array_len); +void _dbus_type_reader_read_fixed_array (const DBusTypeReader *reader, + void *value, + int *n_elements); void _dbus_type_reader_recurse (DBusTypeReader *reader, DBusTypeReader *subreader); dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader); @@ -166,6 +165,8 @@ void _dbus_type_reader_get_signature (const DBusTypeReader * dbus_bool_t _dbus_type_reader_set_basic (DBusTypeReader *reader, const void *value, const DBusTypeReader *realign_root); +dbus_bool_t _dbus_type_reader_delete (DBusTypeReader *reader, + const DBusTypeReader *realign_root); dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs, const DBusTypeReader *rhs); @@ -184,10 +185,10 @@ void _dbus_type_writer_init_values_only (DBusTypeWriter *write 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_write_fixed_array (DBusTypeWriter *writer, + int element_type, + const void *value, + int n_elements); dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer, int container_type, const DBusString *contained_type, -- cgit