1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c Marshalling routines for recursive types
4 * Copyright (C) 2004, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-marshal-recursive.h"
25 #include "dbus-marshal-basic.h"
26 #include "dbus-internals.h"
29 * @addtogroup DBusMarshal
32 #define RECURSIVE_MARSHAL_TRACE 1
34 struct DBusTypeReaderClass
37 int id; /* index in all_reader_classes */
38 dbus_bool_t types_only; /* only iterates over types, not values */
39 void (* recurse) (DBusTypeReader *sub,
40 DBusTypeReader *parent);
41 dbus_bool_t (* check_finished) (const DBusTypeReader *reader);
42 void (* next) (DBusTypeReader *reader,
44 void (* init_from_mark) (DBusTypeReader *reader,
45 const DBusTypeMark *mark);
49 first_type_in_signature (const DBusString *str,
54 t = _dbus_string_get_byte (str, pos);
56 if (t == DBUS_STRUCT_BEGIN_CHAR)
57 return DBUS_TYPE_STRUCT;
63 element_type_get_alignment (const DBusString *str,
66 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
70 reader_init (DBusTypeReader *reader,
72 const DBusString *type_str,
74 const DBusString *value_str,
77 reader->byte_order = byte_order;
78 reader->finished = FALSE;
79 reader->type_str = type_str;
80 reader->type_pos = type_pos;
81 reader->value_str = value_str;
82 reader->value_pos = value_pos;
86 base_reader_recurse (DBusTypeReader *sub,
87 DBusTypeReader *parent)
89 /* point subreader at the same place as parent */
99 struct_types_only_reader_recurse (DBusTypeReader *sub,
100 DBusTypeReader *parent)
102 base_reader_recurse (sub, parent);
104 _dbus_assert (_dbus_string_get_byte (sub->type_str,
105 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
111 struct_reader_recurse (DBusTypeReader *sub,
112 DBusTypeReader *parent)
114 struct_types_only_reader_recurse (sub, parent);
116 /* struct has 8 byte alignment */
117 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
121 array_types_only_reader_recurse (DBusTypeReader *sub,
122 DBusTypeReader *parent)
124 base_reader_recurse (sub, parent);
126 /* point type_pos at the array element type */
129 /* Init with values likely to crash things if misused */
130 sub->u.array.start_pos = _DBUS_INT_MAX;
131 sub->array_len_offset = 7;
135 array_reader_get_array_len (const DBusTypeReader *reader)
137 dbus_uint32_t array_len;
140 /* array_len_offset is the offset back from start_pos to end of the len */
141 len_pos = reader->u.array.start_pos - ((int)reader->array_len_offset) - 4;
143 _dbus_marshal_read_basic (reader->value_str,
150 _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n",
151 reader, len_pos, array_len, reader->array_len_offset);
153 _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
159 array_reader_recurse (DBusTypeReader *sub,
160 DBusTypeReader *parent)
165 array_types_only_reader_recurse (sub, parent);
167 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
169 len_pos = sub->value_pos;
171 sub->value_pos += 4; /* for the length */
173 alignment = element_type_get_alignment (sub->type_str,
176 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
178 sub->u.array.start_pos = sub->value_pos;
179 _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
180 sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
182 #if RECURSIVE_MARSHAL_TRACE
183 _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
185 sub->u.array.start_pos,
186 sub->array_len_offset,
187 array_reader_get_array_len (sub),
188 _dbus_type_to_string (first_type_in_signature (sub->type_str,
194 variant_reader_recurse (DBusTypeReader *sub,
195 DBusTypeReader *parent)
199 base_reader_recurse (sub, parent);
201 /* Variant is 1 byte sig length (without nul), signature with nul,
202 * padding to 8-boundary, then values
205 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
207 sub->type_str = sub->value_str;
208 sub->type_pos = sub->value_pos + 1;
210 sub->value_pos = sub->type_pos + sig_len + 1;
212 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
214 #if RECURSIVE_MARSHAL_TRACE
215 _dbus_verbose (" type reader %p variant containing '%s'\n",
217 _dbus_string_get_const_data_len (sub->type_str,
223 array_reader_check_finished (const DBusTypeReader *reader)
227 /* return the array element type if elements remain, and
228 * TYPE_INVALID otherwise
231 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
233 _dbus_assert (reader->value_pos <= end_pos);
234 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
236 return reader->value_pos == end_pos;
240 skip_one_complete_type (const DBusString *type_str,
243 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
246 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
253 switch (_dbus_string_get_byte (type_str, *type_pos))
255 case DBUS_STRUCT_BEGIN_CHAR:
258 case DBUS_STRUCT_END_CHAR:
261 case DBUS_TYPE_INVALID:
262 _dbus_assert_not_reached ("unbalanced parens in signature");
273 find_len_of_complete_type (const DBusString *type_str,
280 skip_one_complete_type (type_str, &end);
282 return end - type_pos;
286 base_reader_next (DBusTypeReader *reader,
289 switch (current_type)
291 case DBUS_TYPE_STRUCT:
292 case DBUS_TYPE_VARIANT:
293 /* Scan forward over the entire container contents */
297 /* Recurse into the struct or variant */
298 _dbus_type_reader_recurse (reader, &sub);
300 /* Skip everything in this subreader */
301 while (_dbus_type_reader_next (&sub))
306 /* Now we are at the end of this container; for variants, the
307 * subreader's type_pos is totally inapplicable (it's in the
308 * value string) but we know that we increment by one past the
311 if (current_type == DBUS_TYPE_VARIANT)
312 reader->type_pos += 1;
314 reader->type_pos = sub.type_pos;
316 if (!reader->klass->types_only)
317 reader->value_pos = sub.value_pos;
321 case DBUS_TYPE_ARRAY:
323 if (!reader->klass->types_only)
324 _dbus_marshal_skip_array (reader->value_str,
325 first_type_in_signature (reader->type_str,
326 reader->type_pos + 1),
330 skip_one_complete_type (reader->type_str, &reader->type_pos);
335 if (!reader->klass->types_only)
336 _dbus_marshal_skip_basic (reader->value_str,
337 current_type, reader->byte_order,
340 reader->type_pos += 1;
346 struct_reader_next (DBusTypeReader *reader,
351 base_reader_next (reader, current_type);
353 /* for STRUCT containers we return FALSE at the end of the struct,
354 * for INVALID we return FALSE at the end of the signature.
355 * In both cases we arrange for get_current_type() to return INVALID
356 * which is defined to happen iff we're at the end (no more next())
358 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
359 if (t == DBUS_STRUCT_END_CHAR)
361 reader->type_pos += 1;
362 reader->finished = TRUE;
367 array_types_only_reader_next (DBusTypeReader *reader,
370 /* We have one "element" to be iterated over
371 * in each array, which is its element type.
372 * So the finished flag indicates whether we've
373 * iterated over it yet or not.
375 reader->finished = TRUE;
379 array_reader_next (DBusTypeReader *reader,
382 /* Skip one array element */
385 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
387 _dbus_assert (reader->value_pos < end_pos);
388 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
390 switch (first_type_in_signature (reader->type_str,
393 case DBUS_TYPE_STRUCT:
394 case DBUS_TYPE_VARIANT:
398 /* Recurse into the struct or variant */
399 _dbus_type_reader_recurse (reader, &sub);
401 /* Skip everything in this element */
402 while (_dbus_type_reader_next (&sub))
407 /* Now we are at the end of this element */
408 reader->value_pos = sub.value_pos;
412 case DBUS_TYPE_ARRAY:
414 _dbus_marshal_skip_array (reader->value_str,
415 first_type_in_signature (reader->type_str,
416 reader->type_pos + 1),
424 _dbus_marshal_skip_basic (reader->value_str,
425 current_type, reader->byte_order,
431 _dbus_assert (reader->value_pos <= end_pos);
433 if (reader->value_pos == end_pos)
435 skip_one_complete_type (reader->type_str,
441 array_init_from_mark (DBusTypeReader *reader,
442 const DBusTypeMark *mark)
444 /* Fill in the array-specific fields from the mark. The general
445 * fields are already filled in.
447 reader->u.array.start_pos = mark->array_start_pos;
448 reader->array_len_offset = mark->array_len_offset;
451 static const DBusTypeReaderClass body_reader_class = {
454 NULL, /* body is always toplevel, so doesn't get recursed into */
460 static const DBusTypeReaderClass body_types_only_reader_class = {
463 NULL, /* body is always toplevel, so doesn't get recursed into */
469 static const DBusTypeReaderClass struct_reader_class = {
472 struct_reader_recurse,
478 static const DBusTypeReaderClass struct_types_only_reader_class = {
481 struct_types_only_reader_recurse,
487 static const DBusTypeReaderClass array_reader_class = {
490 array_reader_recurse,
491 array_reader_check_finished,
496 static const DBusTypeReaderClass array_types_only_reader_class = {
499 array_types_only_reader_recurse,
501 array_types_only_reader_next,
505 static const DBusTypeReaderClass variant_reader_class = {
508 variant_reader_recurse,
514 static const DBusTypeReaderClass const *
515 all_reader_classes[] = {
517 &body_types_only_reader_class,
518 &struct_reader_class,
519 &struct_types_only_reader_class,
521 &array_types_only_reader_class,
522 &variant_reader_class
526 _dbus_type_reader_init (DBusTypeReader *reader,
528 const DBusString *type_str,
530 const DBusString *value_str,
533 reader->klass = &body_reader_class;
535 reader_init (reader, byte_order, type_str, type_pos,
536 value_str, value_pos);
538 #if RECURSIVE_MARSHAL_TRACE
539 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
540 reader, reader->type_pos, reader->value_pos,
541 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
546 _dbus_type_reader_init_from_mark (DBusTypeReader *reader,
548 const DBusString *type_str,
549 const DBusString *value_str,
550 const DBusTypeMark *mark)
552 reader->klass = all_reader_classes[mark->container_type];
554 reader_init (reader, byte_order,
555 mark->type_pos_in_value_str ? value_str : type_str,
557 value_str, mark->value_pos);
559 if (reader->klass->init_from_mark)
560 (* reader->klass->init_from_mark) (reader, mark);
562 #if RECURSIVE_MARSHAL_TRACE
563 _dbus_verbose (" type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",
564 reader, reader->type_pos, reader->value_pos,
565 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
570 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
571 const DBusString *type_str,
574 reader->klass = &body_types_only_reader_class;
576 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
577 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
579 #if RECURSIVE_MARSHAL_TRACE
580 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
581 reader, reader->type_pos,
582 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
587 _dbus_type_reader_init_types_only_from_mark (DBusTypeReader *reader,
588 const DBusString *type_str,
589 const DBusTypeMark *mark)
591 reader->klass = all_reader_classes[mark->container_type];
592 _dbus_assert (reader->klass->types_only);
593 _dbus_assert (!mark->type_pos_in_value_str);
595 reader_init (reader, DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
596 type_str, mark->type_pos,
597 NULL, _DBUS_INT_MAX /* crashes if we screw up */);
599 if (reader->klass->init_from_mark)
600 (* reader->klass->init_from_mark) (reader, mark);
602 #if RECURSIVE_MARSHAL_TRACE
603 _dbus_verbose (" type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",
604 reader, reader->type_pos,
605 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
610 _dbus_type_reader_save_mark (const DBusTypeReader *reader,
613 mark->type_pos_in_value_str = (reader->type_str == reader->value_str);
614 mark->container_type = reader->klass->id;
615 _dbus_assert (all_reader_classes[reader->klass->id] == reader->klass);
617 mark->type_pos = reader->type_pos;
618 mark->value_pos = reader->value_pos;
620 /* these are just junk if the reader isn't really an array of course */
621 mark->array_len_offset = reader->array_len_offset;
622 mark->array_start_pos = reader->u.array.start_pos;
626 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
630 if (reader->finished ||
631 (reader->klass->check_finished &&
632 (* reader->klass->check_finished) (reader)))
633 t = DBUS_TYPE_INVALID;
635 t = first_type_in_signature (reader->type_str,
638 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
639 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
642 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
643 reader, reader->type_pos,
644 _dbus_type_to_string (t));
651 _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)
653 dbus_uint32_t array_len;
655 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
656 _dbus_assert (!reader->klass->types_only);
658 /* reader is supposed to be at an array child */
659 #if RECURSIVE_MARSHAL_TRACE
660 _dbus_verbose ("checking array len at %d\n", reader->value_pos);
663 _dbus_marshal_read_basic (reader->value_str,
669 #if RECURSIVE_MARSHAL_TRACE
670 _dbus_verbose (" ... array len = %d\n", array_len);
673 return array_len == 0;
677 _dbus_type_reader_read_basic (const DBusTypeReader *reader,
682 _dbus_assert (!reader->klass->types_only);
684 t = _dbus_type_reader_get_current_type (reader);
686 _dbus_marshal_read_basic (reader->value_str,
693 #if RECURSIVE_MARSHAL_TRACE
694 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
695 reader, reader->type_pos, reader->value_pos,
696 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
701 _dbus_type_reader_read_array_of_basic (const DBusTypeReader *reader,
706 _dbus_assert (!reader->klass->types_only);
711 * Initialize a new reader pointing to the first type and
712 * corresponding value that's a child of the current container. It's
713 * an error to call this if the current type is a non-container.
715 * Note that DBusTypeReader traverses values, not types. So if you
716 * have an empty array of array of int, you can't recurse into it. You
717 * can only recurse into each element.
719 * @param reader the reader
720 * @param sub a reader to init pointing to the first child
723 _dbus_type_reader_recurse (DBusTypeReader *reader,
728 t = first_type_in_signature (reader->type_str, reader->type_pos);
732 case DBUS_TYPE_STRUCT:
733 if (reader->klass->types_only)
734 sub->klass = &struct_types_only_reader_class;
736 sub->klass = &struct_reader_class;
738 case DBUS_TYPE_ARRAY:
739 if (reader->klass->types_only)
740 sub->klass = &array_types_only_reader_class;
742 sub->klass = &array_reader_class;
744 case DBUS_TYPE_VARIANT:
745 if (reader->klass->types_only)
746 _dbus_assert_not_reached ("can't recurse into variant typecode");
748 sub->klass = &variant_reader_class;
751 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
752 #ifndef DBUS_DISABLE_CHECKS
753 if (t == DBUS_TYPE_INVALID)
754 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
755 #endif /* DBUS_DISABLE_CHECKS */
757 _dbus_assert_not_reached ("don't yet handle recursing into this type");
760 _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
762 (* sub->klass->recurse) (sub, reader);
764 #if RECURSIVE_MARSHAL_TRACE
765 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
766 sub, sub->type_pos, sub->value_pos,
767 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
772 * Skip to the next value on this "level". e.g. the next field in a
773 * struct, the next value in an array. Returns FALSE at the end of the
776 * @param reader the reader
777 * @returns FALSE if nothing more to read at or below this level
780 _dbus_type_reader_next (DBusTypeReader *reader)
784 t = _dbus_type_reader_get_current_type (reader);
786 #if RECURSIVE_MARSHAL_TRACE
787 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
788 reader, reader->type_pos, reader->value_pos,
789 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
790 _dbus_type_to_string (t));
793 if (t == DBUS_TYPE_INVALID)
796 (* reader->klass->next) (reader, t);
798 #if RECURSIVE_MARSHAL_TRACE
799 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
800 reader, reader->type_pos, reader->value_pos,
801 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
802 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
805 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
809 * Check whether there's another value on this "level". e.g. the next
810 * field in a struct, the next value in an array. Returns FALSE at the
811 * end of the current container.
813 * You probably don't want to use this; it makes for an awkward for/while
814 * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)"
816 * @param reader the reader
817 * @returns FALSE if nothing more to read at or below this level
820 _dbus_type_reader_has_next (const DBusTypeReader *reader)
822 /* Not efficient but works for now. */
826 return _dbus_type_reader_next (©);
830 * Gets the string and range of said string containing the signature
831 * of the current value. Essentially a more complete version of
832 * _dbus_type_reader_get_current_type() (returns the full type
833 * rather than only the outside of the onion).
835 * Note though that the first byte in a struct signature is
836 * #DBUS_STRUCT_BEGIN_CHAR while the current type will be
837 * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the
838 * signature is always the same as the current type. Another
839 * difference is that this function will still return a signature when
840 * inside an empty array; say you recurse into empty array of int32,
841 * the signature is "i" but the current type will always be
842 * #DBUS_TYPE_INVALID since there are no elements to be currently
845 * @param reader the reader
846 * @param str_p place to return the string with the type in it
847 * @param start_p place to return start of the type
848 * @param len_p place to return the length of the type
851 _dbus_type_reader_get_signature (const DBusTypeReader *reader,
852 const DBusString **str_p,
856 *str_p = reader->type_str;
857 *start_p = reader->type_pos;
858 *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
862 /* In the variable-length case, we have to fix alignment after we insert.
863 * The strategy is as follows:
865 * - pad a new string to have the same alignment as the
866 * start of the current basic value
867 * - write the new basic value
868 * - copy from the original reader to the new string,
869 * which will fix the alignment of types following
871 * - this copy has to start at realign_root,
872 * but not really write anything until it
873 * passes the value being set
874 * - as an optimization, we can stop copying
875 * when the source and dest values are both
876 * on an 8-boundary, since we know all following
877 * padding and alignment will be identical
878 * - copy the new string back to the original
879 * string, replacing the relevant part of the
883 reader_set_basic_variable_length (DBusTypeReader *reader,
886 const DBusTypeReader *realign_root)
889 DBusString replacement;
891 DBusTypeWriter writer;
892 DBusTypeReader realign_reader;
894 _dbus_assert (realign_root != NULL);
898 if (!_dbus_string_init (&replacement))
901 /* ALIGN_OFFSET is the offset to add to get to an 8-boundary; so 8 -
902 * ALIGN_OFFSET is the padding to have the same align properties in
903 * our replacement string as we do at the position being replaced
905 padding = 8 - _DBUS_ALIGN_OFFSET (reader->value_pos, 8);
906 _dbus_assert (padding >= 0);
908 if (!_dbus_string_lengthen (&replacement, padding))
911 /* Write the new basic value */
913 _dbus_type_writer_init_values_only (&writer,
918 _dbus_string_get_length (&replacement));
920 if (!_dbus_type_writer_write_basic (&writer, current_type, value))
923 /* Rewrite the values following the new basic value, which should
924 * fix their alignment
926 realign_reader = *realign_root;
928 _dbus_type_writer_init_values_only (&writer,
929 realign_reader.byte_order,
930 realign_reader.type_str,
931 realign_reader.type_pos,
933 _dbus_string_get_length (&replacement));
935 if (!_dbus_type_writer_write_reader (&writer,
940 /* Move the replacement into position
941 * (realign_reader should now be at the end of the block to be replaced)
943 if (!_dbus_string_replace_len (&replacement, padding,
944 _dbus_string_get_length (&replacement) - padding,
945 (DBusString*) reader->value_str,
947 realign_reader.value_pos - reader->value_pos))
953 _dbus_string_free (&replacement);
958 reader_set_basic_fixed_length (DBusTypeReader *reader,
962 _dbus_marshal_set_basic ((DBusString*) reader->value_str,
971 * Sets a new value for the basic type pointed to by the reader,
972 * leaving the reader valid to continue reading. Any other readers may
973 * of course be invalidated if you set a variable-length type such as
976 * The provided realign_root is the reader to start from when
977 * realigning the data that follows the newly-set value. The reader
978 * parameter must point to a value below the realign_root parameter.
979 * If the type being set is fixed-length, then realign_root may be
980 * #NULL. Only values reachable from realign_root will be realigned,
981 * so if your string contains other values you will need to deal with
982 * those somehow yourself. It is OK if realign_root is the same
983 * reader as the reader parameter, though if you aren't setting the
984 * root it may not be such a good idea.
986 * @todo DBusTypeReader currently takes "const" versions of the type
987 * and value strings, and this function modifies those strings by
988 * casting away the const, which is of course bad if we want to get
989 * picky. (To be truly clean you'd have an object which contained the
990 * type and value strings and set_basic would be a method on that
991 * object... this would also make DBusTypeReader the same thing as
992 * DBusTypeMark. But since DBusMessage is effectively that object for
993 * D-BUS it doesn't seem worth creating some random object.)
995 * @param reader reader indicating where to set a new value
996 * @param value address of the value to set
997 * @param realign_root realign from here
998 * @returns #FALSE if not enough memory
1001 _dbus_type_reader_set_basic (DBusTypeReader *reader,
1003 const DBusTypeReader *realign_root)
1007 current_type = _dbus_type_reader_get_current_type (reader);
1009 _dbus_assert (_dbus_type_is_basic (current_type));
1011 if (_dbus_type_length_varies (current_type))
1013 _dbus_assert (realign_root != NULL);
1014 return reader_set_basic_variable_length (reader, current_type,
1015 value, realign_root);
1019 reader_set_basic_fixed_length (reader, current_type, value);
1025 * Compares two readers, which must be iterating over the same value data.
1026 * Returns #TRUE if the first parameter is further along than the second parameter.
1028 * @param lhs left-hand-side (first) parameter
1029 * @param rhs left-hand-side (first) parameter
1030 * @returns whether lhs is greater than rhs
1033 _dbus_type_reader_greater_than (const DBusTypeReader *lhs,
1034 const DBusTypeReader *rhs)
1036 _dbus_assert (lhs->value_str == rhs->value_str);
1038 return lhs->value_pos > rhs->value_pos;
1051 * Initialize a write iterator, which is used to write out values in
1052 * serialized D-BUS format.
1054 * The type_pos passed in is expected to be inside an already-valid,
1055 * though potentially empty, type signature. This means that the byte
1056 * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
1057 * other valid type. #DBusTypeWriter won't enforce that the signature
1058 * is already valid (you can append the nul byte at the end if you
1059 * like), but just be aware that you need the nul byte eventually and
1060 * #DBusTypeWriter isn't going to write it for you.
1062 * @param writer the writer to init
1063 * @param byte_order the byte order to marshal into
1064 * @param type_str the string to write typecodes into
1065 * @param type_pos where to insert typecodes
1066 * @param value_str the string to write values into
1067 * @param value_pos where to insert values
1071 _dbus_type_writer_init (DBusTypeWriter *writer,
1073 DBusString *type_str,
1075 DBusString *value_str,
1078 writer->byte_order = byte_order;
1079 writer->type_str = type_str;
1080 writer->type_pos = type_pos;
1081 writer->value_str = value_str;
1082 writer->value_pos = value_pos;
1083 writer->container_type = DBUS_TYPE_INVALID;
1084 writer->type_pos_is_expectation = FALSE;
1085 writer->enabled = TRUE;
1087 #if RECURSIVE_MARSHAL_TRACE
1088 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
1090 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1096 * Like _dbus_type_writer_init(), except the type string
1097 * passed in should correspond to an existing signature that
1098 * matches what you're going to write out. The writer will
1099 * check what you write vs. this existing signature.
1101 * @param writer the writer to init
1102 * @param byte_order the byte order to marshal into
1103 * @param type_str the string with signature
1104 * @param type_pos start of signature
1105 * @param value_str the string to write values into
1106 * @param value_pos where to insert values
1110 _dbus_type_writer_init_values_only (DBusTypeWriter *writer,
1112 const DBusString *type_str,
1114 DBusString *value_str,
1117 _dbus_type_writer_init (writer, byte_order,
1118 (DBusString*)type_str, type_pos,
1119 value_str, value_pos);
1121 writer->type_pos_is_expectation = TRUE;
1125 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
1129 if (writer->enabled)
1130 return _dbus_marshal_write_basic (writer->value_str,
1135 &writer->value_pos);
1140 /* If our parent is an array, things are a little bit complicated.
1142 * The parent must have a complete element type, such as
1143 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
1144 * unclosed parens, or an "a" with no following type.
1146 * To recurse, the only allowed operation is to recurse into the
1147 * first type in the element type. So for "i" you can't recurse, for
1148 * "ai" you can recurse into the array, for "(ii)" you can recurse
1151 * If you recurse into the array for "ai", then you must specify
1152 * "i" for the element type of the array you recurse into.
1154 * While inside an array at any level, we need to avoid writing to
1155 * type_str, since the type only appears once for the whole array,
1156 * it does not appear for each array element.
1158 * While inside an array type_pos points to the expected next
1159 * typecode, rather than the next place we could write a typecode.
1162 writer_recurse_init_and_check (DBusTypeWriter *writer,
1164 DBusTypeWriter *sub)
1166 _dbus_type_writer_init (sub,
1173 sub->container_type = container_type;
1175 if (writer->type_pos_is_expectation ||
1176 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
1177 sub->type_pos_is_expectation = TRUE;
1179 sub->type_pos_is_expectation = FALSE;
1181 sub->enabled = writer->enabled;
1183 #ifndef DBUS_DISABLE_CHECKS
1184 if (writer->type_pos_is_expectation && writer->type_str)
1188 expected = first_type_in_signature (writer->type_str, writer->type_pos);
1190 if (expected != sub->container_type)
1192 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
1193 _dbus_type_to_string (sub->container_type),
1194 _dbus_type_to_string (expected));
1195 _dbus_assert_not_reached ("bad array element or variant content written");
1198 #endif /* DBUS_DISABLE_CHECKS */
1200 #if RECURSIVE_MARSHAL_TRACE
1201 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
1203 _dbus_type_to_string (writer->container_type),
1204 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1206 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1208 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d\n",
1210 _dbus_type_to_string (sub->container_type),
1211 sub->type_pos, sub->value_pos,
1212 sub->type_pos_is_expectation);
1217 write_or_verify_typecode (DBusTypeWriter *writer,
1220 /* A subwriter inside an array or variant will have type_pos
1221 * pointing to the expected typecode; a writer not inside an array
1222 * or variant has type_pos pointing to the next place to insert a
1225 #if RECURSIVE_MARSHAL_TRACE
1226 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
1227 writer, writer->type_pos,
1229 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1233 if (writer->type_str == NULL)
1236 if (writer->type_pos_is_expectation)
1238 #ifndef DBUS_DISABLE_CHECKS
1242 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1244 if (expected != typecode)
1246 _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1247 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1248 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1251 #endif /* DBUS_DISABLE_CHECKS */
1253 /* if immediately inside an array we'd always be appending an element,
1254 * so the expected type doesn't change; if inside a struct or something
1255 * below an array, we need to move through said struct or something.
1257 if (writer->container_type != DBUS_TYPE_ARRAY)
1258 writer->type_pos += 1;
1262 if (!_dbus_string_insert_byte (writer->type_str,
1267 writer->type_pos += 1;
1270 #if RECURSIVE_MARSHAL_TRACE
1271 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1272 writer, writer->type_pos,
1273 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1280 writer_recurse_struct (DBusTypeWriter *writer,
1281 const DBusString *contained_type,
1282 int contained_type_start,
1283 int contained_type_len,
1284 DBusTypeWriter *sub)
1286 /* FIXME right now contained_type is ignored; we could probably
1287 * almost trivially fix the code so if it's present we
1288 * write it out and then set type_pos_is_expectation
1291 /* Ensure that we'll be able to add alignment padding and the typecode */
1292 if (writer->enabled)
1294 if (!_dbus_string_alloc_space (sub->value_str, 8))
1298 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1299 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1301 if (writer->enabled)
1303 if (!_dbus_string_insert_bytes (sub->value_str,
1305 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1307 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1308 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1316 writer_recurse_array (DBusTypeWriter *writer,
1317 const DBusString *contained_type,
1318 int contained_type_start,
1319 int contained_type_len,
1320 DBusTypeWriter *sub)
1322 dbus_uint32_t value = 0;
1326 #ifndef DBUS_DISABLE_CHECKS
1327 if (writer->container_type == DBUS_TYPE_ARRAY &&
1330 if (!_dbus_string_equal_substring (contained_type,
1331 contained_type_start,
1334 writer->u.array.element_type_pos + 1))
1336 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1337 _dbus_string_get_const_data_len (contained_type,
1338 contained_type_start,
1339 contained_type_len));
1340 _dbus_assert_not_reached ("incompatible type for child array");
1343 #endif /* DBUS_DISABLE_CHECKS */
1345 if (writer->enabled)
1347 /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding
1348 * before array values
1350 if (!_dbus_string_alloc_space (sub->value_str, 3 + 4 + 4))
1354 if (writer->type_str != NULL)
1356 sub->type_pos += 1; /* move to point to the element type, since type_pos
1357 * should be the expected type for further writes
1359 sub->u.array.element_type_pos = sub->type_pos;
1362 if (!writer->type_pos_is_expectation)
1364 /* sub is a toplevel/outermost array so we need to write the type data */
1366 /* alloc space for array typecode, element signature */
1367 if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))
1370 if (!_dbus_string_insert_byte (writer->type_str,
1373 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1375 if (!_dbus_string_copy_len (contained_type,
1376 contained_type_start, contained_type_len,
1378 sub->u.array.element_type_pos))
1379 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1382 if (writer->type_str != NULL)
1384 /* If the parent is an array, we hold type_pos pointing at the array element type;
1385 * otherwise advance it to reflect the array value we just recursed into
1387 if (writer->container_type != DBUS_TYPE_ARRAY)
1388 writer->type_pos += 1 + contained_type_len;
1390 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1393 if (writer->enabled)
1395 /* Write the length */
1396 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1398 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1400 _dbus_assert_not_reached ("should not have failed to insert array len");
1402 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1404 /* Write alignment padding for array elements
1405 * Note that we write the padding *even for empty arrays*
1406 * to avoid wonky special cases
1408 alignment = element_type_get_alignment (contained_type, contained_type_start);
1410 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1411 if (aligned != sub->value_pos)
1413 if (!_dbus_string_insert_bytes (sub->value_str,
1415 aligned - sub->value_pos,
1417 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1419 sub->value_pos = aligned;
1421 sub->u.array.start_pos = sub->value_pos;
1423 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1424 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1426 #if RECURSIVE_MARSHAL_TRACE
1427 _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1429 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :
1431 sub->u.array.start_pos, sub->u.array.len_pos);
1438 /* Variant value will normally have:
1439 * 1 byte signature length not including nul
1440 * signature typecodes (nul terminated)
1441 * padding to 8-boundary
1442 * body according to signature
1444 * The signature string can only have a single type
1445 * in it but that type may be complex/recursive.
1447 * So a typical variant type with the integer 3 will have these
1449 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1451 * For an array of 4-byte types stuffed into variants, the padding to
1452 * 8-boundary is only the 1 byte that is required for the 4-boundary
1453 * anyhow for all array elements after the first one. And for single
1454 * variants in isolation, wasting a few bytes is hardly a big deal.
1456 * The main world of hurt for writing out a variant is that the type
1457 * string is the same string as the value string. Which means
1458 * inserting to the type string will move the value_pos; and it means
1459 * that inserting to the type string could break type alignment.
1461 * This type alignment issue is why the body of the variant is always
1462 * 8-aligned. Then we know that re-8-aligning the start of the body
1463 * will always correctly align the full contents of the variant type.
1466 writer_recurse_variant (DBusTypeWriter *writer,
1467 const DBusString *contained_type,
1468 int contained_type_start,
1469 int contained_type_len,
1470 DBusTypeWriter *sub)
1472 if (writer->enabled)
1474 /* Allocate space for the worst case, which is 1 byte sig
1475 * length, nul byte at end of sig, and 7 bytes padding to
1478 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1482 /* write VARIANT typecode to the parent's type string */
1483 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1486 /* If not enabled, mark that we have no type_str anymore ... */
1488 if (!writer->enabled)
1490 sub->type_str = NULL;
1496 /* If we're enabled then continue ... */
1498 if (!_dbus_string_insert_byte (sub->value_str,
1500 contained_type_len))
1501 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1503 sub->value_pos += 1;
1505 /* Here we switch over to the expected type sig we're about to write */
1506 sub->type_str = sub->value_str;
1507 sub->type_pos = sub->value_pos;
1509 if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,
1510 sub->value_str, sub->value_pos))
1511 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1513 sub->value_pos += contained_type_len;
1515 if (!_dbus_string_insert_byte (sub->value_str,
1518 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1520 sub->value_pos += 1;
1522 if (!_dbus_string_insert_bytes (sub->value_str,
1524 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1526 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1527 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1533 _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer,
1535 const DBusString *contained_type,
1536 int contained_type_start,
1537 int contained_type_len,
1538 DBusTypeWriter *sub)
1540 writer_recurse_init_and_check (writer, container_type, sub);
1542 switch (container_type)
1544 case DBUS_TYPE_STRUCT:
1545 return writer_recurse_struct (writer,
1546 contained_type, contained_type_start, contained_type_len,
1549 case DBUS_TYPE_ARRAY:
1550 return writer_recurse_array (writer,
1551 contained_type, contained_type_start, contained_type_len,
1554 case DBUS_TYPE_VARIANT:
1555 return writer_recurse_variant (writer,
1556 contained_type, contained_type_start, contained_type_len,
1560 _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");
1567 _dbus_type_writer_recurse (DBusTypeWriter *writer,
1569 const DBusString *contained_type,
1570 int contained_type_start,
1571 DBusTypeWriter *sub)
1573 int contained_type_len;
1576 contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);
1578 contained_type_len = 0;
1580 return _dbus_type_writer_recurse_contained_len (writer, container_type,
1582 contained_type_start,
1588 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1589 DBusTypeWriter *sub)
1591 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1593 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1594 _dbus_assert (!writer->type_pos_is_expectation ||
1595 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1597 #if RECURSIVE_MARSHAL_TRACE
1598 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1599 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1600 _dbus_type_to_string (writer->container_type));
1601 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1602 sub, sub->type_pos, sub->value_pos,
1603 sub->type_pos_is_expectation,
1604 _dbus_type_to_string (sub->container_type));
1607 if (sub->container_type == DBUS_TYPE_STRUCT)
1609 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1612 else if (sub->container_type == DBUS_TYPE_ARRAY)
1618 /* Set the array length */
1619 len = sub->value_pos - sub->u.array.start_pos;
1620 _dbus_marshal_set_uint32 (sub->value_str,
1621 sub->u.array.len_pos,
1624 #if RECURSIVE_MARSHAL_TRACE
1625 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1626 len, sub->u.array.len_pos);
1631 /* Now get type_pos right for the parent writer. Here are the cases:
1633 * Cases !writer->type_pos_is_expectation:
1634 * (in these cases we want to update to the new insertion point)
1636 * - if we recursed into a STRUCT then we didn't know in advance
1637 * what the types in the struct would be; so we have to fill in
1638 * that information now.
1639 * writer->type_pos = sub->type_pos
1641 * - if we recursed into anything else, we knew the full array
1642 * type, or knew the single typecode marking VARIANT, so
1643 * writer->type_pos is already correct.
1644 * writer->type_pos should remain as-is
1646 * - note that the parent is never an ARRAY or VARIANT, if it were
1647 * then type_pos_is_expectation would be TRUE. The parent
1648 * is thus known to be a toplevel or STRUCT.
1650 * Cases where writer->type_pos_is_expectation:
1651 * (in these cases we want to update to next expected type to write)
1653 * - we recursed from STRUCT into STRUCT and we didn't increment
1654 * type_pos in the parent just to stay consistent with the
1655 * !writer->type_pos_is_expectation case (though we could
1656 * special-case this in recurse_struct instead if we wanted)
1657 * writer->type_pos = sub->type_pos
1659 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1660 * for parent should have been incremented already
1661 * writer->type_pos should remain as-is
1663 * - we recursed from ARRAY into a sub-element, so type_pos in the
1664 * parent is the element type and should remain the element type
1665 * for the benefit of the next child element
1666 * writer->type_pos should remain as-is
1668 * - we recursed from VARIANT into its value, so type_pos in the
1669 * parent makes no difference since there's only one value
1670 * and we just finished writing it and won't use type_pos again
1671 * writer->type_pos should remain as-is
1673 if (writer->type_str != NULL)
1675 if (sub->container_type == DBUS_TYPE_STRUCT &&
1676 (writer->container_type == DBUS_TYPE_STRUCT ||
1677 writer->container_type == DBUS_TYPE_INVALID))
1679 /* Advance the parent to the next struct field */
1680 writer->type_pos = sub->type_pos;
1684 writer->value_pos = sub->value_pos;
1686 #if RECURSIVE_MARSHAL_TRACE
1687 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1688 writer, writer->type_pos, writer->value_pos,
1690 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :
1698 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1704 /* First ensure that our type realloc will succeed */
1705 if (writer->type_str != NULL)
1707 if (!_dbus_string_alloc_space (writer->type_str, 1))
1713 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1716 if (!write_or_verify_typecode (writer, type))
1717 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1722 #if RECURSIVE_MARSHAL_TRACE
1723 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1724 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1731 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1741 * Iterate through all values in the given reader, writing a copy of
1742 * each value to the writer. The reader will be moved forward to its
1745 * If a reader start_after is provided, it should be a reader for the
1746 * same data as the reader to be written. Only values occurring after
1747 * the value pointed to by start_after will be written to the writer.
1749 * @param writer the writer to copy to
1750 * @param reader the reader to copy from
1751 * @param start_after #NULL or a reader showing where to start
1754 _dbus_type_writer_write_reader (DBusTypeWriter *writer,
1755 DBusTypeReader *reader,
1756 const DBusTypeReader *start_after)
1758 DBusTypeWriter orig;
1766 orig_type_len = _dbus_string_get_length (writer->type_str);
1767 orig_value_len = _dbus_string_get_length (writer->value_str);
1768 orig_enabled = writer->enabled;
1772 _dbus_type_writer_set_enabled (writer,
1773 _dbus_type_reader_greater_than (reader, start_after));
1776 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
1778 if (_dbus_type_is_container (current_type))
1780 DBusTypeReader subreader;
1781 DBusTypeWriter subwriter;
1782 const DBusString *sig_str;
1786 _dbus_type_reader_recurse (reader, &subreader);
1788 _dbus_type_reader_get_signature (&subreader, &sig_str,
1789 &sig_start, &sig_len);
1791 if (!_dbus_type_writer_recurse_contained_len (writer, current_type,
1792 sig_str, sig_start, sig_len,
1796 if (!_dbus_type_writer_write_reader (&subwriter, &subreader, start_after))
1799 if (!_dbus_type_writer_unrecurse (writer, &subwriter))
1806 _dbus_assert (_dbus_type_is_basic (current_type));
1808 _dbus_type_reader_read_basic (reader, &val);
1810 if (!_dbus_type_writer_write_basic (writer, current_type, &val))
1814 _dbus_type_reader_next (reader);
1817 _dbus_type_writer_set_enabled (writer, orig_enabled);
1821 if (!writer->type_pos_is_expectation)
1823 new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;
1824 _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
1826 new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;
1827 _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
1835 * If disabled, a writer can still be iterated forward and recursed/unrecursed
1836 * but won't write any values. Types will still be written unless the
1837 * writer is a "values only" writer, because the writer needs access to
1838 * a valid signature to be able to iterate.
1840 * @param writer the type writer
1841 * @param enabled #TRUE if values should be written
1844 _dbus_type_writer_set_enabled (DBusTypeWriter *writer,
1845 dbus_bool_t enabled)
1847 writer->enabled = enabled != FALSE;
1850 /** @} */ /* end of DBusMarshal group */
1852 #ifdef DBUS_BUILD_TESTS
1853 #include "dbus-test.h"
1854 #include "dbus-list.h"
1858 /* Whether to do the OOM stuff */
1859 #define TEST_OOM_HANDLING 0
1860 /* We do start offset 0 through 9, to get various alignment cases. Still this
1861 * obviously makes the test suite run 10x as slow.
1863 #define MAX_INITIAL_OFFSET 9
1865 /* Largest iteration count to test copying, realignment,
1866 * etc. with. i.e. we only test this stuff with some of the smaller
1869 #define MAX_ITERATIONS_FOR_EXPENSIVE_TESTS 1000
1875 DBusString signature;
1885 #define N_FENCE_BYTES 5
1886 #define FENCE_BYTES_STR "abcde"
1887 #define INITIAL_PADDING_BYTE '\0'
1890 data_block_init (DataBlock *block,
1894 if (!_dbus_string_init (&block->signature))
1897 if (!_dbus_string_init (&block->body))
1899 _dbus_string_free (&block->signature);
1903 if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
1904 INITIAL_PADDING_BYTE) ||
1905 !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
1906 INITIAL_PADDING_BYTE) ||
1907 !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
1908 !_dbus_string_append (&block->body, FENCE_BYTES_STR))
1910 _dbus_string_free (&block->signature);
1911 _dbus_string_free (&block->body);
1915 block->byte_order = byte_order;
1916 block->initial_offset = initial_offset;
1922 data_block_save (DataBlock *block,
1923 DataBlockState *state)
1925 state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
1926 state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
1930 data_block_restore (DataBlock *block,
1931 DataBlockState *state)
1933 _dbus_string_delete (&block->signature,
1934 state->saved_sig_len,
1935 _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
1936 _dbus_string_delete (&block->body,
1937 state->saved_body_len,
1938 _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
1942 data_block_verify (DataBlock *block)
1944 if (!_dbus_string_ends_with_c_str (&block->signature,
1949 offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
1953 _dbus_verbose_bytes_of_string (&block->signature,
1955 _dbus_string_get_length (&block->signature) - offset);
1956 _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
1958 if (!_dbus_string_ends_with_c_str (&block->body,
1963 offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
1967 _dbus_verbose_bytes_of_string (&block->body,
1969 _dbus_string_get_length (&block->body) - offset);
1970 _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
1973 _dbus_assert (_dbus_string_validate_nul (&block->signature,
1974 0, block->initial_offset));
1975 _dbus_assert (_dbus_string_validate_nul (&block->body,
1976 0, block->initial_offset));
1980 data_block_free (DataBlock *block)
1982 data_block_verify (block);
1984 _dbus_string_free (&block->signature);
1985 _dbus_string_free (&block->body);
1989 data_block_reset (DataBlock *block)
1991 data_block_verify (block);
1993 _dbus_string_delete (&block->signature,
1994 block->initial_offset,
1995 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
1996 _dbus_string_delete (&block->body,
1997 block->initial_offset,
1998 _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
2000 data_block_verify (block);
2004 data_block_init_reader_writer (DataBlock *block,
2005 DBusTypeReader *reader,
2006 DBusTypeWriter *writer)
2009 _dbus_type_reader_init (reader,
2012 block->initial_offset,
2014 block->initial_offset);
2017 _dbus_type_writer_init (writer,
2020 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
2022 _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
2026 real_check_expected_type (DBusTypeReader *reader,
2028 const char *funcname,
2033 t = _dbus_type_reader_get_current_type (reader);
2037 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
2038 _dbus_type_to_string (t),
2039 _dbus_type_to_string (expected),
2042 _dbus_assert_not_reached ("read wrong type");
2046 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
2048 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
2050 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
2051 _DBUS_FUNCTION_NAME, __LINE__); \
2052 _dbus_assert_not_reached ("test failed"); \
2056 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
2058 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
2059 _DBUS_FUNCTION_NAME, __LINE__); \
2060 _dbus_assert_not_reached ("test failed"); \
2062 check_expected_type (reader, DBUS_TYPE_INVALID); \
2065 typedef struct TestTypeNode TestTypeNode;
2066 typedef struct TestTypeNodeClass TestTypeNodeClass;
2067 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
2068 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
2072 const TestTypeNodeClass *klass;
2075 struct TestTypeNodeContainer
2081 struct TestTypeNodeClass
2087 int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
2089 dbus_bool_t (* construct) (TestTypeNode *node);
2090 void (* destroy) (TestTypeNode *node);
2092 dbus_bool_t (* write_value) (TestTypeNode *node,
2094 DBusTypeWriter *writer,
2096 dbus_bool_t (* read_value) (TestTypeNode *node,
2097 DBusTypeReader *reader,
2099 dbus_bool_t (* set_value) (TestTypeNode *node,
2100 DBusTypeReader *reader,
2101 DBusTypeReader *realign_root,
2103 dbus_bool_t (* build_signature) (TestTypeNode *node,
2107 struct TestTypeNodeContainerClass
2109 TestTypeNodeClass base;
2112 static dbus_bool_t int32_write_value (TestTypeNode *node,
2114 DBusTypeWriter *writer,
2116 static dbus_bool_t int32_read_value (TestTypeNode *node,
2117 DBusTypeReader *reader,
2119 static dbus_bool_t int64_write_value (TestTypeNode *node,
2121 DBusTypeWriter *writer,
2123 static dbus_bool_t int64_read_value (TestTypeNode *node,
2124 DBusTypeReader *reader,
2126 static dbus_bool_t string_write_value (TestTypeNode *node,
2128 DBusTypeWriter *writer,
2130 static dbus_bool_t string_read_value (TestTypeNode *node,
2131 DBusTypeReader *reader,
2133 static dbus_bool_t bool_write_value (TestTypeNode *node,
2135 DBusTypeWriter *writer,
2137 static dbus_bool_t bool_read_value (TestTypeNode *node,
2138 DBusTypeReader *reader,
2140 static dbus_bool_t byte_write_value (TestTypeNode *node,
2142 DBusTypeWriter *writer,
2144 static dbus_bool_t byte_read_value (TestTypeNode *node,
2145 DBusTypeReader *reader,
2147 static dbus_bool_t double_write_value (TestTypeNode *node,
2149 DBusTypeWriter *writer,
2151 static dbus_bool_t double_read_value (TestTypeNode *node,
2152 DBusTypeReader *reader,
2154 static dbus_bool_t object_path_write_value (TestTypeNode *node,
2156 DBusTypeWriter *writer,
2158 static dbus_bool_t object_path_read_value (TestTypeNode *node,
2159 DBusTypeReader *reader,
2161 static dbus_bool_t signature_write_value (TestTypeNode *node,
2163 DBusTypeWriter *writer,
2165 static dbus_bool_t signature_read_value (TestTypeNode *node,
2166 DBusTypeReader *reader,
2168 static dbus_bool_t struct_write_value (TestTypeNode *node,
2170 DBusTypeWriter *writer,
2172 static dbus_bool_t struct_read_value (TestTypeNode *node,
2173 DBusTypeReader *reader,
2175 static dbus_bool_t struct_build_signature (TestTypeNode *node,
2177 static dbus_bool_t array_write_value (TestTypeNode *node,
2179 DBusTypeWriter *writer,
2181 static dbus_bool_t array_read_value (TestTypeNode *node,
2182 DBusTypeReader *reader,
2184 static dbus_bool_t array_build_signature (TestTypeNode *node,
2186 static dbus_bool_t variant_write_value (TestTypeNode *node,
2188 DBusTypeWriter *writer,
2190 static dbus_bool_t variant_read_value (TestTypeNode *node,
2191 DBusTypeReader *reader,
2193 static void container_destroy (TestTypeNode *node);
2196 static const TestTypeNodeClass int32_class = {
2198 sizeof (TestTypeNode),
2208 static const TestTypeNodeClass uint32_class = {
2210 sizeof (TestTypeNode),
2214 int32_write_value, /* recycle from int32 */
2215 int32_read_value, /* recycle from int32 */
2220 static const TestTypeNodeClass int64_class = {
2222 sizeof (TestTypeNode),
2232 static const TestTypeNodeClass uint64_class = {
2234 sizeof (TestTypeNode),
2238 int64_write_value, /* recycle from int64 */
2239 int64_read_value, /* recycle from int64 */
2244 static const TestTypeNodeClass string_0_class = {
2246 sizeof (TestTypeNode),
2247 0, /* string length */
2256 static const TestTypeNodeClass string_1_class = {
2258 sizeof (TestTypeNode),
2259 1, /* string length */
2268 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
2269 static const TestTypeNodeClass string_3_class = {
2271 sizeof (TestTypeNode),
2272 3, /* string length */
2281 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
2282 static const TestTypeNodeClass string_8_class = {
2284 sizeof (TestTypeNode),
2285 8, /* string length */
2294 static const TestTypeNodeClass bool_class = {
2296 sizeof (TestTypeNode),
2306 static const TestTypeNodeClass byte_class = {
2308 sizeof (TestTypeNode),
2318 static const TestTypeNodeClass double_class = {
2320 sizeof (TestTypeNode),
2330 static const TestTypeNodeClass object_path_class = {
2331 DBUS_TYPE_OBJECT_PATH,
2332 sizeof (TestTypeNode),
2336 object_path_write_value,
2337 object_path_read_value,
2342 static const TestTypeNodeClass signature_class = {
2343 DBUS_TYPE_SIGNATURE,
2344 sizeof (TestTypeNode),
2348 signature_write_value,
2349 signature_read_value,
2354 static const TestTypeNodeClass struct_1_class = {
2356 sizeof (TestTypeNodeContainer),
2357 1, /* number of times children appear as fields */
2363 struct_build_signature
2366 static const TestTypeNodeClass struct_2_class = {
2368 sizeof (TestTypeNodeContainer),
2369 2, /* number of times children appear as fields */
2375 struct_build_signature
2378 static const TestTypeNodeClass array_0_class = {
2380 sizeof (TestTypeNodeContainer),
2381 0, /* number of array elements */
2387 array_build_signature
2390 static const TestTypeNodeClass array_1_class = {
2392 sizeof (TestTypeNodeContainer),
2393 1, /* number of array elements */
2399 array_build_signature
2402 static const TestTypeNodeClass array_2_class = {
2404 sizeof (TestTypeNodeContainer),
2405 2, /* number of array elements */
2411 array_build_signature
2414 static const TestTypeNodeClass array_9_class = {
2416 sizeof (TestTypeNodeContainer),
2417 9, /* number of array elements */
2423 array_build_signature
2426 static const TestTypeNodeClass variant_class = {
2428 sizeof (TestTypeNodeContainer),
2432 variant_write_value,
2438 static const TestTypeNodeClass* const
2454 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2456 static const TestTypeNodeClass* const
2457 container_nodes[] = {
2464 /* array_9_class is omitted on purpose, it's too slow;
2465 * we only use it in one hardcoded test below
2468 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2470 static TestTypeNode*
2471 node_new (const TestTypeNodeClass *klass)
2475 node = dbus_malloc0 (klass->instance_size);
2479 node->klass = klass;
2481 if (klass->construct)
2483 if (!(* klass->construct) (node))
2494 node_destroy (TestTypeNode *node)
2496 if (node->klass->destroy)
2497 (* node->klass->destroy) (node);
2502 node_write_value (TestTypeNode *node,
2504 DBusTypeWriter *writer,
2509 retval = (* node->klass->write_value) (node, block, writer, seed);
2512 /* Handy to see where things break, but too expensive to do all the time */
2513 data_block_verify (block);
2520 node_read_value (TestTypeNode *node,
2521 DBusTypeReader *reader,
2525 DBusTypeReader restored;
2527 _dbus_type_reader_save_mark (reader, &mark);
2529 if (!(* node->klass->read_value) (node, reader, seed))
2532 _dbus_type_reader_init_from_mark (&restored,
2538 if (!(* node->klass->read_value) (node, &restored, seed))
2545 node_build_signature (TestTypeNode *node,
2548 if (node->klass->build_signature)
2549 return (* node->klass->build_signature) (node, str);
2551 return _dbus_string_append_byte (str, node->klass->typecode);
2555 node_append_child (TestTypeNode *node,
2556 TestTypeNode *child)
2558 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2560 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2562 if (!_dbus_list_append (&container->children, child))
2563 _dbus_assert_not_reached ("no memory"); /* we never check the return value on node_append_child anyhow - it's run from outside the malloc-failure test code */
2568 static int n_iterations_completed_total = 0;
2569 static int n_iterations_completed_this_test = 0;
2570 static int n_iterations_expected_this_test = 0;
2574 const DBusString *signature;
2577 TestTypeNode **nodes;
2579 } NodeIterationData;
2583 run_test_copy (NodeIterationData *nid)
2588 DBusTypeReader reader;
2589 DBusTypeWriter writer;
2591 _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
2597 if (!data_block_init (&dest, src->byte_order, src->initial_offset))
2600 data_block_init_reader_writer (src, &reader, NULL);
2601 data_block_init_reader_writer (&dest, NULL, &writer);
2603 /* DBusTypeWriter assumes it's writing into an existing signature,
2604 * so doesn't add nul on its own. We have to do that.
2606 if (!_dbus_string_insert_byte (&dest.signature,
2607 dest.initial_offset, '\0'))
2610 if (!_dbus_type_writer_write_reader (&writer, &reader, NULL))
2613 /* Data blocks should now be identical */
2614 if (!_dbus_string_equal (&src->signature, &dest.signature))
2616 _dbus_verbose ("SOURCE\n");
2617 _dbus_verbose_bytes_of_string (&src->signature, 0,
2618 _dbus_string_get_length (&src->signature));
2619 _dbus_verbose ("DEST\n");
2620 _dbus_verbose_bytes_of_string (&dest.signature, 0,
2621 _dbus_string_get_length (&dest.signature));
2622 _dbus_assert_not_reached ("signatures did not match");
2625 if (!_dbus_string_equal (&src->body, &dest.body))
2627 _dbus_verbose ("SOURCE\n");
2628 _dbus_verbose_bytes_of_string (&src->body, 0,
2629 _dbus_string_get_length (&src->body));
2630 _dbus_verbose ("DEST\n");
2631 _dbus_verbose_bytes_of_string (&dest.body, 0,
2632 _dbus_string_get_length (&dest.body));
2633 _dbus_assert_not_reached ("bodies did not match");
2640 data_block_free (&dest);
2646 run_test_values_only_write (NodeIterationData *nid)
2648 DBusTypeReader reader;
2649 DBusTypeWriter writer;
2654 _dbus_verbose ("%s\n", _DBUS_FUNCTION_NAME);
2658 data_block_reset (nid->block);
2660 sig_len = _dbus_string_get_length (nid->signature);
2662 _dbus_type_writer_init_values_only (&writer,
2663 nid->block->byte_order,
2666 _dbus_string_get_length (&nid->block->body) - N_FENCE_BYTES);
2667 _dbus_type_reader_init (&reader,
2668 nid->block->byte_order,
2671 nid->block->initial_offset);
2674 while (i < nid->n_nodes)
2676 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2682 /* if we wrote any typecodes then this would fail */
2683 _dbus_assert (sig_len == _dbus_string_get_length (nid->signature));
2685 /* But be sure we wrote out the values correctly */
2687 while (i < nid->n_nodes)
2689 if (!node_read_value (nid->nodes[i], &reader, i))
2692 if (i + 1 == nid->n_nodes)
2693 NEXT_EXPECTING_FALSE (&reader);
2695 NEXT_EXPECTING_TRUE (&reader);
2703 data_block_reset (nid->block);
2708 run_test_nodes_iteration (void *data)
2710 NodeIterationData *nid = data;
2711 DBusTypeReader reader;
2712 DBusTypeWriter writer;
2717 * 1. write the value
2718 * 2. strcmp-compare with the signature we built
2720 * 4. type-iterate the signature and the value and see if they are the same type-wise
2724 data_block_init_reader_writer (nid->block,
2727 /* DBusTypeWriter assumes it's writing into an existing signature,
2728 * so doesn't add nul on its own. We have to do that.
2730 if (!_dbus_string_insert_byte (&nid->block->signature,
2731 nid->type_offset, '\0'))
2735 while (i < nid->n_nodes)
2737 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2743 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2744 &nid->block->signature, nid->type_offset))
2746 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2747 _dbus_string_get_const_data (nid->signature),
2748 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2750 _dbus_assert_not_reached ("wrong signature");
2754 while (i < nid->n_nodes)
2756 if (!node_read_value (nid->nodes[i], &reader, i))
2759 if (i + 1 == nid->n_nodes)
2760 NEXT_EXPECTING_FALSE (&reader);
2762 NEXT_EXPECTING_TRUE (&reader);
2767 if (n_iterations_expected_this_test <= MAX_ITERATIONS_FOR_EXPENSIVE_TESTS)
2769 if (!run_test_copy (nid))
2772 if (!run_test_values_only_write (nid))
2776 /* FIXME type-iterate both signature and value and compare the resulting
2777 * tree to the node tree perhaps
2784 data_block_reset (nid->block);
2790 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
2792 const DBusString *signature,
2797 NodeIterationData nid;
2799 if (!data_block_init (&block, byte_order, initial_offset))
2800 _dbus_assert_not_reached ("no memory");
2802 nid.signature = signature;
2804 nid.type_offset = initial_offset;
2806 nid.n_nodes = n_nodes;
2808 #if TEST_OOM_HANDLING
2809 _dbus_test_oom_handling ("running test node",
2810 run_test_nodes_iteration,
2813 if (!run_test_nodes_iteration (&nid))
2814 _dbus_assert_not_reached ("no memory");
2817 data_block_free (&block);
2821 run_test_nodes (TestTypeNode **nodes,
2825 DBusString signature;
2827 if (!_dbus_string_init (&signature))
2828 _dbus_assert_not_reached ("no memory");
2833 if (! node_build_signature (nodes[i], &signature))
2834 _dbus_assert_not_reached ("no memory");
2839 _dbus_verbose (">>> test nodes with signature '%s'\n",
2840 _dbus_string_get_const_data (&signature));
2843 while (i <= MAX_INITIAL_OFFSET)
2845 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2846 DBUS_LITTLE_ENDIAN, i);
2847 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2848 DBUS_BIG_ENDIAN, i);
2853 n_iterations_completed_this_test += 1;
2854 n_iterations_completed_total += 1;
2856 if (n_iterations_completed_this_test == n_iterations_expected_this_test)
2858 fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
2859 n_iterations_completed_this_test,
2860 n_iterations_completed_total);
2862 /* this happens to turn out well with mod == 1 */
2863 else if ((n_iterations_completed_this_test %
2864 (int)(n_iterations_expected_this_test / 10.0)) == 1)
2866 fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
2869 _dbus_string_free (&signature);
2872 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
2874 static TestTypeNode*
2875 value_generator (int *ip)
2878 const TestTypeNodeClass *child_klass;
2879 const TestTypeNodeClass *container_klass;
2880 TestTypeNode *child;
2883 _dbus_assert (i <= N_VALUES);
2889 else if (i < N_BASICS)
2891 node = node_new (basic_nodes[i]);
2895 /* imagine an array:
2896 * container 0 of basic 0
2897 * container 0 of basic 1
2898 * container 0 of basic 2
2899 * container 1 of basic 0
2900 * container 1 of basic 1
2901 * container 1 of basic 2
2905 container_klass = container_nodes[i / N_BASICS];
2906 child_klass = basic_nodes[i % N_BASICS];
2908 node = node_new (container_klass);
2909 child = node_new (child_klass);
2911 node_append_child (node, child);
2914 *ip += 1; /* increment the generator */
2920 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2924 TestTypeNode *container;
2925 TestTypeNode *child;
2928 root = node_new (container_klass);
2930 for (i = 1; i < n_nested; i++)
2932 child = node_new (container_klass);
2933 node_append_child (container, child);
2937 /* container should now be the most-nested container */
2940 while ((child = value_generator (&i)))
2942 node_append_child (container, child);
2944 run_test_nodes (&root, 1);
2946 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2947 node_destroy (child);
2950 node_destroy (root);
2954 start_next_test (const char *format,
2957 n_iterations_completed_this_test = 0;
2958 n_iterations_expected_this_test = expected;
2960 fprintf (stderr, ">>> >>> ");
2961 fprintf (stderr, format,
2962 n_iterations_expected_this_test);
2966 make_and_run_test_nodes (void)
2970 /* We try to do this in order of "complicatedness" so that test
2971 * failures tend to show up in the simplest test case that
2972 * demonstrates the failure. There are also some tests that run
2973 * more than once for this reason, first while going through simple
2974 * cases, second while going through a broader range of complex
2977 /* Each basic node. The basic nodes should include:
2979 * - each fixed-size type (in such a way that it has different values each time,
2980 * so we can tell if we mix two of them up)
2981 * - strings of various lengths
2985 /* Each container node. The container nodes should include:
2987 * struct with 1 and 2 copies of the contained item
2988 * array with 0, 1, 2 copies of the contained item
2991 /* Let a "value" be a basic node, or a container containing a single basic node.
2992 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2993 * When iterating through all values to make combinations, do the basic types
2994 * first and the containers second.
2996 /* Each item is shown with its number of iterations to complete so
2997 * we can keep a handle on this unit test
3000 /* FIXME test just an empty body, no types at all */
3002 start_next_test ("Each value by itself %d iterations\n", N_VALUES);
3006 while ((node = value_generator (&i)))
3008 run_test_nodes (&node, 1);
3010 node_destroy (node);
3014 start_next_test ("All values in one big toplevel %d iteration\n", 1);
3016 TestTypeNode *nodes[N_VALUES];
3019 while ((nodes[i] = value_generator (&i)))
3022 run_test_nodes (nodes, N_VALUES);
3024 for (i = 0; i < N_VALUES; i++)
3025 node_destroy (nodes[i]);
3028 start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
3029 N_VALUES * N_VALUES);
3031 TestTypeNode *nodes[2];
3034 while ((nodes[0] = value_generator (&i)))
3037 while ((nodes[1] = value_generator (&j)))
3039 run_test_nodes (nodes, 2);
3041 node_destroy (nodes[1]);
3044 node_destroy (nodes[0]);
3048 start_next_test ("Each container containing each value %d iterations\n",
3049 N_CONTAINERS * N_VALUES);
3050 for (i = 0; i < N_CONTAINERS; i++)
3052 const TestTypeNodeClass *container_klass = container_nodes[i];
3054 make_and_run_values_inside_container (container_klass, 1);
3057 n_iterations_completed_this_test = 0;
3058 n_iterations_expected_this_test = N_CONTAINERS * N_VALUES;
3059 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
3060 n_iterations_completed_this_test);
3061 for (i = 0; i < N_CONTAINERS; i++)
3063 const TestTypeNodeClass *container_klass = container_nodes[i];
3065 make_and_run_values_inside_container (container_klass, 2);
3068 start_next_test ("Each container of same container of same container of each value %d iterations\n",
3069 N_CONTAINERS * N_VALUES);
3070 for (i = 0; i < N_CONTAINERS; i++)
3072 const TestTypeNodeClass *container_klass = container_nodes[i];
3074 make_and_run_values_inside_container (container_klass, 3);
3077 start_next_test ("Each value,value pair inside a struct %d iterations\n",
3078 N_VALUES * N_VALUES);
3080 TestTypeNode *val1, *val2;
3083 node = node_new (&struct_1_class);
3086 while ((val1 = value_generator (&i)))
3089 while ((val2 = value_generator (&j)))
3091 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3093 node_append_child (node, val1);
3094 node_append_child (node, val2);
3096 run_test_nodes (&node, 1);
3098 _dbus_list_clear (&container->children);
3099 node_destroy (val2);
3101 node_destroy (val1);
3103 node_destroy (node);
3106 start_next_test ("All values in one big struct %d iteration\n",
3110 TestTypeNode *child;
3112 node = node_new (&struct_1_class);
3115 while ((child = value_generator (&i)))
3116 node_append_child (node, child);
3118 run_test_nodes (&node, 1);
3120 node_destroy (node);
3123 start_next_test ("Each value in a large array %d iterations\n",
3129 node = node_new (&array_9_class);
3132 while ((val = value_generator (&i)))
3134 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3136 node_append_child (node, val);
3138 run_test_nodes (&node, 1);
3140 _dbus_list_clear (&container->children);
3144 node_destroy (node);
3147 start_next_test ("Each container of each container of each value %d iterations\n",
3148 N_CONTAINERS * N_CONTAINERS * N_VALUES);
3149 for (i = 0; i < N_CONTAINERS; i++)
3151 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
3152 TestTypeNode *outer_container = node_new (outer_container_klass);
3154 for (j = 0; j < N_CONTAINERS; j++)
3156 TestTypeNode *child;
3157 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
3158 TestTypeNode *inner_container = node_new (inner_container_klass);
3160 node_append_child (outer_container, inner_container);
3163 while ((child = value_generator (&m)))
3165 node_append_child (inner_container, child);
3167 run_test_nodes (&outer_container, 1);
3169 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
3170 node_destroy (child);
3172 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
3173 node_destroy (inner_container);
3175 node_destroy (outer_container);
3178 start_next_test ("Each container of each container of each container of each value %d iterations\n",
3179 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
3180 for (i = 0; i < N_CONTAINERS; i++)
3182 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
3183 TestTypeNode *outer_container = node_new (outer_container_klass);
3185 for (j = 0; j < N_CONTAINERS; j++)
3187 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
3188 TestTypeNode *inner_container = node_new (inner_container_klass);
3190 node_append_child (outer_container, inner_container);
3192 for (k = 0; k < N_CONTAINERS; k++)
3194 TestTypeNode *child;
3195 const TestTypeNodeClass *center_container_klass = container_nodes[k];
3196 TestTypeNode *center_container = node_new (center_container_klass);
3198 node_append_child (inner_container, center_container);
3201 while ((child = value_generator (&m)))
3203 node_append_child (center_container, child);
3205 run_test_nodes (&outer_container, 1);
3207 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
3208 node_destroy (child);
3210 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
3211 node_destroy (center_container);
3213 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
3214 node_destroy (inner_container);
3216 node_destroy (outer_container);
3220 /* This one takes a really long time, so comment it out for now */
3221 start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
3222 N_VALUES * N_VALUES * N_VALUES);
3224 TestTypeNode *nodes[3];
3227 while ((nodes[0] = value_generator (&i)))
3230 while ((nodes[1] = value_generator (&j)))
3233 while ((nodes[2] = value_generator (&k)))
3235 run_test_nodes (nodes, 3);
3237 node_destroy (nodes[2]);
3239 node_destroy (nodes[1]);
3241 node_destroy (nodes[0]);
3244 #endif /* #if 0 expensive test */
3246 fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
3247 n_iterations_completed_total);
3248 fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
3249 MAX_INITIAL_OFFSET);
3250 fprintf (stderr, "out of memory handling %s tested\n",
3251 TEST_OOM_HANDLING ? "was" : "was not");
3254 dbus_bool_t _dbus_marshal_recursive_test (void);
3257 _dbus_marshal_recursive_test (void)
3259 make_and_run_test_nodes ();
3265 dbus_bool_t _dbus_marshal_test (void);
3267 main (int argc, char **argv)
3269 _dbus_marshal_test ();
3271 _dbus_marshal_recursive_test ();
3281 * Implementations of each type node class
3288 #define SAMPLE_INT32 12345678
3289 #define SAMPLE_INT32_ALTERNATE 53781429
3291 int32_from_seed (int seed)
3293 /* Generate an integer value that's predictable from seed. We could
3294 * just use seed itself, but that would only ever touch one byte of
3295 * the int so would miss some kinds of bug.
3299 v = 42; /* just to quiet compiler afaik */
3306 v = SAMPLE_INT32_ALTERNATE;
3320 v *= seed; /* wraps around eventually, which is fine */
3326 int32_write_value (TestTypeNode *node,
3328 DBusTypeWriter *writer,
3331 /* also used for uint32 */
3334 v = int32_from_seed (seed);
3336 return _dbus_type_writer_write_basic (writer,
3337 node->klass->typecode,
3342 int32_read_value (TestTypeNode *node,
3343 DBusTypeReader *reader,
3346 /* also used for uint32 */
3349 check_expected_type (reader, node->klass->typecode);
3351 _dbus_type_reader_read_basic (reader,
3352 (dbus_int32_t*) &v);
3354 _dbus_assert (v == int32_from_seed (seed));
3359 #ifdef DBUS_HAVE_INT64
3361 int64_from_seed (int seed)
3366 v32 = int32_from_seed (seed);
3368 v = - (dbus_int32_t) ~ v32;
3369 v |= (((dbus_int64_t)v32) << 32);
3376 int64_write_value (TestTypeNode *node,
3378 DBusTypeWriter *writer,
3381 #ifdef DBUS_HAVE_INT64
3382 /* also used for uint64 */
3385 v = int64_from_seed (seed);
3387 return _dbus_type_writer_write_basic (writer,
3388 node->klass->typecode,
3396 int64_read_value (TestTypeNode *node,
3397 DBusTypeReader *reader,
3400 #ifdef DBUS_HAVE_INT64
3401 /* also used for uint64 */
3404 check_expected_type (reader, node->klass->typecode);
3406 _dbus_type_reader_read_basic (reader,
3407 (dbus_int64_t*) &v);
3409 _dbus_assert (v == int64_from_seed (seed));
3417 #define MAX_SAMPLE_STRING_LEN 10
3419 string_from_seed (char *buf,
3426 _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
3428 v = (unsigned char) ('A' + seed);
3433 if (v < 'A' || v > 'z')
3446 string_write_value (TestTypeNode *node,
3448 DBusTypeWriter *writer,
3451 char buf[MAX_SAMPLE_STRING_LEN];
3452 const char *v_string = buf;
3454 string_from_seed (buf, node->klass->subclass_detail,
3457 return _dbus_type_writer_write_basic (writer,
3458 node->klass->typecode,
3463 string_read_value (TestTypeNode *node,
3464 DBusTypeReader *reader,
3468 char buf[MAX_SAMPLE_STRING_LEN];
3470 check_expected_type (reader, node->klass->typecode);
3472 _dbus_type_reader_read_basic (reader,
3473 (const char **) &v);
3475 string_from_seed (buf, node->klass->subclass_detail,
3478 if (strcmp (buf, v) != 0)
3480 _dbus_warn ("read string '%s' expected '%s'\n",
3482 _dbus_assert_not_reached ("test failed");
3488 #define BOOL_FROM_SEED(seed) (seed % 2)
3491 bool_write_value (TestTypeNode *node,
3493 DBusTypeWriter *writer,
3498 v = BOOL_FROM_SEED (seed);
3500 return _dbus_type_writer_write_basic (writer,
3501 node->klass->typecode,
3506 bool_read_value (TestTypeNode *node,
3507 DBusTypeReader *reader,
3512 check_expected_type (reader, node->klass->typecode);
3514 _dbus_type_reader_read_basic (reader,
3515 (unsigned char*) &v);
3517 _dbus_assert (v == BOOL_FROM_SEED (seed));
3522 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
3525 byte_write_value (TestTypeNode *node,
3527 DBusTypeWriter *writer,
3532 v = BYTE_FROM_SEED (seed);
3534 return _dbus_type_writer_write_basic (writer,
3535 node->klass->typecode,
3540 byte_read_value (TestTypeNode *node,
3541 DBusTypeReader *reader,
3546 check_expected_type (reader, node->klass->typecode);
3548 _dbus_type_reader_read_basic (reader,
3549 (unsigned char*) &v);
3551 _dbus_assert (v == BYTE_FROM_SEED (seed));
3557 double_from_seed (int seed)
3559 return SAMPLE_INT32 * (double) seed + 0.3;
3563 double_write_value (TestTypeNode *node,
3565 DBusTypeWriter *writer,
3570 v = double_from_seed (seed);
3572 return _dbus_type_writer_write_basic (writer,
3573 node->klass->typecode,
3578 double_read_value (TestTypeNode *node,
3579 DBusTypeReader *reader,
3585 check_expected_type (reader, node->klass->typecode);
3587 _dbus_type_reader_read_basic (reader,
3590 expected = double_from_seed (seed);
3592 if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
3594 #ifdef DBUS_HAVE_INT64
3595 _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
3597 *(dbus_uint64_t*)&expected,
3598 *(dbus_uint64_t*)&v);
3600 _dbus_assert_not_reached ("test failed");
3607 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
3609 object_path_from_seed (char *buf,
3615 v = (unsigned char) ('A' + seed);
3620 if (v < 'A' || v > 'z')
3635 object_path_write_value (TestTypeNode *node,
3637 DBusTypeWriter *writer,
3640 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3641 const char *v_string = buf;
3643 object_path_from_seed (buf, seed);
3645 return _dbus_type_writer_write_basic (writer,
3646 node->klass->typecode,
3651 object_path_read_value (TestTypeNode *node,
3652 DBusTypeReader *reader,
3656 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3658 check_expected_type (reader, node->klass->typecode);
3660 _dbus_type_reader_read_basic (reader,
3661 (const char **) &v);
3663 object_path_from_seed (buf, seed);
3665 if (strcmp (buf, v) != 0)
3667 _dbus_warn ("read object path '%s' expected '%s'\n",
3669 _dbus_assert_not_reached ("test failed");
3676 #define MAX_SAMPLE_SIGNATURE_LEN 10
3678 signature_from_seed (char *buf,
3683 const char *sample_signatures[] = {
3692 s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
3694 for (i = 0; s[i]; i++)
3702 signature_write_value (TestTypeNode *node,
3704 DBusTypeWriter *writer,
3707 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3708 const char *v_string = buf;
3710 signature_from_seed (buf, seed);
3712 return _dbus_type_writer_write_basic (writer,
3713 node->klass->typecode,
3718 signature_read_value (TestTypeNode *node,
3719 DBusTypeReader *reader,
3723 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3725 check_expected_type (reader, node->klass->typecode);
3727 _dbus_type_reader_read_basic (reader,
3728 (const char **) &v);
3730 signature_from_seed (buf, seed);
3732 if (strcmp (buf, v) != 0)
3734 _dbus_warn ("read signature value '%s' expected '%s'\n",
3736 _dbus_assert_not_reached ("test failed");
3743 struct_write_value (TestTypeNode *node,
3745 DBusTypeWriter *writer,
3748 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3749 DataBlockState saved;
3754 n_copies = node->klass->subclass_detail;
3756 _dbus_assert (container->children != NULL);
3758 data_block_save (block, &saved);
3760 if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT,
3766 while (i < n_copies)
3770 link = _dbus_list_get_first_link (&container->children);
3771 while (link != NULL)
3773 TestTypeNode *child = link->data;
3774 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3776 if (!node_write_value (child, block, &sub, seed + i))
3778 data_block_restore (block, &saved);
3788 if (!_dbus_type_writer_unrecurse (writer, &sub))
3790 data_block_restore (block, &saved);
3798 struct_read_value (TestTypeNode *node,
3799 DBusTypeReader *reader,
3802 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3807 n_copies = node->klass->subclass_detail;
3809 check_expected_type (reader, DBUS_TYPE_STRUCT);
3811 _dbus_type_reader_recurse (reader, &sub);
3814 while (i < n_copies)
3818 link = _dbus_list_get_first_link (&container->children);
3819 while (link != NULL)
3821 TestTypeNode *child = link->data;
3822 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3824 if (!node_read_value (child, &sub, seed + i))
3827 if (i == (n_copies - 1) && next == NULL)
3828 NEXT_EXPECTING_FALSE (&sub);
3830 NEXT_EXPECTING_TRUE (&sub);
3842 struct_build_signature (TestTypeNode *node,
3845 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3850 n_copies = node->klass->subclass_detail;
3852 orig_len = _dbus_string_get_length (str);
3854 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3858 while (i < n_copies)
3862 link = _dbus_list_get_first_link (&container->children);
3863 while (link != NULL)
3865 TestTypeNode *child = link->data;
3866 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3868 if (!node_build_signature (child, str))
3877 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3883 _dbus_string_set_length (str, orig_len);
3888 array_write_value (TestTypeNode *node,
3890 DBusTypeWriter *writer,
3893 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3894 DataBlockState saved;
3896 DBusString element_signature;
3900 n_copies = node->klass->subclass_detail;
3902 _dbus_assert (container->children != NULL);
3904 data_block_save (block, &saved);
3906 if (!_dbus_string_init (&element_signature))
3909 if (!node_build_signature (_dbus_list_get_first (&container->children),
3910 &element_signature))
3913 if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
3914 &element_signature, 0,
3919 while (i < n_copies)
3923 link = _dbus_list_get_first_link (&container->children);
3924 while (link != NULL)
3926 TestTypeNode *child = link->data;
3927 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3929 if (!node_write_value (child, block, &sub, seed + i))
3938 if (!_dbus_type_writer_unrecurse (writer, &sub))
3941 _dbus_string_free (&element_signature);
3945 data_block_restore (block, &saved);
3946 _dbus_string_free (&element_signature);
3951 array_read_value (TestTypeNode *node,
3952 DBusTypeReader *reader,
3955 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3960 n_copies = node->klass->subclass_detail;
3962 check_expected_type (reader, DBUS_TYPE_ARRAY);
3966 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3968 _dbus_type_reader_recurse (reader, &sub);
3971 while (i < n_copies)
3975 link = _dbus_list_get_first_link (&container->children);
3976 while (link != NULL)
3978 TestTypeNode *child = link->data;
3979 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3981 if (!node_read_value (child, &sub, seed + i))
3984 if (i == (n_copies - 1) && next == NULL)
3985 NEXT_EXPECTING_FALSE (&sub);
3987 NEXT_EXPECTING_TRUE (&sub);
3997 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
4004 array_build_signature (TestTypeNode *node,
4007 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4010 orig_len = _dbus_string_get_length (str);
4012 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
4015 if (!node_build_signature (_dbus_list_get_first (&container->children),
4022 _dbus_string_set_length (str, orig_len);
4026 /* 10 is random just to add another seed that we use in the suite */
4027 #define VARIANT_SEED 10
4030 variant_write_value (TestTypeNode *node,
4032 DBusTypeWriter *writer,
4035 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4036 DataBlockState saved;
4038 DBusString content_signature;
4039 TestTypeNode *child;
4041 _dbus_assert (container->children != NULL);
4042 _dbus_assert (_dbus_list_length_is_one (&container->children));
4044 child = _dbus_list_get_first (&container->children);
4046 data_block_save (block, &saved);
4048 if (!_dbus_string_init (&content_signature))
4051 if (!node_build_signature (child,
4052 &content_signature))
4055 if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_VARIANT,
4056 &content_signature, 0,
4060 if (!node_write_value (child, block, &sub, seed + VARIANT_SEED))
4063 if (!_dbus_type_writer_unrecurse (writer, &sub))
4066 _dbus_string_free (&content_signature);
4070 data_block_restore (block, &saved);
4071 _dbus_string_free (&content_signature);
4076 variant_read_value (TestTypeNode *node,
4077 DBusTypeReader *reader,
4080 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4082 TestTypeNode *child;
4084 _dbus_assert (container->children != NULL);
4085 _dbus_assert (_dbus_list_length_is_one (&container->children));
4087 child = _dbus_list_get_first (&container->children);
4089 check_expected_type (reader, DBUS_TYPE_VARIANT);
4091 _dbus_type_reader_recurse (reader, &sub);
4093 if (!node_read_value (child, &sub, seed + VARIANT_SEED))
4096 NEXT_EXPECTING_FALSE (&sub);
4102 container_destroy (TestTypeNode *node)
4104 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
4107 link = _dbus_list_get_first_link (&container->children);
4108 while (link != NULL)
4110 TestTypeNode *child = link->data;
4111 DBusList *next = _dbus_list_get_next_link (&container->children, link);
4113 node_destroy (child);
4115 _dbus_list_free_link (link);
4121 #endif /* DBUS_BUILD_TESTS */