1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c Marshalling routines for recursive types
4 * Copyright (C) 2004 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-internals.h"
28 * @addtogroup DBusMarshal
31 #define RECURSIVE_MARSHAL_TRACE 0
33 struct DBusTypeReaderClass
36 dbus_bool_t types_only; /* only iterates over types, not values */
37 void (* recurse) (DBusTypeReader *sub,
38 DBusTypeReader *parent);
39 int (* get_current_type) (DBusTypeReader *reader);
40 void (* next) (DBusTypeReader *reader,
45 first_type_in_signature (const DBusString *str,
50 t = _dbus_string_get_byte (str, pos);
52 if (t == DBUS_STRUCT_BEGIN_CHAR)
53 return DBUS_TYPE_STRUCT;
59 element_type_get_alignment (const DBusString *str,
62 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
66 reader_init (DBusTypeReader *reader,
68 const DBusString *type_str,
70 const DBusString *value_str,
73 reader->byte_order = byte_order;
74 reader->finished = FALSE;
75 reader->type_str = type_str;
76 reader->type_pos = type_pos;
77 reader->value_str = value_str;
78 reader->value_pos = value_pos;
82 base_reader_recurse (DBusTypeReader *sub,
83 DBusTypeReader *parent)
85 /* point subreader at the same place as parent */
95 struct_types_only_reader_recurse (DBusTypeReader *sub,
96 DBusTypeReader *parent)
98 base_reader_recurse (sub, parent);
100 _dbus_assert (_dbus_string_get_byte (sub->type_str,
101 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
107 struct_reader_recurse (DBusTypeReader *sub,
108 DBusTypeReader *parent)
110 struct_types_only_reader_recurse (sub, parent);
112 /* struct has 8 byte alignment */
113 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
117 array_types_only_reader_recurse (DBusTypeReader *sub,
118 DBusTypeReader *parent)
120 base_reader_recurse (sub, parent);
122 /* point type_pos at the array element type */
125 sub->u.array.element_type = first_type_in_signature (sub->type_str,
128 /* Init with values likely to crash things if misused */
129 sub->u.array.start_pos = _DBUS_INT_MAX;
130 sub->u.array.len = _DBUS_INT_MAX;
134 array_reader_recurse (DBusTypeReader *sub,
135 DBusTypeReader *parent)
137 dbus_uint32_t array_len;
140 _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
142 array_types_only_reader_recurse (sub, parent);
144 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
146 _dbus_demarshal_basic_type (sub->value_str,
152 sub->u.array.len = array_len;
154 alignment = element_type_get_alignment (sub->type_str,
157 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
159 sub->u.array.start_pos = sub->value_pos;
161 #if RECURSIVE_MARSHAL_TRACE
162 _dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n",
164 sub->u.array.start_pos,
166 _dbus_type_to_string (sub->u.array.element_type));
171 variant_reader_recurse (DBusTypeReader *sub,
172 DBusTypeReader *parent)
176 base_reader_recurse (sub, parent);
178 /* Variant is 1 byte sig length (without nul), signature with nul,
179 * padding to 8-boundary, then values
182 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
184 sub->type_str = sub->value_str;
185 sub->type_pos = sub->value_pos + 1;
187 sub->value_pos = sub->type_pos + sig_len + 1;
189 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
191 #if RECURSIVE_MARSHAL_TRACE
192 _dbus_verbose (" type reader %p variant containing '%s'\n",
194 _dbus_string_get_const_data_len (sub->type_str,
200 base_reader_get_current_type (DBusTypeReader *reader)
204 t = first_type_in_signature (reader->type_str,
211 struct_reader_get_current_type (DBusTypeReader *reader)
215 if (reader->finished)
216 t = DBUS_TYPE_INVALID;
218 t = first_type_in_signature (reader->type_str,
225 array_types_only_reader_get_current_type (DBusTypeReader *reader)
229 if (reader->finished)
230 t = DBUS_TYPE_INVALID;
232 t = reader->u.array.element_type;
238 array_reader_get_current_type (DBusTypeReader *reader)
243 /* return the array element type if elements remain, and
244 * TYPE_INVALID otherwise
247 end_pos = reader->u.array.start_pos + reader->u.array.len;
249 _dbus_assert (reader->value_pos <= end_pos);
250 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
252 if (reader->value_pos < end_pos)
253 t = reader->u.array.element_type;
255 t = DBUS_TYPE_INVALID;
261 skip_one_complete_type (const DBusString *type_str,
264 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
267 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
274 switch (_dbus_string_get_byte (type_str, *type_pos))
276 case DBUS_STRUCT_BEGIN_CHAR:
279 case DBUS_STRUCT_END_CHAR:
282 case DBUS_TYPE_INVALID:
283 _dbus_assert_not_reached ("unbalanced parens in signature");
294 skip_array_values (int element_type,
295 const DBusString *value_str,
299 dbus_uint32_t array_len;
303 pos = _DBUS_ALIGN_VALUE (*value_pos, 4);
305 _dbus_demarshal_basic_type (value_str,
311 alignment = _dbus_type_get_alignment (element_type);
313 pos = _DBUS_ALIGN_VALUE (pos, alignment);
315 *value_pos = pos + array_len;
319 base_reader_next (DBusTypeReader *reader,
322 switch (current_type)
324 case DBUS_TYPE_STRUCT:
325 case DBUS_TYPE_VARIANT:
326 /* Scan forward over the entire container contents */
330 /* Recurse into the struct or variant */
331 _dbus_type_reader_recurse (reader, &sub);
333 /* Skip everything in this subreader */
334 while (_dbus_type_reader_next (&sub))
339 /* Now we are at the end of this container; for variants, the
340 * subreader's type_pos is totally inapplicable (it's in the
341 * value string) but we know that we increment by one past the
344 if (current_type == DBUS_TYPE_VARIANT)
345 reader->type_pos += 1;
347 reader->type_pos = sub.type_pos;
349 if (!reader->klass->types_only)
350 reader->value_pos = sub.value_pos;
354 case DBUS_TYPE_ARRAY:
356 if (!reader->klass->types_only)
357 skip_array_values (first_type_in_signature (reader->type_str,
358 reader->type_pos + 1),
359 reader->value_str, &reader->value_pos, reader->byte_order);
361 skip_one_complete_type (reader->type_str, &reader->type_pos);
366 if (!reader->klass->types_only)
367 _dbus_marshal_skip_basic_type (reader->value_str,
368 current_type, reader->byte_order,
371 reader->type_pos += 1;
377 struct_reader_next (DBusTypeReader *reader,
382 base_reader_next (reader, current_type);
384 /* for STRUCT containers we return FALSE at the end of the struct,
385 * for INVALID we return FALSE at the end of the signature.
386 * In both cases we arrange for get_current_type() to return INVALID
387 * which is defined to happen iff we're at the end (no more next())
389 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
390 if (t == DBUS_STRUCT_END_CHAR)
392 reader->type_pos += 1;
393 reader->finished = TRUE;
398 array_types_only_reader_next (DBusTypeReader *reader,
401 /* We have one "element" to be iterated over
402 * in each array, which is its element type.
403 * So the finished flag indicates whether we've
404 * iterated over it yet or not.
406 reader->finished = TRUE;
410 array_reader_next (DBusTypeReader *reader,
413 /* Skip one array element */
416 end_pos = reader->u.array.start_pos + reader->u.array.len;
418 _dbus_assert (reader->value_pos < end_pos);
419 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
421 switch (reader->u.array.element_type)
423 case DBUS_TYPE_STRUCT:
424 case DBUS_TYPE_VARIANT:
428 /* Recurse into the struct or variant */
429 _dbus_type_reader_recurse (reader, &sub);
431 /* Skip everything in this element */
432 while (_dbus_type_reader_next (&sub))
437 /* Now we are at the end of this element */
438 reader->value_pos = sub.value_pos;
442 case DBUS_TYPE_ARRAY:
444 skip_array_values (first_type_in_signature (reader->type_str,
445 reader->type_pos + 1),
446 reader->value_str, &reader->value_pos, reader->byte_order);
452 _dbus_marshal_skip_basic_type (reader->value_str,
453 current_type, reader->byte_order,
459 _dbus_assert (reader->value_pos <= end_pos);
461 if (reader->value_pos == end_pos)
463 skip_one_complete_type (reader->type_str,
468 static const DBusTypeReaderClass body_reader_class = {
471 NULL, /* body is always toplevel, so doesn't get recursed into */
472 base_reader_get_current_type,
476 static const DBusTypeReaderClass body_types_only_reader_class = {
479 NULL, /* body is always toplevel, so doesn't get recursed into */
480 base_reader_get_current_type,
484 static const DBusTypeReaderClass struct_reader_class = {
487 struct_reader_recurse,
488 struct_reader_get_current_type,
492 static const DBusTypeReaderClass struct_types_only_reader_class = {
495 struct_types_only_reader_recurse,
496 struct_reader_get_current_type,
500 static const DBusTypeReaderClass array_reader_class = {
503 array_reader_recurse,
504 array_reader_get_current_type,
508 static const DBusTypeReaderClass array_types_only_reader_class = {
511 array_types_only_reader_recurse,
512 array_types_only_reader_get_current_type,
513 array_types_only_reader_next
516 static const DBusTypeReaderClass variant_reader_class = {
519 variant_reader_recurse,
520 base_reader_get_current_type,
525 _dbus_type_reader_init (DBusTypeReader *reader,
527 const DBusString *type_str,
529 const DBusString *value_str,
532 reader->klass = &body_reader_class;
534 reader_init (reader, byte_order, type_str, type_pos,
535 value_str, value_pos);
537 #if RECURSIVE_MARSHAL_TRACE
538 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
539 reader, reader->type_pos, reader->value_pos,
540 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
545 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
546 const DBusString *type_str,
549 reader->klass = &body_types_only_reader_class;
551 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
552 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
554 #if RECURSIVE_MARSHAL_TRACE
555 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
556 reader, reader->type_pos,
557 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
562 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
566 t = (* reader->klass->get_current_type) (reader);
568 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
569 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
572 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
573 reader, reader->type_pos,
574 _dbus_type_to_string (t));
581 _dbus_type_reader_array_is_empty (DBusTypeReader *reader)
583 dbus_uint32_t array_len;
586 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
587 _dbus_assert (!reader->klass->types_only);
589 len_pos = _DBUS_ALIGN_VALUE (reader->value_pos, 4);
591 _dbus_demarshal_basic_type (reader->value_str,
597 return array_len == 0;
601 _dbus_type_reader_read_basic (DBusTypeReader *reader,
607 _dbus_assert (!reader->klass->types_only);
609 t = _dbus_type_reader_get_current_type (reader);
611 next = reader->value_pos;
612 _dbus_demarshal_basic_type (reader->value_str,
618 #if RECURSIVE_MARSHAL_TRACE
619 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
620 reader, reader->type_pos, reader->value_pos, next,
621 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
626 _dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
631 _dbus_assert (!reader->klass->types_only);
636 * Initialize a new reader pointing to the first type and
637 * corresponding value that's a child of the current container. It's
638 * an error to call this if the current type is a non-container.
640 * Note that DBusTypeReader traverses values, not types. So if you
641 * have an empty array of array of int, you can't recurse into it. You
642 * can only recurse into each element.
644 * @param reader the reader
645 * @param sub a reader to init pointing to the first child
648 _dbus_type_reader_recurse (DBusTypeReader *reader,
653 t = first_type_in_signature (reader->type_str, reader->type_pos);
657 case DBUS_TYPE_STRUCT:
658 if (reader->klass->types_only)
659 sub->klass = &struct_types_only_reader_class;
661 sub->klass = &struct_reader_class;
663 case DBUS_TYPE_ARRAY:
664 if (reader->klass->types_only)
665 sub->klass = &array_types_only_reader_class;
667 sub->klass = &array_reader_class;
669 case DBUS_TYPE_VARIANT:
670 if (reader->klass->types_only)
671 _dbus_assert_not_reached ("can't recurse into variant typecode");
673 sub->klass = &variant_reader_class;
676 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
677 #ifndef DBUS_DISABLE_CHECKS
678 if (t == DBUS_TYPE_INVALID)
679 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
680 #endif /* DBUS_DISABLE_CHECKS */
682 _dbus_assert_not_reached ("don't yet handle recursing into this type");
685 (* sub->klass->recurse) (sub, reader);
687 #if RECURSIVE_MARSHAL_TRACE
688 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
689 sub, sub->type_pos, sub->value_pos,
690 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
695 * Skip to the next value on this "level". e.g. the next field in a
696 * struct, the next value in an array, the next key or value in a
697 * dict. Returns FALSE at the end of the current container.
699 * @param reader the reader
700 * @returns FALSE if nothing more to read at or below this level
703 _dbus_type_reader_next (DBusTypeReader *reader)
707 t = _dbus_type_reader_get_current_type (reader);
709 #if RECURSIVE_MARSHAL_TRACE
710 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
711 reader, reader->type_pos, reader->value_pos,
712 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
713 _dbus_type_to_string (t));
716 if (t == DBUS_TYPE_INVALID)
719 (* reader->klass->next) (reader, t);
721 #if RECURSIVE_MARSHAL_TRACE
722 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
723 reader, reader->type_pos, reader->value_pos,
724 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
725 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
728 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
742 _dbus_type_writer_init (DBusTypeWriter *writer,
744 DBusString *type_str,
746 DBusString *value_str,
749 writer->byte_order = byte_order;
750 writer->type_str = type_str;
751 writer->type_pos = type_pos;
752 writer->value_str = value_str;
753 writer->value_pos = value_pos;
754 writer->container_type = DBUS_TYPE_INVALID;
755 writer->type_pos_is_expectation = FALSE;
757 #if RECURSIVE_MARSHAL_TRACE
758 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
759 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
764 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
771 old_value_len = _dbus_string_get_length (writer->value_str);
773 if (!_dbus_marshal_basic_type (writer->value_str,
780 bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
782 writer->value_pos += bytes_written;
787 /* If our parent is an array, things are a little bit complicated.
789 * The parent must have a complete element type, such as
790 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
791 * unclosed parens, or an "a" with no following type.
793 * To recurse, the only allowed operation is to recurse into the
794 * first type in the element type. So for "i" you can't recurse, for
795 * "ai" you can recurse into the array, for "(ii)" you can recurse
798 * If you recurse into the array for "ai", then you must specify
799 * "i" for the element type of the array you recurse into.
801 * While inside an array at any level, we need to avoid writing to
802 * type_str, since the type only appears once for the whole array,
803 * it does not appear for each array element.
805 * While inside an array type_pos points to the expected next
806 * typecode, rather than the next place we could write a typecode.
809 writer_recurse_init_and_check (DBusTypeWriter *writer,
813 _dbus_type_writer_init (sub,
820 sub->container_type = container_type;
822 if (writer->type_pos_is_expectation ||
823 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
824 sub->type_pos_is_expectation = TRUE;
826 sub->type_pos_is_expectation = FALSE;
828 #ifndef DBUS_DISABLE_CHECKS
829 if (writer->type_pos_is_expectation)
833 expected = first_type_in_signature (writer->type_str, writer->type_pos);
835 if (expected != sub->container_type)
837 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
838 _dbus_type_to_string (sub->container_type),
839 _dbus_type_to_string (expected));
840 _dbus_assert_not_reached ("bad array element or variant content written");
843 #endif /* DBUS_DISABLE_CHECKS */
845 #if RECURSIVE_MARSHAL_TRACE
846 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
848 _dbus_type_to_string (writer->container_type),
849 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
850 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
851 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d\n",
853 _dbus_type_to_string (sub->container_type),
854 sub->type_pos, sub->value_pos,
855 sub->type_pos_is_expectation);
860 write_or_verify_typecode (DBusTypeWriter *writer,
863 /* A subwriter inside an array or variant will have type_pos
864 * pointing to the expected typecode; a writer not inside an array
865 * or variant has type_pos pointing to the next place to insert a
868 #if RECURSIVE_MARSHAL_TRACE
869 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
870 writer, writer->type_pos,
871 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
874 if (writer->type_pos_is_expectation)
876 #ifndef DBUS_DISABLE_CHECKS
880 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
882 if (expected != typecode)
884 _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
885 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
886 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
889 #endif /* DBUS_DISABLE_CHECKS */
891 /* if immediately inside an array we'd always be appending an element,
892 * so the expected type doesn't change; if inside a struct or something
893 * below an array, we need to move through said struct or something.
895 if (writer->container_type != DBUS_TYPE_ARRAY)
896 writer->type_pos += 1;
900 if (!_dbus_string_insert_byte (writer->type_str,
905 writer->type_pos += 1;
908 #if RECURSIVE_MARSHAL_TRACE
909 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
910 writer, writer->type_pos,
911 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
918 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
921 writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
923 /* Ensure that we'll be able to add alignment padding and the typecode */
924 if (!_dbus_string_alloc_space (sub->value_str, 8))
927 if (!_dbus_string_alloc_space (sub->type_str, 1))
930 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
931 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
933 if (!_dbus_string_insert_bytes (sub->value_str,
935 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
937 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
938 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
944 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
945 const char *element_type,
948 int element_type_len;
949 DBusString element_type_str;
950 dbus_uint32_t value = 0;
955 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
957 _dbus_string_init_const (&element_type_str, element_type);
958 element_type_len = _dbus_string_get_length (&element_type_str);
960 #ifndef DBUS_DISABLE_CHECKS
961 if (writer->container_type == DBUS_TYPE_ARRAY)
963 if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
964 writer->type_str, writer->u.array.element_type_pos + 1))
966 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
968 _dbus_assert_not_reached ("incompatible type for child array");
971 #endif /* DBUS_DISABLE_CHECKS */
973 /* 4 bytes for the array length and 4 bytes possible padding */
974 if (!_dbus_string_alloc_space (sub->value_str, 8))
977 sub->type_pos += 1; /* move to point to the element type, since type_pos
978 * should be the expected type for further writes
980 sub->u.array.element_type_pos = sub->type_pos;
982 if (!writer->type_pos_is_expectation)
984 /* sub is a toplevel/outermost array so we need to write the type data */
986 /* alloc space for array typecode, element signature, possible 7
989 if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
992 if (!_dbus_string_insert_byte (writer->type_str,
995 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
997 if (!_dbus_string_copy (&element_type_str, 0,
998 sub->type_str, sub->u.array.element_type_pos))
999 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1002 /* If the parent is an array, we hold type_pos pointing at the array element type;
1003 * otherwise advance it to reflect the array value we just recursed into
1005 if (writer->container_type != DBUS_TYPE_ARRAY)
1006 writer->type_pos += 1 + element_type_len;
1008 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1010 /* Write the length */
1011 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1013 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1015 _dbus_assert_not_reached ("should not have failed to insert array len");
1017 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1019 /* Write alignment padding for array elements */
1020 _dbus_string_init_const (&str, element_type);
1021 alignment = element_type_get_alignment (&str, 0);
1023 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1024 if (aligned != sub->value_pos)
1026 if (!_dbus_string_insert_bytes (sub->value_str,
1028 aligned - sub->value_pos,
1030 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1032 sub->value_pos = aligned;
1034 sub->u.array.start_pos = sub->value_pos;
1036 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1037 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1039 #if RECURSIVE_MARSHAL_TRACE
1040 _dbus_verbose (" type writer %p recurse array done remaining sig '%s'\n", sub,
1041 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
1047 /* Variant value will normally have:
1048 * 1 byte signature length not including nul
1049 * signature typecodes (nul terminated)
1050 * padding to 8-boundary
1051 * body according to signature
1053 * The signature string can only have a single type
1054 * in it but that type may be complex/recursive.
1056 * So a typical variant type with the integer 3 will have these
1058 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1060 * For an array of 4-byte types stuffed into variants, the padding to
1061 * 8-boundary is only the 1 byte that is required for the 4-boundary
1062 * anyhow for all array elements after the first one. And for single
1063 * variants in isolation, wasting a few bytes is hardly a big deal.
1065 * The main world of hurt for writing out a variant is that the type
1066 * string is the same string as the value string. Which means
1067 * inserting to the type string will move the value_pos; and it means
1068 * that inserting to the type string could break type alignment.
1070 * This type alignment issue is why the body of the variant is always
1071 * 8-aligned. Then we know that re-8-aligning the start of the body
1072 * will always correctly align the full contents of the variant type.
1075 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1076 const char *contained_type,
1077 DBusTypeWriter *sub)
1079 int contained_type_len;
1080 DBusString contained_type_str;
1082 writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1084 _dbus_string_init_const (&contained_type_str, contained_type);
1086 contained_type_len = _dbus_string_get_length (&contained_type_str);
1088 /* Allocate space for the worst case, which is 1 byte sig
1089 * length, nul byte at end of sig, and 7 bytes padding to
1092 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1095 /* write VARIANT typecode to the parent's type string */
1096 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1099 if (!_dbus_string_insert_byte (sub->value_str,
1101 contained_type_len))
1102 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1104 sub->value_pos += 1;
1106 /* Here we switch over to the expected type sig we're about to write */
1107 sub->type_str = sub->value_str;
1108 sub->type_pos = sub->value_pos;
1110 if (!_dbus_string_copy (&contained_type_str, 0,
1111 sub->value_str, sub->value_pos))
1112 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1114 sub->value_pos += contained_type_len;
1116 if (!_dbus_string_insert_byte (sub->value_str,
1119 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1121 sub->value_pos += 1;
1123 if (!_dbus_string_insert_bytes (sub->value_str,
1125 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1127 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1128 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1134 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1135 DBusTypeWriter *sub)
1137 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1139 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1140 _dbus_assert (!writer->type_pos_is_expectation ||
1141 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1143 #if RECURSIVE_MARSHAL_TRACE
1144 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1145 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1146 _dbus_type_to_string (writer->container_type));
1147 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1148 sub, sub->type_pos, sub->value_pos,
1149 sub->type_pos_is_expectation,
1150 _dbus_type_to_string (sub->container_type));
1153 if (sub->container_type == DBUS_TYPE_STRUCT)
1155 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1158 else if (sub->container_type == DBUS_TYPE_ARRAY)
1162 /* Set the array length */
1163 len = sub->value_pos - sub->u.array.start_pos;
1164 _dbus_marshal_set_uint32 (sub->value_str,
1166 sub->u.array.len_pos,
1168 #if RECURSIVE_MARSHAL_TRACE
1169 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1170 len, sub->u.array.len_pos);
1174 /* Now get type_pos right for the parent writer. Here are the cases:
1176 * Cases !writer->type_pos_is_expectation:
1177 * (in these cases we want to update to the new insertion point)
1179 * - if we recursed into a STRUCT then we didn't know in advance
1180 * what the types in the struct would be; so we have to fill in
1181 * that information now.
1182 * writer->type_pos = sub->type_pos
1184 * - if we recursed into anything else, we knew the full array
1185 * type, or knew the single typecode marking VARIANT, so
1186 * writer->type_pos is already correct.
1187 * writer->type_pos should remain as-is
1189 * - note that the parent is never an ARRAY or VARIANT, if it were
1190 * then type_pos_is_expectation would be TRUE. The parent
1191 * is thus known to be a toplevel or STRUCT.
1193 * Cases where writer->type_pos_is_expectation:
1194 * (in these cases we want to update to next expected type to write)
1196 * - we recursed from STRUCT into STRUCT and we didn't increment
1197 * type_pos in the parent just to stay consistent with the
1198 * !writer->type_pos_is_expectation case (though we could
1199 * special-case this in recurse_struct instead if we wanted)
1200 * writer->type_pos = sub->type_pos
1202 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1203 * for parent should have been incremented already
1204 * writer->type_pos should remain as-is
1206 * - we recursed from ARRAY into a sub-element, so type_pos in the
1207 * parent is the element type and should remain the element type
1208 * for the benefit of the next child element
1209 * writer->type_pos should remain as-is
1211 * - we recursed from VARIANT into its value, so type_pos in the
1212 * parent makes no difference since there's only one value
1213 * and we just finished writing it and won't use type_pos again
1214 * writer->type_pos should remain as-is
1216 if (sub->container_type == DBUS_TYPE_STRUCT &&
1217 (writer->container_type == DBUS_TYPE_STRUCT ||
1218 writer->container_type == DBUS_TYPE_INVALID))
1220 /* Advance the parent to the next struct field */
1221 writer->type_pos = sub->type_pos;
1224 writer->value_pos = sub->value_pos;
1226 #if RECURSIVE_MARSHAL_TRACE
1227 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1228 writer, writer->type_pos, writer->value_pos,
1229 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1236 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1242 /* First ensure that our type realloc will succeed */
1243 if (!_dbus_string_alloc_space (writer->type_str, 1))
1248 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1251 if (!write_or_verify_typecode (writer, type))
1252 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1257 #if RECURSIVE_MARSHAL_TRACE
1258 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1259 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1266 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1275 /** @} */ /* end of DBusMarshal group */
1277 #ifdef DBUS_BUILD_TESTS
1278 #include "dbus-test.h"
1279 #include "dbus-list.h"
1285 DBusString signature;
1296 data_block_init (DataBlock *block)
1298 if (!_dbus_string_init (&block->signature))
1301 if (!_dbus_string_init (&block->body))
1303 _dbus_string_free (&block->signature);
1311 data_block_free (DataBlock *block)
1313 _dbus_string_free (&block->signature);
1314 _dbus_string_free (&block->body);
1318 data_block_save (DataBlock *block,
1319 DataBlockState *state)
1321 state->saved_sig_len = _dbus_string_get_length (&block->signature);
1322 state->saved_body_len = _dbus_string_get_length (&block->body);
1326 data_block_restore (DataBlock *block,
1327 DataBlockState *state)
1329 /* These set_length should be shortening things so should always work */
1331 if (!_dbus_string_set_length (&block->signature,
1332 state->saved_sig_len))
1333 _dbus_assert_not_reached ("could not restore signature length");
1335 if (!_dbus_string_set_length (&block->body,
1336 state->saved_body_len))
1337 _dbus_assert_not_reached ("could not restore body length");
1341 data_block_init_reader_writer (DataBlock *block,
1343 DBusTypeReader *reader,
1344 DBusTypeWriter *writer)
1346 _dbus_type_reader_init (reader,
1349 _dbus_string_get_length (&block->signature),
1351 _dbus_string_get_length (&block->body));
1353 _dbus_type_writer_init (writer,
1356 _dbus_string_get_length (&block->signature),
1358 _dbus_string_get_length (&block->body));
1362 real_check_expected_type (DBusTypeReader *reader,
1364 const char *funcname,
1369 t = _dbus_type_reader_get_current_type (reader);
1373 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1374 _dbus_type_to_string (t),
1375 _dbus_type_to_string (expected),
1382 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1384 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
1386 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
1387 _DBUS_FUNCTION_NAME, __LINE__); \
1388 _dbus_assert_not_reached ("test failed"); \
1392 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
1394 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
1395 _DBUS_FUNCTION_NAME, __LINE__); \
1396 _dbus_assert_not_reached ("test failed"); \
1398 check_expected_type (reader, DBUS_TYPE_INVALID); \
1401 #define SAMPLE_INT32 12345678
1402 #define SAMPLE_INT32_ALTERNATE 53781429
1404 typedef struct TestTypeNode TestTypeNode;
1405 typedef struct TestTypeNodeClass TestTypeNodeClass;
1406 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
1407 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1411 const TestTypeNodeClass *klass;
1414 struct TestTypeNodeContainer
1420 struct TestTypeNodeClass
1426 dbus_bool_t (* construct) (TestTypeNode *node);
1427 void (* destroy) (TestTypeNode *node);
1429 dbus_bool_t (* write_value) (TestTypeNode *node,
1431 DBusTypeWriter *writer,
1433 dbus_bool_t (* read_value) (TestTypeNode *node,
1435 DBusTypeReader *reader,
1437 dbus_bool_t (* build_signature) (TestTypeNode *node,
1441 struct TestTypeNodeContainerClass
1443 TestTypeNodeClass base;
1446 static dbus_bool_t int32_write_value (TestTypeNode *node,
1448 DBusTypeWriter *writer,
1450 static dbus_bool_t int32_read_value (TestTypeNode *node,
1452 DBusTypeReader *reader,
1454 static dbus_bool_t int64_write_value (TestTypeNode *node,
1456 DBusTypeWriter *writer,
1458 static dbus_bool_t int64_read_value (TestTypeNode *node,
1460 DBusTypeReader *reader,
1462 static dbus_bool_t struct_1_write_value (TestTypeNode *node,
1464 DBusTypeWriter *writer,
1466 static dbus_bool_t struct_1_read_value (TestTypeNode *node,
1468 DBusTypeReader *reader,
1470 static dbus_bool_t struct_1_build_signature (TestTypeNode *node,
1472 static dbus_bool_t struct_2_write_value (TestTypeNode *node,
1474 DBusTypeWriter *writer,
1476 static dbus_bool_t struct_2_read_value (TestTypeNode *node,
1478 DBusTypeReader *reader,
1480 static dbus_bool_t struct_2_build_signature (TestTypeNode *node,
1482 static dbus_bool_t array_build_signature (TestTypeNode *node,
1484 static dbus_bool_t array_1_write_value (TestTypeNode *node,
1486 DBusTypeWriter *writer,
1488 static dbus_bool_t array_1_read_value (TestTypeNode *node,
1490 DBusTypeReader *reader,
1492 static dbus_bool_t array_0_write_value (TestTypeNode *node,
1494 DBusTypeWriter *writer,
1496 static dbus_bool_t array_0_read_value (TestTypeNode *node,
1498 DBusTypeReader *reader,
1500 static dbus_bool_t array_2_write_value (TestTypeNode *node,
1502 DBusTypeWriter *writer,
1504 static dbus_bool_t array_2_read_value (TestTypeNode *node,
1506 DBusTypeReader *reader,
1508 static dbus_bool_t array_9_write_value (TestTypeNode *node,
1510 DBusTypeWriter *writer,
1512 static dbus_bool_t array_9_read_value (TestTypeNode *node,
1514 DBusTypeReader *reader,
1516 static dbus_bool_t variant_write_value (TestTypeNode *node,
1518 DBusTypeWriter *writer,
1520 static dbus_bool_t variant_read_value (TestTypeNode *node,
1522 DBusTypeReader *reader,
1524 static void container_destroy (TestTypeNode *node);
1528 static const TestTypeNodeClass int32_class = {
1530 sizeof (TestTypeNode),
1538 static const TestTypeNodeClass uint32_class = {
1540 sizeof (TestTypeNode),
1543 int32_write_value, /* recycle from int32 */
1544 int32_read_value, /* recycle from int32 */
1548 static const TestTypeNodeClass int64_class = {
1550 sizeof (TestTypeNode),
1558 static const TestTypeNodeClass uint64_class = {
1560 sizeof (TestTypeNode),
1563 int64_write_value, /* recycle from int64 */
1564 int64_read_value, /* recycle from int64 */
1568 static const TestTypeNodeClass struct_1_class = {
1570 sizeof (TestTypeNodeContainer),
1573 struct_1_write_value,
1574 struct_1_read_value,
1575 struct_1_build_signature
1578 static const TestTypeNodeClass struct_2_class = {
1580 sizeof (TestTypeNodeContainer),
1583 struct_2_write_value,
1584 struct_2_read_value,
1585 struct_2_build_signature
1588 static const TestTypeNodeClass array_0_class = {
1590 sizeof (TestTypeNodeContainer),
1593 array_0_write_value,
1595 array_build_signature
1598 static const TestTypeNodeClass array_1_class = {
1600 sizeof (TestTypeNodeContainer),
1603 array_1_write_value,
1605 array_build_signature
1608 static const TestTypeNodeClass array_2_class = {
1610 sizeof (TestTypeNodeContainer),
1613 array_2_write_value,
1615 array_build_signature
1618 static const TestTypeNodeClass array_9_class = {
1620 sizeof (TestTypeNodeContainer),
1623 array_9_write_value,
1625 array_build_signature
1628 static const TestTypeNodeClass variant_class = {
1630 sizeof (TestTypeNodeContainer),
1633 variant_write_value,
1638 static const TestTypeNodeClass* const
1645 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
1647 static const TestTypeNodeClass* const
1648 container_nodes[] = {
1655 /* array_9_class is omitted on purpose, it's too slow;
1656 * we only use it in one hardcoded test below
1659 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
1661 static TestTypeNode*
1662 node_new (const TestTypeNodeClass *klass)
1666 node = dbus_malloc0 (klass->instance_size);
1670 node->klass = klass;
1672 if (klass->construct)
1674 if (!(* klass->construct) (node))
1685 node_destroy (TestTypeNode *node)
1687 if (node->klass->destroy)
1688 (* node->klass->destroy) (node);
1693 node_write_value (TestTypeNode *node,
1695 DBusTypeWriter *writer,
1698 return (* node->klass->write_value) (node, block, writer, seed);
1702 node_read_value (TestTypeNode *node,
1704 DBusTypeReader *reader,
1707 return (* node->klass->read_value) (node, block, reader, seed);
1711 node_build_signature (TestTypeNode *node,
1714 if (node->klass->build_signature)
1715 return (* node->klass->build_signature) (node, str);
1717 return _dbus_string_append_byte (str, node->klass->typecode);
1721 node_append_child (TestTypeNode *node,
1722 TestTypeNode *child)
1724 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
1726 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
1728 if (!_dbus_list_append (&container->children, child))
1729 _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 */
1736 const DBusString *signature;
1740 TestTypeNode **nodes;
1742 } NodeIterationData;
1745 run_test_nodes_iteration (void *data)
1747 NodeIterationData *nid = data;
1748 DBusTypeReader reader;
1749 DBusTypeWriter writer;
1753 * 1. write the value
1754 * 2. strcmp-compare with the signature we built
1756 * 4. type-iterate the signature and the value and see if they are the same type-wise
1758 data_block_init_reader_writer (nid->block,
1763 while (i < nid->n_nodes)
1765 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
1771 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
1772 &nid->block->signature, nid->type_offset))
1774 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
1775 _dbus_string_get_const_data (nid->signature),
1776 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
1778 _dbus_assert_not_reached ("wrong signature");
1782 while (i < nid->n_nodes)
1784 if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
1787 if (i + 1 == nid->n_nodes)
1788 NEXT_EXPECTING_FALSE (&reader);
1790 NEXT_EXPECTING_TRUE (&reader);
1795 /* FIXME type-iterate both signature and value */
1801 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
1803 const DBusString *signature,
1808 NodeIterationData nid;
1810 if (!data_block_init (&block))
1811 _dbus_assert_not_reached ("no memory");
1813 if (!_dbus_string_lengthen (&block.signature, initial_offset))
1814 _dbus_assert_not_reached ("no memory");
1816 if (!_dbus_string_lengthen (&block.body, initial_offset))
1817 _dbus_assert_not_reached ("no memory");
1819 nid.signature = signature;
1821 nid.type_offset = initial_offset;
1823 nid.n_nodes = n_nodes;
1824 nid.byte_order = byte_order;
1826 /* FIXME put the OOM testing back once we debug everything and are willing to
1827 * wait for it to run ;-)
1830 _dbus_test_oom_handling ("running test node",
1831 run_test_nodes_iteration,
1834 if (!run_test_nodes_iteration (&nid))
1835 _dbus_assert_not_reached ("no memory");
1838 data_block_free (&block);
1842 run_test_nodes (TestTypeNode **nodes,
1846 DBusString signature;
1848 if (!_dbus_string_init (&signature))
1849 _dbus_assert_not_reached ("no memory");
1854 if (! node_build_signature (nodes[i], &signature))
1855 _dbus_assert_not_reached ("no memory");
1860 _dbus_verbose (">>> test nodes with signature '%s'\n",
1861 _dbus_string_get_const_data (&signature));
1863 /* We do start offset 0 through 9, to get various alignment cases. Still this
1864 * obviously makes the test suite run 10x as slow.
1869 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1870 DBUS_LITTLE_ENDIAN, i);
1871 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1872 DBUS_BIG_ENDIAN, i);
1877 _dbus_string_free (&signature);
1880 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
1882 static TestTypeNode*
1883 value_generator (int *ip)
1886 const TestTypeNodeClass *child_klass;
1887 const TestTypeNodeClass *container_klass;
1888 TestTypeNode *child;
1891 _dbus_assert (i <= N_VALUES);
1897 else if (i < N_BASICS)
1899 node = node_new (basic_nodes[i]);
1903 /* imagine an array:
1904 * container 0 of basic 0
1905 * container 0 of basic 1
1906 * container 0 of basic 2
1907 * container 1 of basic 0
1908 * container 1 of basic 1
1909 * container 1 of basic 2
1913 container_klass = container_nodes[i / N_BASICS];
1914 child_klass = basic_nodes[i % N_BASICS];
1916 node = node_new (container_klass);
1917 child = node_new (child_klass);
1919 node_append_child (node, child);
1922 *ip += 1; /* increment the generator */
1928 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
1932 TestTypeNode *container;
1933 TestTypeNode *child;
1936 root = node_new (container_klass);
1938 for (i = 1; i < n_nested; i++)
1940 child = node_new (container_klass);
1941 node_append_child (container, child);
1945 /* container should now be the most-nested container */
1948 while ((child = value_generator (&i)))
1950 node_append_child (container, child);
1952 run_test_nodes (&root, 1);
1954 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
1955 node_destroy (child);
1958 node_destroy (root);
1962 make_and_run_test_nodes (void)
1966 /* We try to do this in order of "complicatedness" so that test
1967 * failures tend to show up in the simplest test case that
1968 * demonstrates the failure. There are also some tests that run
1969 * more than once for this reason, first while going through simple
1970 * cases, second while going through a broader range of complex
1973 /* Each basic node. The basic nodes should include:
1975 * - each fixed-size type (in such a way that it has different values each time,
1976 * so we can tell if we mix two of them up)
1977 * - strings of length 0-9
1981 /* Each container node. The container nodes should include:
1983 * struct with 1 and 2 copies of the contained item
1984 * array with 0, 1, 2 copies of the contained item
1987 /* Let a "value" be a basic node, or a container containing a single basic node.
1988 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
1989 * When iterating through all values to make combinations, do the basic types
1990 * first and the containers second.
1992 /* Each item is shown with its number of iterations to complete so
1993 * we can keep a handle on this unit test
1996 /* FIXME test just an empty body, no types at all */
1998 _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
2003 while ((node = value_generator (&i)))
2005 run_test_nodes (&node, 1);
2007 node_destroy (node);
2011 _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
2013 TestTypeNode *nodes[N_VALUES];
2016 while ((nodes[i] = value_generator (&i)))
2019 run_test_nodes (nodes, N_VALUES);
2021 for (i = 0; i < N_VALUES; i++)
2022 node_destroy (nodes[i]);
2025 _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
2026 N_VALUES * N_VALUES * 2);
2028 TestTypeNode *nodes[2];
2031 while ((nodes[0] = value_generator (&i)))
2034 while ((nodes[1] = value_generator (&j)))
2036 run_test_nodes (nodes, 2);
2038 node_destroy (nodes[1]);
2041 node_destroy (nodes[0]);
2045 _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
2046 N_CONTAINERS * N_VALUES);
2047 for (i = 0; i < N_CONTAINERS; i++)
2049 const TestTypeNodeClass *container_klass = container_nodes[i];
2051 make_and_run_values_inside_container (container_klass, 1);
2054 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2055 N_CONTAINERS * N_VALUES);
2056 for (i = 0; i < N_CONTAINERS; i++)
2058 const TestTypeNodeClass *container_klass = container_nodes[i];
2060 make_and_run_values_inside_container (container_klass, 2);
2063 _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
2064 N_CONTAINERS * N_VALUES);
2065 for (i = 0; i < N_CONTAINERS; i++)
2067 const TestTypeNodeClass *container_klass = container_nodes[i];
2069 make_and_run_values_inside_container (container_klass, 3);
2072 _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
2073 N_VALUES * N_VALUES);
2075 TestTypeNode *val1, *val2;
2078 node = node_new (&struct_1_class);
2081 while ((val1 = value_generator (&i)))
2084 while ((val2 = value_generator (&j)))
2086 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2088 node_append_child (node, val1);
2089 node_append_child (node, val2);
2091 run_test_nodes (&node, 1);
2093 _dbus_list_clear (&container->children);
2094 node_destroy (val2);
2096 node_destroy (val1);
2098 node_destroy (node);
2101 _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
2104 TestTypeNode *child;
2106 node = node_new (&struct_1_class);
2109 while ((child = value_generator (&i)))
2110 node_append_child (node, child);
2112 run_test_nodes (&node, 1);
2114 node_destroy (node);
2117 _dbus_verbose (">>> >>> Each value in a large array %d iterations\n",
2123 node = node_new (&array_9_class);
2126 while ((val = value_generator (&i)))
2128 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2130 node_append_child (node, val);
2132 run_test_nodes (&node, 1);
2134 _dbus_list_clear (&container->children);
2138 node_destroy (node);
2141 _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
2142 N_CONTAINERS * N_CONTAINERS * N_VALUES);
2143 for (i = 0; i < N_CONTAINERS; i++)
2145 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2146 TestTypeNode *outer_container = node_new (outer_container_klass);
2148 for (j = 0; j < N_CONTAINERS; j++)
2150 TestTypeNode *child;
2151 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2152 TestTypeNode *inner_container = node_new (inner_container_klass);
2154 node_append_child (outer_container, inner_container);
2157 while ((child = value_generator (&m)))
2159 node_append_child (inner_container, child);
2161 run_test_nodes (&outer_container, 1);
2163 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2164 node_destroy (child);
2166 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2167 node_destroy (inner_container);
2169 node_destroy (outer_container);
2172 _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
2173 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2174 for (i = 0; i < N_CONTAINERS; i++)
2176 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2177 TestTypeNode *outer_container = node_new (outer_container_klass);
2179 for (j = 0; j < N_CONTAINERS; j++)
2181 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2182 TestTypeNode *inner_container = node_new (inner_container_klass);
2184 node_append_child (outer_container, inner_container);
2186 for (k = 0; k < N_CONTAINERS; k++)
2188 TestTypeNode *child;
2189 const TestTypeNodeClass *center_container_klass = container_nodes[k];
2190 TestTypeNode *center_container = node_new (center_container_klass);
2192 node_append_child (inner_container, center_container);
2195 while ((child = value_generator (&m)))
2197 node_append_child (center_container, child);
2199 run_test_nodes (&outer_container, 1);
2201 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2202 node_destroy (child);
2204 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2205 node_destroy (center_container);
2207 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2208 node_destroy (inner_container);
2210 node_destroy (outer_container);
2213 _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2214 N_VALUES * N_VALUES * N_VALUES);
2216 TestTypeNode *nodes[3];
2219 while ((nodes[0] = value_generator (&i)))
2222 while ((nodes[1] = value_generator (&j)))
2225 while ((nodes[2] = value_generator (&k)))
2227 run_test_nodes (nodes, 3);
2229 node_destroy (nodes[2]);
2231 node_destroy (nodes[1]);
2233 node_destroy (nodes[0]);
2238 dbus_bool_t _dbus_marshal_recursive_test (void);
2241 _dbus_marshal_recursive_test (void)
2243 make_and_run_test_nodes ();
2250 main (int argc, char **argv)
2252 _dbus_marshal_recursive_test ();
2262 * Implementations of each type node class
2269 int32_from_seed (int seed)
2271 /* Generate an integer value that's predictable from seed. We could
2272 * just use seed itself, but that would only ever touch one byte of
2273 * the int so would miss some kinds of bug.
2277 v = 42; /* just to quiet compiler afaik */
2284 v = SAMPLE_INT32_ALTERNATE;
2298 v *= seed; /* wraps around eventually, which is fine */
2304 int32_write_value (TestTypeNode *node,
2306 DBusTypeWriter *writer,
2309 /* also used for uint32 */
2312 v = int32_from_seed (seed);
2314 return _dbus_type_writer_write_basic (writer,
2315 node->klass->typecode,
2320 int32_read_value (TestTypeNode *node,
2322 DBusTypeReader *reader,
2325 /* also used for uint32 */
2328 check_expected_type (reader, node->klass->typecode);
2330 _dbus_type_reader_read_basic (reader,
2331 (dbus_int32_t*) &v);
2333 _dbus_assert (v == int32_from_seed (seed));
2338 #ifdef DBUS_HAVE_INT64
2340 int64_from_seed (int seed)
2345 v32 = int32_from_seed (seed);
2347 v = - (dbus_int32_t) ~ v32;
2348 v |= (((dbus_int64_t)v32) << 32);
2355 int64_write_value (TestTypeNode *node,
2357 DBusTypeWriter *writer,
2360 #ifdef DBUS_HAVE_INT64
2361 /* also used for uint64 */
2364 v = int64_from_seed (seed);
2366 return _dbus_type_writer_write_basic (writer,
2367 node->klass->typecode,
2375 int64_read_value (TestTypeNode *node,
2377 DBusTypeReader *reader,
2380 #ifdef DBUS_HAVE_INT64
2381 /* also used for uint64 */
2384 check_expected_type (reader, node->klass->typecode);
2386 _dbus_type_reader_read_basic (reader,
2387 (dbus_int64_t*) &v);
2389 _dbus_assert (v == int64_from_seed (seed));
2398 struct_N_write_value (TestTypeNode *node,
2400 DBusTypeWriter *writer,
2403 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2404 DataBlockState saved;
2408 _dbus_assert (container->children != NULL);
2410 data_block_save (block, &saved);
2412 if (!_dbus_type_writer_recurse_struct (writer,
2417 while (i < n_copies)
2421 link = _dbus_list_get_first_link (&container->children);
2422 while (link != NULL)
2424 TestTypeNode *child = link->data;
2425 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2427 if (!node_write_value (child, block, &sub, i))
2429 data_block_restore (block, &saved);
2439 if (!_dbus_type_writer_unrecurse (writer, &sub))
2441 data_block_restore (block, &saved);
2449 struct_N_read_value (TestTypeNode *node,
2451 DBusTypeReader *reader,
2454 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2458 check_expected_type (reader, DBUS_TYPE_STRUCT);
2460 _dbus_type_reader_recurse (reader, &sub);
2463 while (i < n_copies)
2467 link = _dbus_list_get_first_link (&container->children);
2468 while (link != NULL)
2470 TestTypeNode *child = link->data;
2471 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2473 if (!node_read_value (child, block, &sub, i))
2476 if (i == (n_copies - 1) && next == NULL)
2477 NEXT_EXPECTING_FALSE (&sub);
2479 NEXT_EXPECTING_TRUE (&sub);
2491 struct_N_build_signature (TestTypeNode *node,
2495 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2499 orig_len = _dbus_string_get_length (str);
2501 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
2505 while (i < n_copies)
2509 link = _dbus_list_get_first_link (&container->children);
2510 while (link != NULL)
2512 TestTypeNode *child = link->data;
2513 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2515 if (!node_build_signature (child, str))
2524 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
2530 _dbus_string_set_length (str, orig_len);
2535 struct_1_write_value (TestTypeNode *node,
2537 DBusTypeWriter *writer,
2540 return struct_N_write_value (node, block, writer, 1);
2544 struct_1_read_value (TestTypeNode *node,
2546 DBusTypeReader *reader,
2549 return struct_N_read_value (node, block, reader, 1);
2553 struct_1_build_signature (TestTypeNode *node,
2556 return struct_N_build_signature (node, str, 1);
2561 struct_2_write_value (TestTypeNode *node,
2563 DBusTypeWriter *writer,
2566 return struct_N_write_value (node, block, writer, 2);
2570 struct_2_read_value (TestTypeNode *node,
2572 DBusTypeReader *reader,
2575 return struct_N_read_value (node, block, reader, 2);
2579 struct_2_build_signature (TestTypeNode *node,
2582 return struct_N_build_signature (node, str, 2);
2586 array_N_write_value (TestTypeNode *node,
2588 DBusTypeWriter *writer,
2591 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2592 DataBlockState saved;
2594 DBusString element_signature;
2597 _dbus_assert (container->children != NULL);
2599 data_block_save (block, &saved);
2601 if (!_dbus_string_init (&element_signature))
2604 if (!node_build_signature (_dbus_list_get_first (&container->children),
2605 &element_signature))
2608 if (!_dbus_type_writer_recurse_array (writer,
2609 _dbus_string_get_const_data (&element_signature),
2614 while (i < n_copies)
2618 link = _dbus_list_get_first_link (&container->children);
2619 while (link != NULL)
2621 TestTypeNode *child = link->data;
2622 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2624 if (!node_write_value (child, block, &sub, i))
2633 if (!_dbus_type_writer_unrecurse (writer, &sub))
2636 _dbus_string_free (&element_signature);
2640 data_block_restore (block, &saved);
2641 _dbus_string_free (&element_signature);
2646 array_N_read_value (TestTypeNode *node,
2648 DBusTypeReader *reader,
2651 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2655 check_expected_type (reader, DBUS_TYPE_ARRAY);
2659 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
2661 _dbus_type_reader_recurse (reader, &sub);
2664 while (i < n_copies)
2668 link = _dbus_list_get_first_link (&container->children);
2669 while (link != NULL)
2671 TestTypeNode *child = link->data;
2672 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2674 if (!node_read_value (child, block, &sub, i))
2677 if (i == (n_copies - 1) && next == NULL)
2678 NEXT_EXPECTING_FALSE (&sub);
2680 NEXT_EXPECTING_TRUE (&sub);
2690 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
2697 array_build_signature (TestTypeNode *node,
2700 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2703 orig_len = _dbus_string_get_length (str);
2705 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
2708 if (!node_build_signature (_dbus_list_get_first (&container->children),
2715 _dbus_string_set_length (str, orig_len);
2720 array_0_write_value (TestTypeNode *node,
2722 DBusTypeWriter *writer,
2725 return array_N_write_value (node, block, writer, 0);
2729 array_0_read_value (TestTypeNode *node,
2731 DBusTypeReader *reader,
2734 return array_N_read_value (node, block, reader, 0);
2739 array_1_write_value (TestTypeNode *node,
2741 DBusTypeWriter *writer,
2744 return array_N_write_value (node, block, writer, 1);
2748 array_1_read_value (TestTypeNode *node,
2750 DBusTypeReader *reader,
2753 return array_N_read_value (node, block, reader, 1);
2757 array_2_write_value (TestTypeNode *node,
2759 DBusTypeWriter *writer,
2762 return array_N_write_value (node, block, writer, 2);
2766 array_2_read_value (TestTypeNode *node,
2768 DBusTypeReader *reader,
2771 return array_N_read_value (node, block, reader, 2);
2775 array_9_write_value (TestTypeNode *node,
2777 DBusTypeWriter *writer,
2780 return array_N_write_value (node, block, writer, 9);
2784 array_9_read_value (TestTypeNode *node,
2786 DBusTypeReader *reader,
2789 return array_N_read_value (node, block, reader, 9);
2792 /* 10 is random just to add another seed that we use in the suite */
2793 #define VARIANT_SEED 10
2796 variant_write_value (TestTypeNode *node,
2798 DBusTypeWriter *writer,
2801 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2802 DataBlockState saved;
2804 DBusString content_signature;
2805 TestTypeNode *child;
2807 _dbus_assert (container->children != NULL);
2808 _dbus_assert (_dbus_list_length_is_one (&container->children));
2810 child = _dbus_list_get_first (&container->children);
2812 data_block_save (block, &saved);
2814 if (!_dbus_string_init (&content_signature))
2817 if (!node_build_signature (child,
2818 &content_signature))
2821 if (!_dbus_type_writer_recurse_variant (writer,
2822 _dbus_string_get_const_data (&content_signature),
2826 if (!node_write_value (child, block, &sub, VARIANT_SEED))
2829 if (!_dbus_type_writer_unrecurse (writer, &sub))
2832 _dbus_string_free (&content_signature);
2836 data_block_restore (block, &saved);
2837 _dbus_string_free (&content_signature);
2842 variant_read_value (TestTypeNode *node,
2844 DBusTypeReader *reader,
2847 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2849 TestTypeNode *child;
2851 _dbus_assert (container->children != NULL);
2852 _dbus_assert (_dbus_list_length_is_one (&container->children));
2854 child = _dbus_list_get_first (&container->children);
2856 check_expected_type (reader, DBUS_TYPE_VARIANT);
2858 _dbus_type_reader_recurse (reader, &sub);
2860 if (!node_read_value (child, block, &sub, VARIANT_SEED))
2863 NEXT_EXPECTING_FALSE (&sub);
2869 container_destroy (TestTypeNode *node)
2871 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2874 link = _dbus_list_get_first_link (&container->children);
2875 while (link != NULL)
2877 TestTypeNode *child = link->data;
2878 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2880 node_destroy (child);
2882 _dbus_list_free_link (link);
2888 #endif /* DBUS_BUILD_TESTS */