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 _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
178 base_reader_recurse (sub, parent);
180 /* Variant is 1 byte sig length (without nul), signature with nul,
181 * padding to 8-boundary, then values
184 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
186 sub->type_str = sub->value_str;
187 sub->type_pos = sub->value_pos + 1;
189 sub->value_pos = sub->type_pos + sig_len + 1;
191 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
193 #if RECURSIVE_MARSHAL_TRACE
194 _dbus_verbose (" type reader %p variant containing '%s'\n",
196 _dbus_string_get_const_data_len (sub->type_str,
202 base_reader_get_current_type (DBusTypeReader *reader)
206 t = first_type_in_signature (reader->type_str,
213 struct_reader_get_current_type (DBusTypeReader *reader)
217 if (reader->finished)
218 t = DBUS_TYPE_INVALID;
220 t = first_type_in_signature (reader->type_str,
227 array_types_only_reader_get_current_type (DBusTypeReader *reader)
231 if (reader->finished)
232 t = DBUS_TYPE_INVALID;
234 t = reader->u.array.element_type;
240 array_reader_get_current_type (DBusTypeReader *reader)
245 /* return the array element type if elements remain, and
246 * TYPE_INVALID otherwise
249 end_pos = reader->u.array.start_pos + reader->u.array.len;
251 _dbus_assert (reader->value_pos <= end_pos);
252 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
254 if (reader->value_pos < end_pos)
255 t = reader->u.array.element_type;
257 t = DBUS_TYPE_INVALID;
263 skip_one_complete_type (const DBusString *type_str,
266 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
269 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
276 switch (_dbus_string_get_byte (type_str, *type_pos))
278 case DBUS_STRUCT_BEGIN_CHAR:
281 case DBUS_STRUCT_END_CHAR:
284 case DBUS_TYPE_INVALID:
285 _dbus_assert_not_reached ("unbalanced parens in signature");
296 skip_array_values (int element_type,
297 const DBusString *value_str,
301 dbus_uint32_t array_len;
305 pos = _DBUS_ALIGN_VALUE (*value_pos, 4);
307 _dbus_demarshal_basic_type (value_str,
313 alignment = _dbus_type_get_alignment (element_type);
315 pos = _DBUS_ALIGN_VALUE (pos, alignment);
317 *value_pos = pos + array_len;
321 base_reader_next (DBusTypeReader *reader,
324 switch (current_type)
326 case DBUS_TYPE_STRUCT:
327 /* Scan forward over the entire container contents */
331 /* Recurse into the struct */
332 _dbus_type_reader_recurse (reader, &sub);
334 /* Skip everything in this subreader */
335 while (_dbus_type_reader_next (&sub))
340 /* Now we are at the end of this container */
341 reader->type_pos = sub.type_pos;
343 if (!reader->klass->types_only)
344 reader->value_pos = sub.value_pos;
348 case DBUS_TYPE_ARRAY:
350 if (!reader->klass->types_only)
351 skip_array_values (first_type_in_signature (reader->type_str,
352 reader->type_pos + 1),
353 reader->value_str, &reader->value_pos, reader->byte_order);
355 skip_one_complete_type (reader->type_str, &reader->type_pos);
360 if (!reader->klass->types_only)
361 _dbus_marshal_skip_basic_type (reader->value_str,
362 current_type, reader->byte_order,
365 reader->type_pos += 1;
371 struct_reader_next (DBusTypeReader *reader,
376 base_reader_next (reader, current_type);
378 /* for STRUCT containers we return FALSE at the end of the struct,
379 * for INVALID we return FALSE at the end of the signature.
380 * In both cases we arrange for get_current_type() to return INVALID
381 * which is defined to happen iff we're at the end (no more next())
383 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
384 if (t == DBUS_STRUCT_END_CHAR)
386 reader->type_pos += 1;
387 reader->finished = TRUE;
392 array_types_only_reader_next (DBusTypeReader *reader,
395 /* We have one "element" to be iterated over
396 * in each array, which is its element type.
397 * So the finished flag indicates whether we've
398 * iterated over it yet or not.
400 reader->finished = TRUE;
404 array_reader_next (DBusTypeReader *reader,
407 /* Skip one array element */
410 end_pos = reader->u.array.start_pos + reader->u.array.len;
412 _dbus_assert (reader->value_pos < end_pos);
413 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
415 if (reader->u.array.element_type == DBUS_TYPE_STRUCT)
419 /* Recurse into the struct */
420 _dbus_type_reader_recurse (reader, &sub);
422 /* Skip everything in this element */
423 while (_dbus_type_reader_next (&sub))
428 /* Now we are at the end of this element */
429 reader->value_pos = sub.value_pos;
431 else if (reader->u.array.element_type == DBUS_TYPE_ARRAY)
433 skip_array_values (first_type_in_signature (reader->type_str,
434 reader->type_pos + 1),
435 reader->value_str, &reader->value_pos, reader->byte_order);
439 _dbus_marshal_skip_basic_type (reader->value_str,
440 current_type, reader->byte_order,
444 _dbus_assert (reader->value_pos <= end_pos);
446 if (reader->value_pos == end_pos)
448 skip_one_complete_type (reader->type_str,
453 static const DBusTypeReaderClass body_reader_class = {
456 NULL, /* body is always toplevel, so doesn't get recursed into */
457 base_reader_get_current_type,
461 static const DBusTypeReaderClass body_types_only_reader_class = {
464 NULL, /* body is always toplevel, so doesn't get recursed into */
465 base_reader_get_current_type,
469 static const DBusTypeReaderClass struct_reader_class = {
472 struct_reader_recurse,
473 struct_reader_get_current_type,
477 static const DBusTypeReaderClass struct_types_only_reader_class = {
480 struct_types_only_reader_recurse,
481 struct_reader_get_current_type,
485 static const DBusTypeReaderClass array_reader_class = {
488 array_reader_recurse,
489 array_reader_get_current_type,
493 static const DBusTypeReaderClass array_types_only_reader_class = {
496 array_types_only_reader_recurse,
497 array_types_only_reader_get_current_type,
498 array_types_only_reader_next
501 static const DBusTypeReaderClass variant_reader_class = {
504 variant_reader_recurse,
505 base_reader_get_current_type,
510 _dbus_type_reader_init (DBusTypeReader *reader,
512 const DBusString *type_str,
514 const DBusString *value_str,
517 reader->klass = &body_reader_class;
519 reader_init (reader, byte_order, type_str, type_pos,
520 value_str, value_pos);
522 #if RECURSIVE_MARSHAL_TRACE
523 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
524 reader, reader->type_pos, reader->value_pos,
525 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
530 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
531 const DBusString *type_str,
534 reader->klass = &body_types_only_reader_class;
536 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
537 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
539 #if RECURSIVE_MARSHAL_TRACE
540 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
541 reader, reader->type_pos,
542 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
547 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
551 t = (* reader->klass->get_current_type) (reader);
553 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
554 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
557 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
558 reader, reader->type_pos,
559 _dbus_type_to_string (t));
566 _dbus_type_reader_array_is_empty (DBusTypeReader *reader)
568 dbus_uint32_t array_len;
571 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
572 _dbus_assert (!reader->klass->types_only);
574 len_pos = _DBUS_ALIGN_VALUE (reader->value_pos, 4);
576 _dbus_demarshal_basic_type (reader->value_str,
582 return array_len == 0;
586 _dbus_type_reader_read_basic (DBusTypeReader *reader,
592 _dbus_assert (!reader->klass->types_only);
594 t = _dbus_type_reader_get_current_type (reader);
596 next = reader->value_pos;
597 _dbus_demarshal_basic_type (reader->value_str,
603 #if RECURSIVE_MARSHAL_TRACE
604 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
605 reader, reader->type_pos, reader->value_pos, next,
606 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
611 _dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
616 _dbus_assert (!reader->klass->types_only);
621 * Initialize a new reader pointing to the first type and
622 * corresponding value that's a child of the current container. It's
623 * an error to call this if the current type is a non-container.
625 * Note that DBusTypeReader traverses values, not types. So if you
626 * have an empty array of array of int, you can't recurse into it. You
627 * can only recurse into each element.
629 * @param reader the reader
630 * @param sub a reader to init pointing to the first child
633 _dbus_type_reader_recurse (DBusTypeReader *reader,
638 t = first_type_in_signature (reader->type_str, reader->type_pos);
642 case DBUS_TYPE_STRUCT:
643 if (reader->klass->types_only)
644 sub->klass = &struct_types_only_reader_class;
646 sub->klass = &struct_reader_class;
648 case DBUS_TYPE_ARRAY:
649 if (reader->klass->types_only)
650 sub->klass = &array_types_only_reader_class;
652 sub->klass = &array_reader_class;
654 case DBUS_TYPE_VARIANT:
655 if (reader->klass->types_only)
656 _dbus_assert_not_reached ("can't recurse into variant typecode");
658 sub->klass = &variant_reader_class;
661 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
662 #ifndef DBUS_DISABLE_CHECKS
663 if (t == DBUS_TYPE_INVALID)
664 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
665 #endif /* DBUS_DISABLE_CHECKS */
667 _dbus_assert_not_reached ("don't yet handle recursing into this type");
670 (* sub->klass->recurse) (sub, reader);
672 #if RECURSIVE_MARSHAL_TRACE
673 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
674 sub, sub->type_pos, sub->value_pos,
675 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
680 * Skip to the next value on this "level". e.g. the next field in a
681 * struct, the next value in an array, the next key or value in a
682 * dict. Returns FALSE at the end of the current container.
684 * @param reader the reader
685 * @returns FALSE if nothing more to read at or below this level
688 _dbus_type_reader_next (DBusTypeReader *reader)
692 t = _dbus_type_reader_get_current_type (reader);
694 #if RECURSIVE_MARSHAL_TRACE
695 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
696 reader, reader->type_pos, reader->value_pos,
697 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
698 _dbus_type_to_string (t));
701 if (t == DBUS_TYPE_INVALID)
704 (* reader->klass->next) (reader, t);
706 #if RECURSIVE_MARSHAL_TRACE
707 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
708 reader, reader->type_pos, reader->value_pos,
709 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
710 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
713 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
727 _dbus_type_writer_init (DBusTypeWriter *writer,
729 DBusString *type_str,
731 DBusString *value_str,
734 writer->byte_order = byte_order;
735 writer->type_str = type_str;
736 writer->type_pos = type_pos;
737 writer->value_str = value_str;
738 writer->value_pos = value_pos;
739 writer->container_type = DBUS_TYPE_INVALID;
740 writer->type_pos_is_expectation = FALSE;
742 #if RECURSIVE_MARSHAL_TRACE
743 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
744 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
749 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
756 old_value_len = _dbus_string_get_length (writer->value_str);
758 if (!_dbus_marshal_basic_type (writer->value_str,
765 bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
767 writer->value_pos += bytes_written;
772 /* If our parent is an array, things are a little bit complicated.
774 * The parent must have a complete element type, such as
775 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
776 * unclosed parens, or an "a" with no following type.
778 * To recurse, the only allowed operation is to recurse into the
779 * first type in the element type. So for "i" you can't recurse, for
780 * "ai" you can recurse into the array, for "(ii)" you can recurse
783 * If you recurse into the array for "ai", then you must specify
784 * "i" for the element type of the array you recurse into.
786 * While inside an array at any level, we need to avoid writing to
787 * type_str, since the type only appears once for the whole array,
788 * it does not appear for each array element.
790 * While inside an array type_pos points to the expected next
791 * typecode, rather than the next place we could write a typecode.
794 writer_recurse_init_and_check (DBusTypeWriter *writer,
798 _dbus_type_writer_init (sub,
805 sub->container_type = container_type;
807 if (writer->type_pos_is_expectation ||
808 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
809 sub->type_pos_is_expectation = TRUE;
811 sub->type_pos_is_expectation = FALSE;
813 #ifndef DBUS_DISABLE_CHECKS
814 if (writer->type_pos_is_expectation)
818 expected = first_type_in_signature (writer->type_str, writer->type_pos);
820 if (expected != sub->container_type)
822 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
823 _dbus_type_to_string (sub->container_type),
824 _dbus_type_to_string (expected));
825 _dbus_assert_not_reached ("bad array element or variant content written");
828 #endif /* DBUS_DISABLE_CHECKS */
830 #if RECURSIVE_MARSHAL_TRACE
831 _dbus_verbose (" type writer %p recurse parent type_pos = %d value_pos = %d is_expectation = %d container_type = %s remaining sig '%s'\n",
832 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
833 _dbus_type_to_string (writer->container_type),
834 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
835 _dbus_verbose (" type writer %p recurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
836 sub, sub->type_pos, sub->value_pos,
837 sub->type_pos_is_expectation,
838 _dbus_type_to_string (sub->container_type));
843 write_or_verify_typecode (DBusTypeWriter *writer,
846 /* A subwriter inside an array or variant will have type_pos
847 * pointing to the expected typecode; a writer not inside an array
848 * or variant has type_pos pointing to the next place to insert a
851 #if RECURSIVE_MARSHAL_TRACE
852 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
853 writer, writer->type_pos,
854 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
857 if (writer->type_pos_is_expectation)
859 #ifndef DBUS_DISABLE_CHECKS
863 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
865 if (expected != typecode)
867 _dbus_warn ("Array or Variant type requires that type %s be written, but %s was written\n",
868 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
869 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
872 #endif /* DBUS_DISABLE_CHECKS */
874 /* if immediately inside an array we'd always be appending an element,
875 * so the expected type doesn't change; if inside a struct or something
876 * below an array, we need to move through said struct or something.
878 if (writer->container_type != DBUS_TYPE_ARRAY)
879 writer->type_pos += 1;
883 if (!_dbus_string_insert_byte (writer->type_str,
888 writer->type_pos += 1;
891 #if RECURSIVE_MARSHAL_TRACE
892 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
893 writer, writer->type_pos,
894 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
901 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
904 writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
906 /* Ensure that we'll be able to add alignment padding and the typecode */
907 if (!_dbus_string_alloc_space (sub->value_str, 8))
910 if (!_dbus_string_alloc_space (sub->type_str, 1))
913 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
914 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
916 if (!_dbus_string_insert_bytes (sub->value_str,
918 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
920 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
921 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
927 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
928 const char *element_type,
931 int element_type_len;
932 DBusString element_type_str;
933 dbus_uint32_t value = 0;
938 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
940 _dbus_string_init_const (&element_type_str, element_type);
941 element_type_len = _dbus_string_get_length (&element_type_str);
943 #ifndef DBUS_DISABLE_CHECKS
944 if (writer->container_type == DBUS_TYPE_ARRAY)
946 if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
947 writer->type_str, writer->u.array.element_type_pos + 1))
949 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
951 _dbus_assert_not_reached ("incompatible type for child array");
954 #endif /* DBUS_DISABLE_CHECKS */
956 /* 4 bytes for the array length and 4 bytes possible padding */
957 if (!_dbus_string_alloc_space (sub->value_str, 8))
960 sub->type_pos += 1; /* move to point to the element type, since type_pos
961 * should be the expected type for further writes
963 sub->u.array.element_type_pos = sub->type_pos;
965 if (!writer->type_pos_is_expectation)
967 /* sub is a toplevel/outermost array so we need to write the type data */
969 /* alloc space for array typecode, element signature, possible 7
972 if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
975 if (!_dbus_string_insert_byte (writer->type_str,
978 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
980 if (!_dbus_string_copy (&element_type_str, 0,
981 sub->type_str, sub->u.array.element_type_pos))
982 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
985 /* If the parent is an array, we hold type_pos pointing at the array element type;
986 * otherwise advance it to reflect the array value we just recursed into
988 if (writer->container_type != DBUS_TYPE_ARRAY)
989 writer->type_pos += 1 + element_type_len;
991 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
993 /* Write the length */
994 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
996 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
998 _dbus_assert_not_reached ("should not have failed to insert array len");
1000 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1002 /* Write alignment padding for array elements */
1003 _dbus_string_init_const (&str, element_type);
1004 alignment = element_type_get_alignment (&str, 0);
1006 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1007 if (aligned != sub->value_pos)
1009 if (!_dbus_string_insert_bytes (sub->value_str,
1011 aligned - sub->value_pos,
1013 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1015 sub->value_pos = aligned;
1017 sub->u.array.start_pos = sub->value_pos;
1019 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1020 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1022 #if RECURSIVE_MARSHAL_TRACE
1023 _dbus_verbose (" type writer %p recurse array done remaining sig '%s'\n", sub,
1024 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
1030 /* Variant value will normally have:
1031 * 1 byte signature length not including nul
1032 * signature typecodes (nul terminated)
1033 * padding to 8-boundary
1034 * body according to signature
1036 * The signature string can only have a single type
1037 * in it but that type may be complex/recursive.
1039 * So a typical variant type with the integer 3 will have these
1041 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1043 * For an array of 4-byte types stuffed into variants, the padding to
1044 * 8-boundary is only the 1 byte that is required for the 4-boundary
1045 * anyhow for all array elements after the first one. And for single
1046 * variants in isolation, wasting a few bytes is hardly a big deal.
1048 * The main world of hurt for writing out a variant is that the type
1049 * string is the same string as the value string. Which means
1050 * inserting to the type string will move the value_pos; and it means
1051 * that inserting to the type string could break type alignment.
1053 * This type alignment issue is why the body of the variant is always
1054 * 8-aligned. Then we know that re-8-aligning the start of the body
1055 * will always correctly align the full contents of the variant type.
1058 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1059 const char *contained_type,
1060 DBusTypeWriter *sub)
1062 int contained_type_len;
1063 DBusString contained_type_str;
1065 writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1067 _dbus_string_init_const (&contained_type_str, contained_type);
1069 contained_type_len = _dbus_string_get_length (&contained_type_str);
1071 /* Allocate space for the worst case, which is 1 byte sig
1072 * length, nul byte at end of sig, and 7 bytes padding to
1075 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1078 /* write VARIANT typecode to the parent's type string */
1079 if (!write_or_verify_typecode (sub, DBUS_TYPE_VARIANT))
1082 if (!_dbus_string_insert_byte (sub->value_str,
1084 contained_type_len))
1085 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1087 sub->value_pos += 1;
1089 /* Here we switch over to the expected type sig we're about to write */
1090 sub->type_str = sub->value_str;
1091 sub->type_pos = sub->value_pos;
1093 if (!_dbus_string_copy (&contained_type_str, 0,
1094 sub->value_str, sub->value_pos))
1095 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1097 sub->value_pos += contained_type_len;
1099 if (!_dbus_string_insert_byte (sub->value_str,
1102 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1104 sub->value_pos += 1;
1106 if (!_dbus_string_insert_bytes (sub->value_str,
1108 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1110 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1111 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1117 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1118 DBusTypeWriter *sub)
1120 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1122 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1123 _dbus_assert (!writer->type_pos_is_expectation ||
1124 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1126 #if RECURSIVE_MARSHAL_TRACE
1127 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1128 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1129 _dbus_type_to_string (writer->container_type));
1130 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1131 sub, sub->type_pos, sub->value_pos,
1132 sub->type_pos_is_expectation,
1133 _dbus_type_to_string (sub->container_type));
1136 if (sub->container_type == DBUS_TYPE_STRUCT)
1138 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1141 else if (sub->container_type == DBUS_TYPE_ARRAY)
1145 /* Set the array length */
1146 len = sub->value_pos - sub->u.array.start_pos;
1147 _dbus_marshal_set_uint32 (sub->value_str,
1149 sub->u.array.len_pos,
1151 #if RECURSIVE_MARSHAL_TRACE
1152 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1153 len, sub->u.array.len_pos);
1157 /* Now get type_pos right for the parent writer. Here are the cases:
1159 * Cases !writer->type_pos_is_expectation:
1160 * (in these cases we want to update to the new insertion point)
1162 * - if we recursed into a STRUCT then we didn't know in advance
1163 * what the types in the struct would be; so we have to fill in
1164 * that information now.
1165 * writer->type_pos = sub->type_pos
1167 * - if we recursed into anything else, we knew the full array
1168 * type, or knew the single typecode marking VARIANT, so
1169 * writer->type_pos is already correct.
1170 * writer->type_pos should remain as-is
1172 * - note that the parent is never an ARRAY or VARIANT, if it were
1173 * then type_pos_is_expectation would be TRUE. The parent
1174 * is thus known to be a toplevel or STRUCT.
1176 * Cases where writer->type_pos_is_expectation:
1177 * (in these cases we want to update to next expected type to write)
1179 * - we recursed from STRUCT into STRUCT and we didn't increment
1180 * type_pos in the parent just to stay consistent with the
1181 * !writer->type_pos_is_expectation case (though we could
1182 * special-case this in recurse_struct instead if we wanted)
1183 * writer->type_pos = sub->type_pos
1185 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1186 * for parent should have been incremented already
1187 * writer->type_pos should remain as-is
1189 * - we recursed from ARRAY into a sub-element, so type_pos in the
1190 * parent is the element type and should remain the element type
1191 * for the benefit of the next child element
1192 * writer->type_pos should remain as-is
1194 * - we recursed from VARIANT into its value, so type_pos in the
1195 * parent makes no difference since there's only one value
1196 * and we just finished writing it and won't use type_pos again
1197 * writer->type_pos should remain as-is
1199 if (sub->container_type == DBUS_TYPE_STRUCT &&
1200 (writer->container_type == DBUS_TYPE_STRUCT ||
1201 writer->container_type == DBUS_TYPE_INVALID))
1203 /* Advance the parent to the next struct field */
1204 writer->type_pos = sub->type_pos;
1207 writer->value_pos = sub->value_pos;
1209 #if RECURSIVE_MARSHAL_TRACE
1210 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1211 writer, writer->type_pos, writer->value_pos,
1212 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1219 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1225 /* First ensure that our type realloc will succeed */
1226 if (!_dbus_string_alloc_space (writer->type_str, 1))
1231 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1234 if (!write_or_verify_typecode (writer, type))
1235 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1240 #if RECURSIVE_MARSHAL_TRACE
1241 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1242 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1249 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1258 /** @} */ /* end of DBusMarshal group */
1260 #ifdef DBUS_BUILD_TESTS
1261 #include "dbus-test.h"
1262 #include "dbus-list.h"
1268 DBusString signature;
1279 data_block_init (DataBlock *block)
1281 if (!_dbus_string_init (&block->signature))
1284 if (!_dbus_string_init (&block->body))
1286 _dbus_string_free (&block->signature);
1294 data_block_free (DataBlock *block)
1296 _dbus_string_free (&block->signature);
1297 _dbus_string_free (&block->body);
1301 data_block_save (DataBlock *block,
1302 DataBlockState *state)
1304 state->saved_sig_len = _dbus_string_get_length (&block->signature);
1305 state->saved_body_len = _dbus_string_get_length (&block->body);
1309 data_block_restore (DataBlock *block,
1310 DataBlockState *state)
1312 /* These set_length should be shortening things so should always work */
1314 if (!_dbus_string_set_length (&block->signature,
1315 state->saved_sig_len))
1316 _dbus_assert_not_reached ("could not restore signature length");
1318 if (!_dbus_string_set_length (&block->body,
1319 state->saved_body_len))
1320 _dbus_assert_not_reached ("could not restore body length");
1324 data_block_init_reader_writer (DataBlock *block,
1326 DBusTypeReader *reader,
1327 DBusTypeWriter *writer)
1329 _dbus_type_reader_init (reader,
1332 _dbus_string_get_length (&block->signature),
1334 _dbus_string_get_length (&block->body));
1336 _dbus_type_writer_init (writer,
1339 _dbus_string_get_length (&block->signature),
1341 _dbus_string_get_length (&block->body));
1345 real_check_expected_type (DBusTypeReader *reader,
1347 const char *funcname,
1352 t = _dbus_type_reader_get_current_type (reader);
1356 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1357 _dbus_type_to_string (t),
1358 _dbus_type_to_string (expected),
1365 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1367 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
1369 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
1370 _DBUS_FUNCTION_NAME, __LINE__); \
1371 _dbus_assert_not_reached ("test failed"); \
1375 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
1377 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
1378 _DBUS_FUNCTION_NAME, __LINE__); \
1379 _dbus_assert_not_reached ("test failed"); \
1381 check_expected_type (reader, DBUS_TYPE_INVALID); \
1384 #define SAMPLE_INT32 12345678
1385 #define SAMPLE_INT32_ALTERNATE 53781429
1387 typedef struct TestTypeNode TestTypeNode;
1388 typedef struct TestTypeNodeClass TestTypeNodeClass;
1389 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
1390 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1394 const TestTypeNodeClass *klass;
1397 struct TestTypeNodeContainer
1403 struct TestTypeNodeClass
1409 dbus_bool_t (* construct) (TestTypeNode *node);
1410 void (* destroy) (TestTypeNode *node);
1412 dbus_bool_t (* write_value) (TestTypeNode *node,
1414 DBusTypeWriter *writer,
1416 dbus_bool_t (* read_value) (TestTypeNode *node,
1418 DBusTypeReader *reader,
1420 dbus_bool_t (* build_signature) (TestTypeNode *node,
1424 struct TestTypeNodeContainerClass
1426 TestTypeNodeClass base;
1429 static dbus_bool_t int32_write_value (TestTypeNode *node,
1431 DBusTypeWriter *writer,
1433 static dbus_bool_t int32_read_value (TestTypeNode *node,
1435 DBusTypeReader *reader,
1437 static dbus_bool_t int64_write_value (TestTypeNode *node,
1439 DBusTypeWriter *writer,
1441 static dbus_bool_t int64_read_value (TestTypeNode *node,
1443 DBusTypeReader *reader,
1445 static dbus_bool_t struct_1_write_value (TestTypeNode *node,
1447 DBusTypeWriter *writer,
1449 static dbus_bool_t struct_1_read_value (TestTypeNode *node,
1451 DBusTypeReader *reader,
1453 static dbus_bool_t struct_1_build_signature (TestTypeNode *node,
1455 static dbus_bool_t struct_2_write_value (TestTypeNode *node,
1457 DBusTypeWriter *writer,
1459 static dbus_bool_t struct_2_read_value (TestTypeNode *node,
1461 DBusTypeReader *reader,
1463 static dbus_bool_t struct_2_build_signature (TestTypeNode *node,
1465 static dbus_bool_t array_build_signature (TestTypeNode *node,
1467 static dbus_bool_t array_1_write_value (TestTypeNode *node,
1469 DBusTypeWriter *writer,
1471 static dbus_bool_t array_1_read_value (TestTypeNode *node,
1473 DBusTypeReader *reader,
1475 static dbus_bool_t array_0_write_value (TestTypeNode *node,
1477 DBusTypeWriter *writer,
1479 static dbus_bool_t array_0_read_value (TestTypeNode *node,
1481 DBusTypeReader *reader,
1483 static dbus_bool_t array_2_write_value (TestTypeNode *node,
1485 DBusTypeWriter *writer,
1487 static dbus_bool_t array_2_read_value (TestTypeNode *node,
1489 DBusTypeReader *reader,
1491 static dbus_bool_t array_9_write_value (TestTypeNode *node,
1493 DBusTypeWriter *writer,
1495 static dbus_bool_t array_9_read_value (TestTypeNode *node,
1497 DBusTypeReader *reader,
1499 static void container_destroy (TestTypeNode *node);
1503 static const TestTypeNodeClass int32_class = {
1505 sizeof (TestTypeNode),
1513 static const TestTypeNodeClass uint32_class = {
1515 sizeof (TestTypeNode),
1518 int32_write_value, /* recycle from int32 */
1519 int32_read_value, /* recycle from int32 */
1523 static const TestTypeNodeClass int64_class = {
1525 sizeof (TestTypeNode),
1533 static const TestTypeNodeClass uint64_class = {
1535 sizeof (TestTypeNode),
1538 int64_write_value, /* recycle from int64 */
1539 int64_read_value, /* recycle from int64 */
1543 static const TestTypeNodeClass struct_1_class = {
1545 sizeof (TestTypeNodeContainer),
1548 struct_1_write_value,
1549 struct_1_read_value,
1550 struct_1_build_signature
1553 static const TestTypeNodeClass struct_2_class = {
1555 sizeof (TestTypeNodeContainer),
1558 struct_2_write_value,
1559 struct_2_read_value,
1560 struct_2_build_signature
1563 static const TestTypeNodeClass array_0_class = {
1565 sizeof (TestTypeNodeContainer),
1568 array_0_write_value,
1570 array_build_signature
1573 static const TestTypeNodeClass array_1_class = {
1575 sizeof (TestTypeNodeContainer),
1578 array_1_write_value,
1580 array_build_signature
1583 static const TestTypeNodeClass array_2_class = {
1585 sizeof (TestTypeNodeContainer),
1588 array_2_write_value,
1590 array_build_signature
1593 static const TestTypeNodeClass array_9_class = {
1595 sizeof (TestTypeNodeContainer),
1598 array_9_write_value,
1600 array_build_signature
1603 static const TestTypeNodeClass* const
1610 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
1612 static const TestTypeNodeClass* const
1613 container_nodes[] = {
1619 /* array_9_class is omitted on purpose, it's too slow;
1620 * we only use it in one hardcoded test below
1623 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
1625 static TestTypeNode*
1626 node_new (const TestTypeNodeClass *klass)
1630 node = dbus_malloc0 (klass->instance_size);
1634 node->klass = klass;
1636 if (klass->construct)
1638 if (!(* klass->construct) (node))
1649 node_destroy (TestTypeNode *node)
1651 if (node->klass->destroy)
1652 (* node->klass->destroy) (node);
1657 node_write_value (TestTypeNode *node,
1659 DBusTypeWriter *writer,
1662 return (* node->klass->write_value) (node, block, writer, seed);
1666 node_read_value (TestTypeNode *node,
1668 DBusTypeReader *reader,
1671 return (* node->klass->read_value) (node, block, reader, seed);
1675 node_build_signature (TestTypeNode *node,
1678 if (node->klass->build_signature)
1679 return (* node->klass->build_signature) (node, str);
1681 return _dbus_string_append_byte (str, node->klass->typecode);
1685 node_append_child (TestTypeNode *node,
1686 TestTypeNode *child)
1688 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
1690 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
1692 if (!_dbus_list_append (&container->children, child))
1693 _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 */
1700 const DBusString *signature;
1704 TestTypeNode **nodes;
1706 } NodeIterationData;
1709 run_test_nodes_iteration (void *data)
1711 NodeIterationData *nid = data;
1712 DBusTypeReader reader;
1713 DBusTypeWriter writer;
1717 * 1. write the value
1718 * 2. strcmp-compare with the signature we built
1720 * 4. type-iterate the signature and the value and see if they are the same type-wise
1722 data_block_init_reader_writer (nid->block,
1727 while (i < nid->n_nodes)
1729 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
1735 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
1736 &nid->block->signature, nid->type_offset))
1738 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
1739 _dbus_string_get_const_data (nid->signature),
1740 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
1742 _dbus_assert_not_reached ("wrong signature");
1746 while (i < nid->n_nodes)
1748 if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
1751 if (i + 1 == nid->n_nodes)
1752 NEXT_EXPECTING_FALSE (&reader);
1754 NEXT_EXPECTING_TRUE (&reader);
1759 /* FIXME type-iterate both signature and value */
1765 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
1767 const DBusString *signature,
1772 NodeIterationData nid;
1774 if (!data_block_init (&block))
1775 _dbus_assert_not_reached ("no memory");
1777 if (!_dbus_string_lengthen (&block.signature, initial_offset))
1778 _dbus_assert_not_reached ("no memory");
1780 if (!_dbus_string_lengthen (&block.body, initial_offset))
1781 _dbus_assert_not_reached ("no memory");
1783 nid.signature = signature;
1785 nid.type_offset = initial_offset;
1787 nid.n_nodes = n_nodes;
1788 nid.byte_order = byte_order;
1790 /* FIXME put the OOM testing back once we debug everything and are willing to
1791 * wait for it to run ;-)
1794 _dbus_test_oom_handling ("running test node",
1795 run_test_nodes_iteration,
1798 if (!run_test_nodes_iteration (&nid))
1799 _dbus_assert_not_reached ("no memory");
1802 data_block_free (&block);
1806 run_test_nodes (TestTypeNode **nodes,
1810 DBusString signature;
1812 if (!_dbus_string_init (&signature))
1813 _dbus_assert_not_reached ("no memory");
1818 if (! node_build_signature (nodes[i], &signature))
1819 _dbus_assert_not_reached ("no memory");
1824 _dbus_verbose (">>> test nodes with signature '%s'\n",
1825 _dbus_string_get_const_data (&signature));
1827 /* We do start offset 0 through 9, to get various alignment cases. Still this
1828 * obviously makes the test suite run 10x as slow.
1833 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1834 DBUS_LITTLE_ENDIAN, i);
1835 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1836 DBUS_BIG_ENDIAN, i);
1841 _dbus_string_free (&signature);
1844 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
1846 static TestTypeNode*
1847 value_generator (int *ip)
1850 const TestTypeNodeClass *child_klass;
1851 const TestTypeNodeClass *container_klass;
1852 TestTypeNode *child;
1855 _dbus_assert (i <= N_VALUES);
1861 else if (i < N_BASICS)
1863 node = node_new (basic_nodes[i]);
1867 /* imagine an array:
1868 * container 0 of basic 0
1869 * container 0 of basic 1
1870 * container 0 of basic 2
1871 * container 1 of basic 0
1872 * container 1 of basic 1
1873 * container 1 of basic 2
1877 container_klass = container_nodes[i / N_BASICS];
1878 child_klass = basic_nodes[i % N_BASICS];
1880 node = node_new (container_klass);
1881 child = node_new (child_klass);
1883 node_append_child (node, child);
1886 *ip += 1; /* increment the generator */
1892 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
1896 TestTypeNode *container;
1897 TestTypeNode *child;
1900 root = node_new (container_klass);
1902 for (i = 1; i < n_nested; i++)
1904 child = node_new (container_klass);
1905 node_append_child (container, child);
1909 /* container should now be the most-nested container */
1912 while ((child = value_generator (&i)))
1914 node_append_child (container, child);
1916 run_test_nodes (&root, 1);
1918 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
1919 node_destroy (child);
1922 node_destroy (root);
1926 make_and_run_test_nodes (void)
1930 /* We try to do this in order of "complicatedness" so that test
1931 * failures tend to show up in the simplest test case that
1932 * demonstrates the failure. There are also some tests that run
1933 * more than once for this reason, first while going through simple
1934 * cases, second while going through a broader range of complex
1937 /* Each basic node. The basic nodes should include:
1939 * - each fixed-size type (in such a way that it has different values each time,
1940 * so we can tell if we mix two of them up)
1941 * - strings of length 0-9
1945 /* Each container node. The container nodes should include:
1947 * struct with 1 and 2 copies of the contained item
1948 * array with 0, 1, 2 copies of the contained item
1951 /* Let a "value" be a basic node, or a container containing a single basic node.
1952 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
1953 * When iterating through all values to make combinations, do the basic types
1954 * first and the containers second.
1956 /* Each item is shown with its number of iterations to complete so
1957 * we can keep a handle on this unit test
1960 /* FIXME test just an empty body, no types at all */
1962 _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
1967 while ((node = value_generator (&i)))
1969 run_test_nodes (&node, 1);
1971 node_destroy (node);
1975 _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
1977 TestTypeNode *nodes[N_VALUES];
1980 while ((nodes[i] = value_generator (&i)))
1983 run_test_nodes (nodes, N_VALUES);
1985 for (i = 0; i < N_VALUES; i++)
1986 node_destroy (nodes[i]);
1989 _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
1990 N_VALUES * N_VALUES * 2);
1992 TestTypeNode *nodes[2];
1995 while ((nodes[0] = value_generator (&i)))
1998 while ((nodes[1] = value_generator (&j)))
2000 run_test_nodes (nodes, 2);
2002 node_destroy (nodes[1]);
2005 node_destroy (nodes[0]);
2009 _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
2010 N_CONTAINERS * N_VALUES);
2011 for (i = 0; i < N_CONTAINERS; i++)
2013 const TestTypeNodeClass *container_klass = container_nodes[i];
2015 make_and_run_values_inside_container (container_klass, 1);
2018 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2019 N_CONTAINERS * N_VALUES);
2020 for (i = 0; i < N_CONTAINERS; i++)
2022 const TestTypeNodeClass *container_klass = container_nodes[i];
2024 make_and_run_values_inside_container (container_klass, 2);
2027 _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
2028 N_CONTAINERS * N_VALUES);
2029 for (i = 0; i < N_CONTAINERS; i++)
2031 const TestTypeNodeClass *container_klass = container_nodes[i];
2033 make_and_run_values_inside_container (container_klass, 3);
2036 _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
2037 N_VALUES * N_VALUES);
2039 TestTypeNode *val1, *val2;
2042 node = node_new (&struct_1_class);
2045 while ((val1 = value_generator (&i)))
2048 while ((val2 = value_generator (&j)))
2050 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2052 node_append_child (node, val1);
2053 node_append_child (node, val2);
2055 run_test_nodes (&node, 1);
2057 _dbus_list_clear (&container->children);
2058 node_destroy (val2);
2060 node_destroy (val1);
2062 node_destroy (node);
2065 _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
2068 TestTypeNode *child;
2070 node = node_new (&struct_1_class);
2073 while ((child = value_generator (&i)))
2074 node_append_child (node, child);
2076 run_test_nodes (&node, 1);
2078 node_destroy (node);
2081 _dbus_verbose (">>> >>> Each value in a large array %d iterations\n",
2087 node = node_new (&array_9_class);
2090 while ((val = value_generator (&i)))
2092 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2094 node_append_child (node, val);
2096 run_test_nodes (&node, 1);
2098 _dbus_list_clear (&container->children);
2102 node_destroy (node);
2105 _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
2106 N_CONTAINERS * N_CONTAINERS * N_VALUES);
2107 for (i = 0; i < N_CONTAINERS; i++)
2109 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2110 TestTypeNode *outer_container = node_new (outer_container_klass);
2112 for (j = 0; j < N_CONTAINERS; j++)
2114 TestTypeNode *child;
2115 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2116 TestTypeNode *inner_container = node_new (inner_container_klass);
2118 node_append_child (outer_container, inner_container);
2121 while ((child = value_generator (&m)))
2123 node_append_child (inner_container, child);
2125 run_test_nodes (&outer_container, 1);
2127 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2128 node_destroy (child);
2130 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2131 node_destroy (inner_container);
2133 node_destroy (outer_container);
2136 _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
2137 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2138 for (i = 0; i < N_CONTAINERS; i++)
2140 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2141 TestTypeNode *outer_container = node_new (outer_container_klass);
2143 for (j = 0; j < N_CONTAINERS; j++)
2145 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2146 TestTypeNode *inner_container = node_new (inner_container_klass);
2148 node_append_child (outer_container, inner_container);
2150 for (k = 0; k < N_CONTAINERS; k++)
2152 TestTypeNode *child;
2153 const TestTypeNodeClass *center_container_klass = container_nodes[k];
2154 TestTypeNode *center_container = node_new (center_container_klass);
2156 node_append_child (inner_container, center_container);
2159 while ((child = value_generator (&m)))
2161 node_append_child (center_container, child);
2163 run_test_nodes (&outer_container, 1);
2165 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2166 node_destroy (child);
2168 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2169 node_destroy (center_container);
2171 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2172 node_destroy (inner_container);
2174 node_destroy (outer_container);
2177 _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2178 N_VALUES * N_VALUES * N_VALUES);
2180 TestTypeNode *nodes[3];
2183 while ((nodes[0] = value_generator (&i)))
2186 while ((nodes[1] = value_generator (&j)))
2189 while ((nodes[2] = value_generator (&k)))
2191 run_test_nodes (nodes, 3);
2193 node_destroy (nodes[2]);
2195 node_destroy (nodes[1]);
2197 node_destroy (nodes[0]);
2202 dbus_bool_t _dbus_marshal_recursive_test (void);
2205 _dbus_marshal_recursive_test (void)
2207 make_and_run_test_nodes ();
2214 main (int argc, char **argv)
2216 _dbus_marshal_recursive_test ();
2226 * Implementations of each type node class
2233 int32_from_seed (int seed)
2235 /* Generate an integer value that's predictable from seed. We could
2236 * just use seed itself, but that would only ever touch one byte of
2237 * the int so would miss some kinds of bug.
2241 v = 42; /* just to quiet compiler afaik */
2248 v = SAMPLE_INT32_ALTERNATE;
2262 v *= seed; /* wraps around eventually, which is fine */
2268 int32_write_value (TestTypeNode *node,
2270 DBusTypeWriter *writer,
2273 /* also used for uint32 */
2276 v = int32_from_seed (seed);
2278 return _dbus_type_writer_write_basic (writer,
2279 node->klass->typecode,
2284 int32_read_value (TestTypeNode *node,
2286 DBusTypeReader *reader,
2289 /* also used for uint32 */
2292 check_expected_type (reader, node->klass->typecode);
2294 _dbus_type_reader_read_basic (reader,
2295 (dbus_int32_t*) &v);
2297 _dbus_assert (v == int32_from_seed (seed));
2302 #ifdef DBUS_HAVE_INT64
2304 int64_from_seed (int seed)
2309 v32 = int32_from_seed (seed);
2311 v = - (dbus_int32_t) ~ v32;
2312 v |= (((dbus_int64_t)v32) << 32);
2319 int64_write_value (TestTypeNode *node,
2321 DBusTypeWriter *writer,
2324 #ifdef DBUS_HAVE_INT64
2325 /* also used for uint64 */
2328 v = int64_from_seed (seed);
2330 return _dbus_type_writer_write_basic (writer,
2331 node->klass->typecode,
2339 int64_read_value (TestTypeNode *node,
2341 DBusTypeReader *reader,
2344 #ifdef DBUS_HAVE_INT64
2345 /* also used for uint64 */
2348 check_expected_type (reader, node->klass->typecode);
2350 _dbus_type_reader_read_basic (reader,
2351 (dbus_int64_t*) &v);
2353 _dbus_assert (v == int64_from_seed (seed));
2362 struct_N_write_value (TestTypeNode *node,
2364 DBusTypeWriter *writer,
2367 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2368 DataBlockState saved;
2372 _dbus_assert (container->children != NULL);
2374 data_block_save (block, &saved);
2376 if (!_dbus_type_writer_recurse_struct (writer,
2381 while (i < n_copies)
2385 link = _dbus_list_get_first_link (&container->children);
2386 while (link != NULL)
2388 TestTypeNode *child = link->data;
2389 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2391 if (!node_write_value (child, block, &sub, i))
2393 data_block_restore (block, &saved);
2403 if (!_dbus_type_writer_unrecurse (writer, &sub))
2405 data_block_restore (block, &saved);
2413 struct_N_read_value (TestTypeNode *node,
2415 DBusTypeReader *reader,
2418 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2422 check_expected_type (reader, DBUS_TYPE_STRUCT);
2424 _dbus_type_reader_recurse (reader, &sub);
2427 while (i < n_copies)
2431 link = _dbus_list_get_first_link (&container->children);
2432 while (link != NULL)
2434 TestTypeNode *child = link->data;
2435 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2437 if (!node_read_value (child, block, &sub, i))
2440 if (i == (n_copies - 1) && next == NULL)
2441 NEXT_EXPECTING_FALSE (&sub);
2443 NEXT_EXPECTING_TRUE (&sub);
2455 struct_N_build_signature (TestTypeNode *node,
2459 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2463 orig_len = _dbus_string_get_length (str);
2465 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
2469 while (i < n_copies)
2473 link = _dbus_list_get_first_link (&container->children);
2474 while (link != NULL)
2476 TestTypeNode *child = link->data;
2477 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2479 if (!node_build_signature (child, str))
2488 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
2494 _dbus_string_set_length (str, orig_len);
2499 struct_1_write_value (TestTypeNode *node,
2501 DBusTypeWriter *writer,
2504 return struct_N_write_value (node, block, writer, 1);
2508 struct_1_read_value (TestTypeNode *node,
2510 DBusTypeReader *reader,
2513 return struct_N_read_value (node, block, reader, 1);
2517 struct_1_build_signature (TestTypeNode *node,
2520 return struct_N_build_signature (node, str, 1);
2525 struct_2_write_value (TestTypeNode *node,
2527 DBusTypeWriter *writer,
2530 return struct_N_write_value (node, block, writer, 2);
2534 struct_2_read_value (TestTypeNode *node,
2536 DBusTypeReader *reader,
2539 return struct_N_read_value (node, block, reader, 2);
2543 struct_2_build_signature (TestTypeNode *node,
2546 return struct_N_build_signature (node, str, 2);
2550 array_N_write_value (TestTypeNode *node,
2552 DBusTypeWriter *writer,
2555 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2556 DataBlockState saved;
2558 DBusString element_signature;
2561 _dbus_assert (container->children != NULL);
2563 data_block_save (block, &saved);
2565 if (!_dbus_string_init (&element_signature))
2568 if (!node_build_signature (_dbus_list_get_first (&container->children),
2569 &element_signature))
2572 if (!_dbus_type_writer_recurse_array (writer,
2573 _dbus_string_get_const_data (&element_signature),
2578 while (i < n_copies)
2582 link = _dbus_list_get_first_link (&container->children);
2583 while (link != NULL)
2585 TestTypeNode *child = link->data;
2586 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2588 if (!node_write_value (child, block, &sub, i))
2597 if (!_dbus_type_writer_unrecurse (writer, &sub))
2603 data_block_restore (block, &saved);
2604 _dbus_string_free (&element_signature);
2609 array_N_read_value (TestTypeNode *node,
2611 DBusTypeReader *reader,
2614 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2618 check_expected_type (reader, DBUS_TYPE_ARRAY);
2622 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
2624 _dbus_type_reader_recurse (reader, &sub);
2627 while (i < n_copies)
2631 link = _dbus_list_get_first_link (&container->children);
2632 while (link != NULL)
2634 TestTypeNode *child = link->data;
2635 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2637 if (!node_read_value (child, block, &sub, i))
2640 if (i == (n_copies - 1) && next == NULL)
2641 NEXT_EXPECTING_FALSE (&sub);
2643 NEXT_EXPECTING_TRUE (&sub);
2653 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
2660 array_build_signature (TestTypeNode *node,
2663 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2666 orig_len = _dbus_string_get_length (str);
2668 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
2671 if (!node_build_signature (_dbus_list_get_first (&container->children),
2678 _dbus_string_set_length (str, orig_len);
2683 array_0_write_value (TestTypeNode *node,
2685 DBusTypeWriter *writer,
2688 return array_N_write_value (node, block, writer, 0);
2692 array_0_read_value (TestTypeNode *node,
2694 DBusTypeReader *reader,
2697 return array_N_read_value (node, block, reader, 0);
2702 array_1_write_value (TestTypeNode *node,
2704 DBusTypeWriter *writer,
2707 return array_N_write_value (node, block, writer, 1);
2711 array_1_read_value (TestTypeNode *node,
2713 DBusTypeReader *reader,
2716 return array_N_read_value (node, block, reader, 1);
2720 array_2_write_value (TestTypeNode *node,
2722 DBusTypeWriter *writer,
2725 return array_N_write_value (node, block, writer, 2);
2729 array_2_read_value (TestTypeNode *node,
2731 DBusTypeReader *reader,
2734 return array_N_read_value (node, block, reader, 2);
2739 array_9_write_value (TestTypeNode *node,
2741 DBusTypeWriter *writer,
2744 return array_N_write_value (node, block, writer, 9);
2748 array_9_read_value (TestTypeNode *node,
2750 DBusTypeReader *reader,
2753 return array_N_read_value (node, block, reader, 9);
2757 container_destroy (TestTypeNode *node)
2759 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2762 link = _dbus_list_get_first_link (&container->children);
2763 while (link != NULL)
2765 TestTypeNode *child = link->data;
2766 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2768 node_destroy (child);
2770 _dbus_list_free_link (link);
2776 #endif /* DBUS_BUILD_TESTS */