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-marshal-basic.h"
26 #include "dbus-internals.h"
29 * @addtogroup DBusMarshal
32 #define RECURSIVE_MARSHAL_TRACE 0
34 struct DBusTypeReaderClass
37 dbus_bool_t types_only; /* only iterates over types, not values */
38 void (* recurse) (DBusTypeReader *sub,
39 DBusTypeReader *parent);
40 int (* get_current_type) (DBusTypeReader *reader);
41 void (* next) (DBusTypeReader *reader,
46 first_type_in_signature (const DBusString *str,
51 t = _dbus_string_get_byte (str, pos);
53 if (t == DBUS_STRUCT_BEGIN_CHAR)
54 return DBUS_TYPE_STRUCT;
60 element_type_get_alignment (const DBusString *str,
63 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
67 reader_init (DBusTypeReader *reader,
69 const DBusString *type_str,
71 const DBusString *value_str,
74 reader->byte_order = byte_order;
75 reader->finished = FALSE;
76 reader->type_str = type_str;
77 reader->type_pos = type_pos;
78 reader->value_str = value_str;
79 reader->value_pos = value_pos;
83 base_reader_recurse (DBusTypeReader *sub,
84 DBusTypeReader *parent)
86 /* point subreader at the same place as parent */
96 struct_types_only_reader_recurse (DBusTypeReader *sub,
97 DBusTypeReader *parent)
99 base_reader_recurse (sub, parent);
101 _dbus_assert (_dbus_string_get_byte (sub->type_str,
102 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
108 struct_reader_recurse (DBusTypeReader *sub,
109 DBusTypeReader *parent)
111 struct_types_only_reader_recurse (sub, parent);
113 /* struct has 8 byte alignment */
114 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
118 array_types_only_reader_recurse (DBusTypeReader *sub,
119 DBusTypeReader *parent)
121 base_reader_recurse (sub, parent);
123 /* point type_pos at the array element type */
126 sub->u.array.element_type = first_type_in_signature (sub->type_str,
129 /* Init with values likely to crash things if misused */
130 sub->u.array.start_pos = _DBUS_INT_MAX;
131 sub->u.array.len = _DBUS_INT_MAX;
135 array_reader_recurse (DBusTypeReader *sub,
136 DBusTypeReader *parent)
138 dbus_uint32_t array_len;
141 _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
143 array_types_only_reader_recurse (sub, parent);
145 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
147 _dbus_demarshal_basic_type (sub->value_str,
154 sub->u.array.len = array_len;
156 alignment = element_type_get_alignment (sub->type_str,
159 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
161 sub->u.array.start_pos = sub->value_pos;
163 #if RECURSIVE_MARSHAL_TRACE
164 _dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n",
166 sub->u.array.start_pos,
168 _dbus_type_to_string (sub->u.array.element_type));
173 variant_reader_recurse (DBusTypeReader *sub,
174 DBusTypeReader *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 base_reader_next (DBusTypeReader *reader,
299 switch (current_type)
301 case DBUS_TYPE_STRUCT:
302 case DBUS_TYPE_VARIANT:
303 /* Scan forward over the entire container contents */
307 /* Recurse into the struct or variant */
308 _dbus_type_reader_recurse (reader, &sub);
310 /* Skip everything in this subreader */
311 while (_dbus_type_reader_next (&sub))
316 /* Now we are at the end of this container; for variants, the
317 * subreader's type_pos is totally inapplicable (it's in the
318 * value string) but we know that we increment by one past the
321 if (current_type == DBUS_TYPE_VARIANT)
322 reader->type_pos += 1;
324 reader->type_pos = sub.type_pos;
326 if (!reader->klass->types_only)
327 reader->value_pos = sub.value_pos;
331 case DBUS_TYPE_ARRAY:
333 if (!reader->klass->types_only)
334 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
335 first_type_in_signature (reader->type_str,
336 reader->type_pos + 1),
339 skip_one_complete_type (reader->type_str, &reader->type_pos);
344 if (!reader->klass->types_only)
345 _dbus_marshal_skip_basic_type (reader->value_str,
346 current_type, reader->byte_order,
349 reader->type_pos += 1;
355 struct_reader_next (DBusTypeReader *reader,
360 base_reader_next (reader, current_type);
362 /* for STRUCT containers we return FALSE at the end of the struct,
363 * for INVALID we return FALSE at the end of the signature.
364 * In both cases we arrange for get_current_type() to return INVALID
365 * which is defined to happen iff we're at the end (no more next())
367 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
368 if (t == DBUS_STRUCT_END_CHAR)
370 reader->type_pos += 1;
371 reader->finished = TRUE;
376 array_types_only_reader_next (DBusTypeReader *reader,
379 /* We have one "element" to be iterated over
380 * in each array, which is its element type.
381 * So the finished flag indicates whether we've
382 * iterated over it yet or not.
384 reader->finished = TRUE;
388 array_reader_next (DBusTypeReader *reader,
391 /* Skip one array element */
394 end_pos = reader->u.array.start_pos + reader->u.array.len;
396 _dbus_assert (reader->value_pos < end_pos);
397 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
399 switch (reader->u.array.element_type)
401 case DBUS_TYPE_STRUCT:
402 case DBUS_TYPE_VARIANT:
406 /* Recurse into the struct or variant */
407 _dbus_type_reader_recurse (reader, &sub);
409 /* Skip everything in this element */
410 while (_dbus_type_reader_next (&sub))
415 /* Now we are at the end of this element */
416 reader->value_pos = sub.value_pos;
420 case DBUS_TYPE_ARRAY:
422 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
423 first_type_in_signature (reader->type_str,
424 reader->type_pos + 1),
431 _dbus_marshal_skip_basic_type (reader->value_str,
432 current_type, reader->byte_order,
438 _dbus_assert (reader->value_pos <= end_pos);
440 if (reader->value_pos == end_pos)
442 skip_one_complete_type (reader->type_str,
447 static const DBusTypeReaderClass body_reader_class = {
450 NULL, /* body is always toplevel, so doesn't get recursed into */
451 base_reader_get_current_type,
455 static const DBusTypeReaderClass body_types_only_reader_class = {
458 NULL, /* body is always toplevel, so doesn't get recursed into */
459 base_reader_get_current_type,
463 static const DBusTypeReaderClass struct_reader_class = {
466 struct_reader_recurse,
467 struct_reader_get_current_type,
471 static const DBusTypeReaderClass struct_types_only_reader_class = {
474 struct_types_only_reader_recurse,
475 struct_reader_get_current_type,
479 static const DBusTypeReaderClass array_reader_class = {
482 array_reader_recurse,
483 array_reader_get_current_type,
487 static const DBusTypeReaderClass array_types_only_reader_class = {
490 array_types_only_reader_recurse,
491 array_types_only_reader_get_current_type,
492 array_types_only_reader_next
495 static const DBusTypeReaderClass variant_reader_class = {
498 variant_reader_recurse,
499 base_reader_get_current_type,
504 _dbus_type_reader_init (DBusTypeReader *reader,
506 const DBusString *type_str,
508 const DBusString *value_str,
511 reader->klass = &body_reader_class;
513 reader_init (reader, byte_order, type_str, type_pos,
514 value_str, value_pos);
516 #if RECURSIVE_MARSHAL_TRACE
517 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
518 reader, reader->type_pos, reader->value_pos,
519 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
524 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
525 const DBusString *type_str,
528 reader->klass = &body_types_only_reader_class;
530 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
531 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
533 #if RECURSIVE_MARSHAL_TRACE
534 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
535 reader, reader->type_pos,
536 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
541 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
545 t = (* reader->klass->get_current_type) (reader);
547 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
548 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
551 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
552 reader, reader->type_pos,
553 _dbus_type_to_string (t));
560 _dbus_type_reader_array_is_empty (DBusTypeReader *reader)
562 dbus_uint32_t array_len;
564 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
565 _dbus_assert (!reader->klass->types_only);
567 /* reader is supposed to be at an array child */
568 _dbus_verbose ("checking array len at %d\n", reader->value_pos);
570 _dbus_demarshal_basic_type (reader->value_str,
576 _dbus_verbose (" ... array len = %d\n", array_len);
578 return array_len == 0;
582 _dbus_type_reader_read_basic (DBusTypeReader *reader,
587 _dbus_assert (!reader->klass->types_only);
589 t = _dbus_type_reader_get_current_type (reader);
591 _dbus_demarshal_basic_type (reader->value_str,
594 reader->value_pos, NULL);
597 #if RECURSIVE_MARSHAL_TRACE
598 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
599 reader, reader->type_pos, reader->value_pos,
600 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
605 _dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
610 _dbus_assert (!reader->klass->types_only);
615 * Initialize a new reader pointing to the first type and
616 * corresponding value that's a child of the current container. It's
617 * an error to call this if the current type is a non-container.
619 * Note that DBusTypeReader traverses values, not types. So if you
620 * have an empty array of array of int, you can't recurse into it. You
621 * can only recurse into each element.
623 * @param reader the reader
624 * @param sub a reader to init pointing to the first child
627 _dbus_type_reader_recurse (DBusTypeReader *reader,
632 t = first_type_in_signature (reader->type_str, reader->type_pos);
636 case DBUS_TYPE_STRUCT:
637 if (reader->klass->types_only)
638 sub->klass = &struct_types_only_reader_class;
640 sub->klass = &struct_reader_class;
642 case DBUS_TYPE_ARRAY:
643 if (reader->klass->types_only)
644 sub->klass = &array_types_only_reader_class;
646 sub->klass = &array_reader_class;
648 case DBUS_TYPE_VARIANT:
649 if (reader->klass->types_only)
650 _dbus_assert_not_reached ("can't recurse into variant typecode");
652 sub->klass = &variant_reader_class;
655 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
656 #ifndef DBUS_DISABLE_CHECKS
657 if (t == DBUS_TYPE_INVALID)
658 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
659 #endif /* DBUS_DISABLE_CHECKS */
661 _dbus_assert_not_reached ("don't yet handle recursing into this type");
664 (* sub->klass->recurse) (sub, reader);
666 #if RECURSIVE_MARSHAL_TRACE
667 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
668 sub, sub->type_pos, sub->value_pos,
669 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
674 * Skip to the next value on this "level". e.g. the next field in a
675 * struct, the next value in an array, the next key or value in a
676 * dict. Returns FALSE at the end of the current container.
678 * @param reader the reader
679 * @returns FALSE if nothing more to read at or below this level
682 _dbus_type_reader_next (DBusTypeReader *reader)
686 t = _dbus_type_reader_get_current_type (reader);
688 #if RECURSIVE_MARSHAL_TRACE
689 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
690 reader, reader->type_pos, reader->value_pos,
691 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
692 _dbus_type_to_string (t));
695 if (t == DBUS_TYPE_INVALID)
698 (* reader->klass->next) (reader, t);
700 #if RECURSIVE_MARSHAL_TRACE
701 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
702 reader, reader->type_pos, reader->value_pos,
703 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
704 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
707 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
721 _dbus_type_writer_init (DBusTypeWriter *writer,
723 DBusString *type_str,
725 DBusString *value_str,
728 writer->byte_order = byte_order;
729 writer->type_str = type_str;
730 writer->type_pos = type_pos;
731 writer->value_str = value_str;
732 writer->value_pos = value_pos;
733 writer->container_type = DBUS_TYPE_INVALID;
734 writer->type_pos_is_expectation = FALSE;
736 #if RECURSIVE_MARSHAL_TRACE
737 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
738 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
743 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
747 return _dbus_marshal_basic_type (writer->value_str,
755 /* If our parent is an array, things are a little bit complicated.
757 * The parent must have a complete element type, such as
758 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
759 * unclosed parens, or an "a" with no following type.
761 * To recurse, the only allowed operation is to recurse into the
762 * first type in the element type. So for "i" you can't recurse, for
763 * "ai" you can recurse into the array, for "(ii)" you can recurse
766 * If you recurse into the array for "ai", then you must specify
767 * "i" for the element type of the array you recurse into.
769 * While inside an array at any level, we need to avoid writing to
770 * type_str, since the type only appears once for the whole array,
771 * it does not appear for each array element.
773 * While inside an array type_pos points to the expected next
774 * typecode, rather than the next place we could write a typecode.
777 writer_recurse_init_and_check (DBusTypeWriter *writer,
781 _dbus_type_writer_init (sub,
788 sub->container_type = container_type;
790 if (writer->type_pos_is_expectation ||
791 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
792 sub->type_pos_is_expectation = TRUE;
794 sub->type_pos_is_expectation = FALSE;
796 #ifndef DBUS_DISABLE_CHECKS
797 if (writer->type_pos_is_expectation)
801 expected = first_type_in_signature (writer->type_str, writer->type_pos);
803 if (expected != sub->container_type)
805 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
806 _dbus_type_to_string (sub->container_type),
807 _dbus_type_to_string (expected));
808 _dbus_assert_not_reached ("bad array element or variant content written");
811 #endif /* DBUS_DISABLE_CHECKS */
813 #if RECURSIVE_MARSHAL_TRACE
814 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
816 _dbus_type_to_string (writer->container_type),
817 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
818 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
819 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d\n",
821 _dbus_type_to_string (sub->container_type),
822 sub->type_pos, sub->value_pos,
823 sub->type_pos_is_expectation);
828 write_or_verify_typecode (DBusTypeWriter *writer,
831 /* A subwriter inside an array or variant will have type_pos
832 * pointing to the expected typecode; a writer not inside an array
833 * or variant has type_pos pointing to the next place to insert a
836 #if RECURSIVE_MARSHAL_TRACE
837 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
838 writer, writer->type_pos,
839 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
842 if (writer->type_pos_is_expectation)
844 #ifndef DBUS_DISABLE_CHECKS
848 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
850 if (expected != typecode)
852 _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
853 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
854 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
857 #endif /* DBUS_DISABLE_CHECKS */
859 /* if immediately inside an array we'd always be appending an element,
860 * so the expected type doesn't change; if inside a struct or something
861 * below an array, we need to move through said struct or something.
863 if (writer->container_type != DBUS_TYPE_ARRAY)
864 writer->type_pos += 1;
868 if (!_dbus_string_insert_byte (writer->type_str,
873 writer->type_pos += 1;
876 #if RECURSIVE_MARSHAL_TRACE
877 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
878 writer, writer->type_pos,
879 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
886 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
889 writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
891 /* Ensure that we'll be able to add alignment padding and the typecode */
892 if (!_dbus_string_alloc_space (sub->value_str, 8))
895 if (!_dbus_string_alloc_space (sub->type_str, 1))
898 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
899 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
901 if (!_dbus_string_insert_bytes (sub->value_str,
903 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
905 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
906 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
912 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
913 const char *element_type,
916 int element_type_len;
917 DBusString element_type_str;
918 dbus_uint32_t value = 0;
923 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
925 _dbus_string_init_const (&element_type_str, element_type);
926 element_type_len = _dbus_string_get_length (&element_type_str);
928 #ifndef DBUS_DISABLE_CHECKS
929 if (writer->container_type == DBUS_TYPE_ARRAY)
931 if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
932 writer->type_str, writer->u.array.element_type_pos + 1))
934 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
936 _dbus_assert_not_reached ("incompatible type for child array");
939 #endif /* DBUS_DISABLE_CHECKS */
941 /* 4 bytes for the array length and 4 bytes possible padding */
942 if (!_dbus_string_alloc_space (sub->value_str, 8))
945 sub->type_pos += 1; /* move to point to the element type, since type_pos
946 * should be the expected type for further writes
948 sub->u.array.element_type_pos = sub->type_pos;
950 if (!writer->type_pos_is_expectation)
952 /* sub is a toplevel/outermost array so we need to write the type data */
954 /* alloc space for array typecode, element signature, possible 7
957 if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
960 if (!_dbus_string_insert_byte (writer->type_str,
963 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
965 if (!_dbus_string_copy (&element_type_str, 0,
966 sub->type_str, sub->u.array.element_type_pos))
967 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
970 /* If the parent is an array, we hold type_pos pointing at the array element type;
971 * otherwise advance it to reflect the array value we just recursed into
973 if (writer->container_type != DBUS_TYPE_ARRAY)
974 writer->type_pos += 1 + element_type_len;
976 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
978 /* Write the length */
979 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
981 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
983 _dbus_assert_not_reached ("should not have failed to insert array len");
985 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
987 /* Write alignment padding for array elements */
988 _dbus_string_init_const (&str, element_type);
989 alignment = element_type_get_alignment (&str, 0);
991 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
992 if (aligned != sub->value_pos)
994 if (!_dbus_string_insert_bytes (sub->value_str,
996 aligned - sub->value_pos,
998 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1000 sub->value_pos = aligned;
1002 sub->u.array.start_pos = sub->value_pos;
1004 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1005 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1007 #if RECURSIVE_MARSHAL_TRACE
1008 _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1009 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0),
1010 sub->u.array.start_pos, sub->u.array.len_pos);
1016 /* Variant value will normally have:
1017 * 1 byte signature length not including nul
1018 * signature typecodes (nul terminated)
1019 * padding to 8-boundary
1020 * body according to signature
1022 * The signature string can only have a single type
1023 * in it but that type may be complex/recursive.
1025 * So a typical variant type with the integer 3 will have these
1027 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1029 * For an array of 4-byte types stuffed into variants, the padding to
1030 * 8-boundary is only the 1 byte that is required for the 4-boundary
1031 * anyhow for all array elements after the first one. And for single
1032 * variants in isolation, wasting a few bytes is hardly a big deal.
1034 * The main world of hurt for writing out a variant is that the type
1035 * string is the same string as the value string. Which means
1036 * inserting to the type string will move the value_pos; and it means
1037 * that inserting to the type string could break type alignment.
1039 * This type alignment issue is why the body of the variant is always
1040 * 8-aligned. Then we know that re-8-aligning the start of the body
1041 * will always correctly align the full contents of the variant type.
1044 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1045 const char *contained_type,
1046 DBusTypeWriter *sub)
1048 int contained_type_len;
1049 DBusString contained_type_str;
1051 writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1053 _dbus_string_init_const (&contained_type_str, contained_type);
1055 contained_type_len = _dbus_string_get_length (&contained_type_str);
1057 /* Allocate space for the worst case, which is 1 byte sig
1058 * length, nul byte at end of sig, and 7 bytes padding to
1061 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1064 /* write VARIANT typecode to the parent's type string */
1065 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1068 if (!_dbus_string_insert_byte (sub->value_str,
1070 contained_type_len))
1071 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1073 sub->value_pos += 1;
1075 /* Here we switch over to the expected type sig we're about to write */
1076 sub->type_str = sub->value_str;
1077 sub->type_pos = sub->value_pos;
1079 if (!_dbus_string_copy (&contained_type_str, 0,
1080 sub->value_str, sub->value_pos))
1081 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1083 sub->value_pos += contained_type_len;
1085 if (!_dbus_string_insert_byte (sub->value_str,
1088 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1090 sub->value_pos += 1;
1092 if (!_dbus_string_insert_bytes (sub->value_str,
1094 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1096 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1097 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1103 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1104 DBusTypeWriter *sub)
1106 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1108 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1109 _dbus_assert (!writer->type_pos_is_expectation ||
1110 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1112 #if RECURSIVE_MARSHAL_TRACE
1113 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1114 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1115 _dbus_type_to_string (writer->container_type));
1116 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1117 sub, sub->type_pos, sub->value_pos,
1118 sub->type_pos_is_expectation,
1119 _dbus_type_to_string (sub->container_type));
1122 if (sub->container_type == DBUS_TYPE_STRUCT)
1124 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1127 else if (sub->container_type == DBUS_TYPE_ARRAY)
1131 /* Set the array length */
1132 len = sub->value_pos - sub->u.array.start_pos;
1133 _dbus_marshal_set_uint32 (sub->value_str,
1135 sub->u.array.len_pos,
1137 #if RECURSIVE_MARSHAL_TRACE
1138 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1139 len, sub->u.array.len_pos);
1143 /* Now get type_pos right for the parent writer. Here are the cases:
1145 * Cases !writer->type_pos_is_expectation:
1146 * (in these cases we want to update to the new insertion point)
1148 * - if we recursed into a STRUCT then we didn't know in advance
1149 * what the types in the struct would be; so we have to fill in
1150 * that information now.
1151 * writer->type_pos = sub->type_pos
1153 * - if we recursed into anything else, we knew the full array
1154 * type, or knew the single typecode marking VARIANT, so
1155 * writer->type_pos is already correct.
1156 * writer->type_pos should remain as-is
1158 * - note that the parent is never an ARRAY or VARIANT, if it were
1159 * then type_pos_is_expectation would be TRUE. The parent
1160 * is thus known to be a toplevel or STRUCT.
1162 * Cases where writer->type_pos_is_expectation:
1163 * (in these cases we want to update to next expected type to write)
1165 * - we recursed from STRUCT into STRUCT and we didn't increment
1166 * type_pos in the parent just to stay consistent with the
1167 * !writer->type_pos_is_expectation case (though we could
1168 * special-case this in recurse_struct instead if we wanted)
1169 * writer->type_pos = sub->type_pos
1171 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1172 * for parent should have been incremented already
1173 * writer->type_pos should remain as-is
1175 * - we recursed from ARRAY into a sub-element, so type_pos in the
1176 * parent is the element type and should remain the element type
1177 * for the benefit of the next child element
1178 * writer->type_pos should remain as-is
1180 * - we recursed from VARIANT into its value, so type_pos in the
1181 * parent makes no difference since there's only one value
1182 * and we just finished writing it and won't use type_pos again
1183 * writer->type_pos should remain as-is
1185 if (sub->container_type == DBUS_TYPE_STRUCT &&
1186 (writer->container_type == DBUS_TYPE_STRUCT ||
1187 writer->container_type == DBUS_TYPE_INVALID))
1189 /* Advance the parent to the next struct field */
1190 writer->type_pos = sub->type_pos;
1193 writer->value_pos = sub->value_pos;
1195 #if RECURSIVE_MARSHAL_TRACE
1196 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1197 writer, writer->type_pos, writer->value_pos,
1198 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1205 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1211 /* First ensure that our type realloc will succeed */
1212 if (!_dbus_string_alloc_space (writer->type_str, 1))
1217 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1220 if (!write_or_verify_typecode (writer, type))
1221 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1226 #if RECURSIVE_MARSHAL_TRACE
1227 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1228 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1235 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1244 /** @} */ /* end of DBusMarshal group */
1246 #ifdef DBUS_BUILD_TESTS
1247 #include "dbus-test.h"
1248 #include "dbus-list.h"
1254 DBusString signature;
1265 data_block_init (DataBlock *block)
1267 if (!_dbus_string_init (&block->signature))
1270 if (!_dbus_string_init (&block->body))
1272 _dbus_string_free (&block->signature);
1280 data_block_free (DataBlock *block)
1282 _dbus_string_free (&block->signature);
1283 _dbus_string_free (&block->body);
1287 data_block_save (DataBlock *block,
1288 DataBlockState *state)
1290 state->saved_sig_len = _dbus_string_get_length (&block->signature);
1291 state->saved_body_len = _dbus_string_get_length (&block->body);
1295 data_block_restore (DataBlock *block,
1296 DataBlockState *state)
1298 /* These set_length should be shortening things so should always work */
1300 if (!_dbus_string_set_length (&block->signature,
1301 state->saved_sig_len))
1302 _dbus_assert_not_reached ("could not restore signature length");
1304 if (!_dbus_string_set_length (&block->body,
1305 state->saved_body_len))
1306 _dbus_assert_not_reached ("could not restore body length");
1310 data_block_init_reader_writer (DataBlock *block,
1312 DBusTypeReader *reader,
1313 DBusTypeWriter *writer)
1315 _dbus_type_reader_init (reader,
1318 _dbus_string_get_length (&block->signature),
1320 _dbus_string_get_length (&block->body));
1322 _dbus_type_writer_init (writer,
1325 _dbus_string_get_length (&block->signature),
1327 _dbus_string_get_length (&block->body));
1331 real_check_expected_type (DBusTypeReader *reader,
1333 const char *funcname,
1338 t = _dbus_type_reader_get_current_type (reader);
1342 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1343 _dbus_type_to_string (t),
1344 _dbus_type_to_string (expected),
1351 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1353 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
1355 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
1356 _DBUS_FUNCTION_NAME, __LINE__); \
1357 _dbus_assert_not_reached ("test failed"); \
1361 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
1363 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
1364 _DBUS_FUNCTION_NAME, __LINE__); \
1365 _dbus_assert_not_reached ("test failed"); \
1367 check_expected_type (reader, DBUS_TYPE_INVALID); \
1370 #define SAMPLE_INT32 12345678
1371 #define SAMPLE_INT32_ALTERNATE 53781429
1373 typedef struct TestTypeNode TestTypeNode;
1374 typedef struct TestTypeNodeClass TestTypeNodeClass;
1375 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
1376 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1380 const TestTypeNodeClass *klass;
1383 struct TestTypeNodeContainer
1389 struct TestTypeNodeClass
1395 int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
1397 dbus_bool_t (* construct) (TestTypeNode *node);
1398 void (* destroy) (TestTypeNode *node);
1400 dbus_bool_t (* write_value) (TestTypeNode *node,
1402 DBusTypeWriter *writer,
1404 dbus_bool_t (* read_value) (TestTypeNode *node,
1406 DBusTypeReader *reader,
1408 dbus_bool_t (* build_signature) (TestTypeNode *node,
1412 struct TestTypeNodeContainerClass
1414 TestTypeNodeClass base;
1417 static dbus_bool_t int32_write_value (TestTypeNode *node,
1419 DBusTypeWriter *writer,
1421 static dbus_bool_t int32_read_value (TestTypeNode *node,
1423 DBusTypeReader *reader,
1425 static dbus_bool_t int64_write_value (TestTypeNode *node,
1427 DBusTypeWriter *writer,
1429 static dbus_bool_t int64_read_value (TestTypeNode *node,
1431 DBusTypeReader *reader,
1433 static dbus_bool_t string_write_value (TestTypeNode *node,
1435 DBusTypeWriter *writer,
1437 static dbus_bool_t string_read_value (TestTypeNode *node,
1439 DBusTypeReader *reader,
1441 static dbus_bool_t bool_read_value (TestTypeNode *node,
1443 DBusTypeReader *reader,
1445 static dbus_bool_t bool_write_value (TestTypeNode *node,
1447 DBusTypeWriter *writer,
1449 static dbus_bool_t byte_read_value (TestTypeNode *node,
1451 DBusTypeReader *reader,
1453 static dbus_bool_t byte_write_value (TestTypeNode *node,
1455 DBusTypeWriter *writer,
1457 static dbus_bool_t double_read_value (TestTypeNode *node,
1459 DBusTypeReader *reader,
1461 static dbus_bool_t double_write_value (TestTypeNode *node,
1463 DBusTypeWriter *writer,
1465 static dbus_bool_t object_path_read_value (TestTypeNode *node,
1467 DBusTypeReader *reader,
1469 static dbus_bool_t object_path_write_value (TestTypeNode *node,
1471 DBusTypeWriter *writer,
1473 static dbus_bool_t signature_read_value (TestTypeNode *node,
1475 DBusTypeReader *reader,
1477 static dbus_bool_t signature_write_value (TestTypeNode *node,
1479 DBusTypeWriter *writer,
1481 static dbus_bool_t struct_write_value (TestTypeNode *node,
1483 DBusTypeWriter *writer,
1485 static dbus_bool_t struct_read_value (TestTypeNode *node,
1487 DBusTypeReader *reader,
1489 static dbus_bool_t struct_build_signature (TestTypeNode *node,
1491 static dbus_bool_t array_write_value (TestTypeNode *node,
1493 DBusTypeWriter *writer,
1495 static dbus_bool_t array_read_value (TestTypeNode *node,
1497 DBusTypeReader *reader,
1499 static dbus_bool_t array_build_signature (TestTypeNode *node,
1501 static dbus_bool_t variant_write_value (TestTypeNode *node,
1503 DBusTypeWriter *writer,
1505 static dbus_bool_t variant_read_value (TestTypeNode *node,
1507 DBusTypeReader *reader,
1509 static void container_destroy (TestTypeNode *node);
1512 static const TestTypeNodeClass int32_class = {
1514 sizeof (TestTypeNode),
1523 static const TestTypeNodeClass uint32_class = {
1525 sizeof (TestTypeNode),
1529 int32_write_value, /* recycle from int32 */
1530 int32_read_value, /* recycle from int32 */
1534 static const TestTypeNodeClass int64_class = {
1536 sizeof (TestTypeNode),
1545 static const TestTypeNodeClass uint64_class = {
1547 sizeof (TestTypeNode),
1551 int64_write_value, /* recycle from int64 */
1552 int64_read_value, /* recycle from int64 */
1556 static const TestTypeNodeClass string_0_class = {
1558 sizeof (TestTypeNode),
1559 0, /* string length */
1567 static const TestTypeNodeClass string_1_class = {
1569 sizeof (TestTypeNode),
1570 1, /* string length */
1578 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
1579 static const TestTypeNodeClass string_3_class = {
1581 sizeof (TestTypeNode),
1582 3, /* string length */
1590 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
1591 static const TestTypeNodeClass string_8_class = {
1593 sizeof (TestTypeNode),
1594 8, /* string length */
1602 static const TestTypeNodeClass bool_class = {
1604 sizeof (TestTypeNode),
1613 static const TestTypeNodeClass byte_class = {
1615 sizeof (TestTypeNode),
1624 static const TestTypeNodeClass double_class = {
1626 sizeof (TestTypeNode),
1635 static const TestTypeNodeClass object_path_class = {
1636 DBUS_TYPE_OBJECT_PATH,
1637 sizeof (TestTypeNode),
1641 object_path_write_value,
1642 object_path_read_value,
1646 static const TestTypeNodeClass signature_class = {
1647 DBUS_TYPE_SIGNATURE,
1648 sizeof (TestTypeNode),
1652 signature_write_value,
1653 signature_read_value,
1657 static const TestTypeNodeClass struct_1_class = {
1659 sizeof (TestTypeNodeContainer),
1660 1, /* number of times children appear as fields */
1665 struct_build_signature
1668 static const TestTypeNodeClass struct_2_class = {
1670 sizeof (TestTypeNodeContainer),
1671 2, /* number of times children appear as fields */
1676 struct_build_signature
1679 static const TestTypeNodeClass array_0_class = {
1681 sizeof (TestTypeNodeContainer),
1682 0, /* number of array elements */
1687 array_build_signature
1690 static const TestTypeNodeClass array_1_class = {
1692 sizeof (TestTypeNodeContainer),
1693 1, /* number of array elements */
1698 array_build_signature
1701 static const TestTypeNodeClass array_2_class = {
1703 sizeof (TestTypeNodeContainer),
1704 2, /* number of array elements */
1709 array_build_signature
1712 static const TestTypeNodeClass array_9_class = {
1714 sizeof (TestTypeNodeContainer),
1715 9, /* number of array elements */
1720 array_build_signature
1723 static const TestTypeNodeClass variant_class = {
1725 sizeof (TestTypeNodeContainer),
1729 variant_write_value,
1734 static const TestTypeNodeClass* const
1750 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
1752 static const TestTypeNodeClass* const
1753 container_nodes[] = {
1760 /* array_9_class is omitted on purpose, it's too slow;
1761 * we only use it in one hardcoded test below
1764 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
1766 static TestTypeNode*
1767 node_new (const TestTypeNodeClass *klass)
1771 node = dbus_malloc0 (klass->instance_size);
1775 node->klass = klass;
1777 if (klass->construct)
1779 if (!(* klass->construct) (node))
1790 node_destroy (TestTypeNode *node)
1792 if (node->klass->destroy)
1793 (* node->klass->destroy) (node);
1798 node_write_value (TestTypeNode *node,
1800 DBusTypeWriter *writer,
1803 return (* node->klass->write_value) (node, block, writer, seed);
1807 node_read_value (TestTypeNode *node,
1809 DBusTypeReader *reader,
1812 return (* node->klass->read_value) (node, block, reader, seed);
1816 node_build_signature (TestTypeNode *node,
1819 if (node->klass->build_signature)
1820 return (* node->klass->build_signature) (node, str);
1822 return _dbus_string_append_byte (str, node->klass->typecode);
1826 node_append_child (TestTypeNode *node,
1827 TestTypeNode *child)
1829 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
1831 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
1833 if (!_dbus_list_append (&container->children, child))
1834 _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 */
1841 const DBusString *signature;
1845 TestTypeNode **nodes;
1847 } NodeIterationData;
1850 run_test_nodes_iteration (void *data)
1852 NodeIterationData *nid = data;
1853 DBusTypeReader reader;
1854 DBusTypeWriter writer;
1858 * 1. write the value
1859 * 2. strcmp-compare with the signature we built
1861 * 4. type-iterate the signature and the value and see if they are the same type-wise
1863 data_block_init_reader_writer (nid->block,
1868 while (i < nid->n_nodes)
1870 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
1876 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
1877 &nid->block->signature, nid->type_offset))
1879 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
1880 _dbus_string_get_const_data (nid->signature),
1881 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
1883 _dbus_assert_not_reached ("wrong signature");
1887 while (i < nid->n_nodes)
1889 if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
1892 if (i + 1 == nid->n_nodes)
1893 NEXT_EXPECTING_FALSE (&reader);
1895 NEXT_EXPECTING_TRUE (&reader);
1900 /* FIXME type-iterate both signature and value and compare the resulting
1901 * tree to the node tree
1908 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
1910 const DBusString *signature,
1915 NodeIterationData nid;
1917 if (!data_block_init (&block))
1918 _dbus_assert_not_reached ("no memory");
1920 if (!_dbus_string_lengthen (&block.signature, initial_offset))
1921 _dbus_assert_not_reached ("no memory");
1923 if (!_dbus_string_lengthen (&block.body, initial_offset))
1924 _dbus_assert_not_reached ("no memory");
1926 nid.signature = signature;
1928 nid.type_offset = initial_offset;
1930 nid.n_nodes = n_nodes;
1931 nid.byte_order = byte_order;
1933 /* FIXME put the OOM testing back once we debug everything and are willing to
1934 * wait for it to run ;-)
1937 _dbus_test_oom_handling ("running test node",
1938 run_test_nodes_iteration,
1941 if (!run_test_nodes_iteration (&nid))
1942 _dbus_assert_not_reached ("no memory");
1945 data_block_free (&block);
1949 run_test_nodes (TestTypeNode **nodes,
1953 DBusString signature;
1955 if (!_dbus_string_init (&signature))
1956 _dbus_assert_not_reached ("no memory");
1961 if (! node_build_signature (nodes[i], &signature))
1962 _dbus_assert_not_reached ("no memory");
1967 _dbus_verbose (">>> test nodes with signature '%s'\n",
1968 _dbus_string_get_const_data (&signature));
1970 /* We do start offset 0 through 9, to get various alignment cases. Still this
1971 * obviously makes the test suite run 10x as slow.
1976 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1977 DBUS_LITTLE_ENDIAN, i);
1978 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
1979 DBUS_BIG_ENDIAN, i);
1984 _dbus_string_free (&signature);
1987 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
1989 static TestTypeNode*
1990 value_generator (int *ip)
1993 const TestTypeNodeClass *child_klass;
1994 const TestTypeNodeClass *container_klass;
1995 TestTypeNode *child;
1998 _dbus_assert (i <= N_VALUES);
2004 else if (i < N_BASICS)
2006 node = node_new (basic_nodes[i]);
2010 /* imagine an array:
2011 * container 0 of basic 0
2012 * container 0 of basic 1
2013 * container 0 of basic 2
2014 * container 1 of basic 0
2015 * container 1 of basic 1
2016 * container 1 of basic 2
2020 container_klass = container_nodes[i / N_BASICS];
2021 child_klass = basic_nodes[i % N_BASICS];
2023 node = node_new (container_klass);
2024 child = node_new (child_klass);
2026 node_append_child (node, child);
2029 *ip += 1; /* increment the generator */
2035 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2039 TestTypeNode *container;
2040 TestTypeNode *child;
2043 root = node_new (container_klass);
2045 for (i = 1; i < n_nested; i++)
2047 child = node_new (container_klass);
2048 node_append_child (container, child);
2052 /* container should now be the most-nested container */
2055 while ((child = value_generator (&i)))
2057 node_append_child (container, child);
2059 run_test_nodes (&root, 1);
2061 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2062 node_destroy (child);
2065 node_destroy (root);
2069 make_and_run_test_nodes (void)
2073 /* We try to do this in order of "complicatedness" so that test
2074 * failures tend to show up in the simplest test case that
2075 * demonstrates the failure. There are also some tests that run
2076 * more than once for this reason, first while going through simple
2077 * cases, second while going through a broader range of complex
2080 /* Each basic node. The basic nodes should include:
2082 * - each fixed-size type (in such a way that it has different values each time,
2083 * so we can tell if we mix two of them up)
2084 * - strings of various lengths
2088 /* Each container node. The container nodes should include:
2090 * struct with 1 and 2 copies of the contained item
2091 * array with 0, 1, 2 copies of the contained item
2094 /* Let a "value" be a basic node, or a container containing a single basic node.
2095 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2096 * When iterating through all values to make combinations, do the basic types
2097 * first and the containers second.
2099 /* Each item is shown with its number of iterations to complete so
2100 * we can keep a handle on this unit test
2103 /* FIXME test just an empty body, no types at all */
2105 _dbus_verbose (">>> >>> Each value by itself %d iterations\n",
2110 while ((node = value_generator (&i)))
2112 run_test_nodes (&node, 1);
2114 node_destroy (node);
2118 _dbus_verbose (">>> >>> All values in one big toplevel 1 iteration\n");
2120 TestTypeNode *nodes[N_VALUES];
2123 while ((nodes[i] = value_generator (&i)))
2126 run_test_nodes (nodes, N_VALUES);
2128 for (i = 0; i < N_VALUES; i++)
2129 node_destroy (nodes[i]);
2132 _dbus_verbose (">>> >>> Each value,value pair combination as toplevel, in both orders %d iterations\n",
2133 N_VALUES * N_VALUES * 2);
2135 TestTypeNode *nodes[2];
2138 while ((nodes[0] = value_generator (&i)))
2141 while ((nodes[1] = value_generator (&j)))
2143 run_test_nodes (nodes, 2);
2145 node_destroy (nodes[1]);
2148 node_destroy (nodes[0]);
2152 _dbus_verbose (">>> >>> Each container containing each value %d iterations\n",
2153 N_CONTAINERS * N_VALUES);
2154 for (i = 0; i < N_CONTAINERS; i++)
2156 const TestTypeNodeClass *container_klass = container_nodes[i];
2158 make_and_run_values_inside_container (container_klass, 1);
2161 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2162 N_CONTAINERS * N_VALUES);
2163 for (i = 0; i < N_CONTAINERS; i++)
2165 const TestTypeNodeClass *container_klass = container_nodes[i];
2167 make_and_run_values_inside_container (container_klass, 2);
2170 _dbus_verbose (">>> >>> Each container of same container of same container of each value %d iterations\n",
2171 N_CONTAINERS * N_VALUES);
2172 for (i = 0; i < N_CONTAINERS; i++)
2174 const TestTypeNodeClass *container_klass = container_nodes[i];
2176 make_and_run_values_inside_container (container_klass, 3);
2179 _dbus_verbose (">>> >>> Each value,value pair inside a struct %d iterations\n",
2180 N_VALUES * N_VALUES);
2182 TestTypeNode *val1, *val2;
2185 node = node_new (&struct_1_class);
2188 while ((val1 = value_generator (&i)))
2191 while ((val2 = value_generator (&j)))
2193 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2195 node_append_child (node, val1);
2196 node_append_child (node, val2);
2198 run_test_nodes (&node, 1);
2200 _dbus_list_clear (&container->children);
2201 node_destroy (val2);
2203 node_destroy (val1);
2205 node_destroy (node);
2208 _dbus_verbose (">>> >>> all values in one big struct 1 iteration\n");
2211 TestTypeNode *child;
2213 node = node_new (&struct_1_class);
2216 while ((child = value_generator (&i)))
2217 node_append_child (node, child);
2219 run_test_nodes (&node, 1);
2221 node_destroy (node);
2224 _dbus_verbose (">>> >>> Each value in a large array %d iterations\n",
2230 node = node_new (&array_9_class);
2233 while ((val = value_generator (&i)))
2235 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2237 node_append_child (node, val);
2239 run_test_nodes (&node, 1);
2241 _dbus_list_clear (&container->children);
2245 node_destroy (node);
2248 _dbus_verbose (">>> >>> Each container of each container of each value %d iterations\n",
2249 N_CONTAINERS * N_CONTAINERS * N_VALUES);
2250 for (i = 0; i < N_CONTAINERS; i++)
2252 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2253 TestTypeNode *outer_container = node_new (outer_container_klass);
2255 for (j = 0; j < N_CONTAINERS; j++)
2257 TestTypeNode *child;
2258 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2259 TestTypeNode *inner_container = node_new (inner_container_klass);
2261 node_append_child (outer_container, inner_container);
2264 while ((child = value_generator (&m)))
2266 node_append_child (inner_container, child);
2268 run_test_nodes (&outer_container, 1);
2270 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2271 node_destroy (child);
2273 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2274 node_destroy (inner_container);
2276 node_destroy (outer_container);
2279 _dbus_verbose (">>> >>> Each container of each container of each container of each value %d iterations\n",
2280 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2281 for (i = 0; i < N_CONTAINERS; i++)
2283 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2284 TestTypeNode *outer_container = node_new (outer_container_klass);
2286 for (j = 0; j < N_CONTAINERS; j++)
2288 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2289 TestTypeNode *inner_container = node_new (inner_container_klass);
2291 node_append_child (outer_container, inner_container);
2293 for (k = 0; k < N_CONTAINERS; k++)
2295 TestTypeNode *child;
2296 const TestTypeNodeClass *center_container_klass = container_nodes[k];
2297 TestTypeNode *center_container = node_new (center_container_klass);
2299 node_append_child (inner_container, center_container);
2302 while ((child = value_generator (&m)))
2304 node_append_child (center_container, child);
2306 run_test_nodes (&outer_container, 1);
2308 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2309 node_destroy (child);
2311 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2312 node_destroy (center_container);
2314 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2315 node_destroy (inner_container);
2317 node_destroy (outer_container);
2320 _dbus_verbose (">>> >>> Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2321 N_VALUES * N_VALUES * N_VALUES);
2323 TestTypeNode *nodes[3];
2326 while ((nodes[0] = value_generator (&i)))
2329 while ((nodes[1] = value_generator (&j)))
2332 while ((nodes[2] = value_generator (&k)))
2334 run_test_nodes (nodes, 3);
2336 node_destroy (nodes[2]);
2338 node_destroy (nodes[1]);
2340 node_destroy (nodes[0]);
2345 dbus_bool_t _dbus_marshal_recursive_test (void);
2348 _dbus_marshal_recursive_test (void)
2350 make_and_run_test_nodes ();
2356 dbus_bool_t _dbus_marshal_test (void);
2358 main (int argc, char **argv)
2360 _dbus_marshal_test ();
2362 _dbus_marshal_recursive_test ();
2372 * Implementations of each type node class
2379 int32_from_seed (int seed)
2381 /* Generate an integer value that's predictable from seed. We could
2382 * just use seed itself, but that would only ever touch one byte of
2383 * the int so would miss some kinds of bug.
2387 v = 42; /* just to quiet compiler afaik */
2394 v = SAMPLE_INT32_ALTERNATE;
2408 v *= seed; /* wraps around eventually, which is fine */
2414 int32_write_value (TestTypeNode *node,
2416 DBusTypeWriter *writer,
2419 /* also used for uint32 */
2422 v = int32_from_seed (seed);
2424 return _dbus_type_writer_write_basic (writer,
2425 node->klass->typecode,
2430 int32_read_value (TestTypeNode *node,
2432 DBusTypeReader *reader,
2435 /* also used for uint32 */
2438 check_expected_type (reader, node->klass->typecode);
2440 _dbus_type_reader_read_basic (reader,
2441 (dbus_int32_t*) &v);
2443 _dbus_assert (v == int32_from_seed (seed));
2448 #ifdef DBUS_HAVE_INT64
2450 int64_from_seed (int seed)
2455 v32 = int32_from_seed (seed);
2457 v = - (dbus_int32_t) ~ v32;
2458 v |= (((dbus_int64_t)v32) << 32);
2465 int64_write_value (TestTypeNode *node,
2467 DBusTypeWriter *writer,
2470 #ifdef DBUS_HAVE_INT64
2471 /* also used for uint64 */
2474 v = int64_from_seed (seed);
2476 return _dbus_type_writer_write_basic (writer,
2477 node->klass->typecode,
2485 int64_read_value (TestTypeNode *node,
2487 DBusTypeReader *reader,
2490 #ifdef DBUS_HAVE_INT64
2491 /* also used for uint64 */
2494 check_expected_type (reader, node->klass->typecode);
2496 _dbus_type_reader_read_basic (reader,
2497 (dbus_int64_t*) &v);
2499 _dbus_assert (v == int64_from_seed (seed));
2507 #define MAX_SAMPLE_STRING_LEN 10
2509 string_from_seed (char *buf,
2516 _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
2518 v = (unsigned char) ('A' + seed);
2523 if (v < 'A' || v > 'z')
2536 string_write_value (TestTypeNode *node,
2538 DBusTypeWriter *writer,
2541 char buf[MAX_SAMPLE_STRING_LEN];
2543 string_from_seed (buf, node->klass->subclass_detail,
2546 return _dbus_type_writer_write_basic (writer,
2547 node->klass->typecode,
2552 string_read_value (TestTypeNode *node,
2554 DBusTypeReader *reader,
2558 char buf[MAX_SAMPLE_STRING_LEN];
2560 check_expected_type (reader, node->klass->typecode);
2562 _dbus_type_reader_read_basic (reader,
2563 (const char **) &v);
2565 string_from_seed (buf, node->klass->subclass_detail,
2568 if (strcmp (buf, v) != 0)
2570 _dbus_warn ("read string '%s' expected '%s'\n",
2572 _dbus_assert_not_reached ("test failed");
2578 #define BOOL_FROM_SEED(seed) (seed % 2)
2581 bool_write_value (TestTypeNode *node,
2583 DBusTypeWriter *writer,
2588 v = BOOL_FROM_SEED (seed);
2590 return _dbus_type_writer_write_basic (writer,
2591 node->klass->typecode,
2596 bool_read_value (TestTypeNode *node,
2598 DBusTypeReader *reader,
2603 check_expected_type (reader, node->klass->typecode);
2605 _dbus_type_reader_read_basic (reader,
2606 (unsigned char*) &v);
2608 _dbus_assert (v == BOOL_FROM_SEED (seed));
2613 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
2616 byte_write_value (TestTypeNode *node,
2618 DBusTypeWriter *writer,
2623 v = BYTE_FROM_SEED (seed);
2625 return _dbus_type_writer_write_basic (writer,
2626 node->klass->typecode,
2631 byte_read_value (TestTypeNode *node,
2633 DBusTypeReader *reader,
2638 check_expected_type (reader, node->klass->typecode);
2640 _dbus_type_reader_read_basic (reader,
2641 (unsigned char*) &v);
2643 _dbus_assert (v == BYTE_FROM_SEED (seed));
2649 double_from_seed (int seed)
2651 return SAMPLE_INT32 * (double) seed + 0.3;
2655 double_write_value (TestTypeNode *node,
2657 DBusTypeWriter *writer,
2662 v = double_from_seed (seed);
2664 return _dbus_type_writer_write_basic (writer,
2665 node->klass->typecode,
2670 double_read_value (TestTypeNode *node,
2672 DBusTypeReader *reader,
2678 check_expected_type (reader, node->klass->typecode);
2680 _dbus_type_reader_read_basic (reader,
2683 expected = double_from_seed (seed);
2685 if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
2687 #ifdef DBUS_HAVE_INT64
2688 _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
2690 *(dbus_uint64_t*)&expected,
2691 *(dbus_uint64_t*)&v);
2693 _dbus_assert_not_reached ("test failed");
2700 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
2702 object_path_from_seed (char *buf,
2708 v = (unsigned char) ('A' + seed);
2713 if (v < 'A' || v > 'z')
2728 object_path_write_value (TestTypeNode *node,
2730 DBusTypeWriter *writer,
2733 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
2735 object_path_from_seed (buf, seed);
2737 return _dbus_type_writer_write_basic (writer,
2738 node->klass->typecode,
2743 object_path_read_value (TestTypeNode *node,
2745 DBusTypeReader *reader,
2749 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
2751 check_expected_type (reader, node->klass->typecode);
2753 _dbus_type_reader_read_basic (reader,
2754 (const char **) &v);
2756 object_path_from_seed (buf, seed);
2758 if (strcmp (buf, v) != 0)
2760 _dbus_warn ("read object path '%s' expected '%s'\n",
2762 _dbus_assert_not_reached ("test failed");
2769 #define MAX_SAMPLE_SIGNATURE_LEN 10
2771 signature_from_seed (char *buf,
2776 const char *sample_signatures[] = {
2784 s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
2786 for (i = 0; s[i]; i++)
2794 signature_write_value (TestTypeNode *node,
2796 DBusTypeWriter *writer,
2799 char buf[MAX_SAMPLE_SIGNATURE_LEN];
2801 signature_from_seed (buf, seed);
2803 return _dbus_type_writer_write_basic (writer,
2804 node->klass->typecode,
2809 signature_read_value (TestTypeNode *node,
2811 DBusTypeReader *reader,
2815 char buf[MAX_SAMPLE_SIGNATURE_LEN];
2817 check_expected_type (reader, node->klass->typecode);
2819 _dbus_type_reader_read_basic (reader,
2820 (const char **) &v);
2822 signature_from_seed (buf, seed);
2824 if (strcmp (buf, v) != 0)
2826 _dbus_warn ("read signature value '%s' expected '%s'\n",
2828 _dbus_assert_not_reached ("test failed");
2835 struct_write_value (TestTypeNode *node,
2837 DBusTypeWriter *writer,
2840 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2841 DataBlockState saved;
2846 n_copies = node->klass->subclass_detail;
2848 _dbus_assert (container->children != NULL);
2850 data_block_save (block, &saved);
2852 if (!_dbus_type_writer_recurse_struct (writer,
2857 while (i < n_copies)
2861 link = _dbus_list_get_first_link (&container->children);
2862 while (link != NULL)
2864 TestTypeNode *child = link->data;
2865 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2867 if (!node_write_value (child, block, &sub, i))
2869 data_block_restore (block, &saved);
2879 if (!_dbus_type_writer_unrecurse (writer, &sub))
2881 data_block_restore (block, &saved);
2889 struct_read_value (TestTypeNode *node,
2891 DBusTypeReader *reader,
2894 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2899 n_copies = node->klass->subclass_detail;
2901 check_expected_type (reader, DBUS_TYPE_STRUCT);
2903 _dbus_type_reader_recurse (reader, &sub);
2906 while (i < n_copies)
2910 link = _dbus_list_get_first_link (&container->children);
2911 while (link != NULL)
2913 TestTypeNode *child = link->data;
2914 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2916 if (!node_read_value (child, block, &sub, i))
2919 if (i == (n_copies - 1) && next == NULL)
2920 NEXT_EXPECTING_FALSE (&sub);
2922 NEXT_EXPECTING_TRUE (&sub);
2934 struct_build_signature (TestTypeNode *node,
2937 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2942 n_copies = node->klass->subclass_detail;
2944 orig_len = _dbus_string_get_length (str);
2946 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
2950 while (i < n_copies)
2954 link = _dbus_list_get_first_link (&container->children);
2955 while (link != NULL)
2957 TestTypeNode *child = link->data;
2958 DBusList *next = _dbus_list_get_next_link (&container->children, link);
2960 if (!node_build_signature (child, str))
2969 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
2975 _dbus_string_set_length (str, orig_len);
2980 array_write_value (TestTypeNode *node,
2982 DBusTypeWriter *writer,
2985 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2986 DataBlockState saved;
2988 DBusString element_signature;
2992 n_copies = node->klass->subclass_detail;
2994 _dbus_assert (container->children != NULL);
2996 data_block_save (block, &saved);
2998 if (!_dbus_string_init (&element_signature))
3001 if (!node_build_signature (_dbus_list_get_first (&container->children),
3002 &element_signature))
3005 if (!_dbus_type_writer_recurse_array (writer,
3006 _dbus_string_get_const_data (&element_signature),
3011 while (i < n_copies)
3015 link = _dbus_list_get_first_link (&container->children);
3016 while (link != NULL)
3018 TestTypeNode *child = link->data;
3019 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3021 if (!node_write_value (child, block, &sub, i))
3030 if (!_dbus_type_writer_unrecurse (writer, &sub))
3033 _dbus_string_free (&element_signature);
3037 data_block_restore (block, &saved);
3038 _dbus_string_free (&element_signature);
3043 array_read_value (TestTypeNode *node,
3045 DBusTypeReader *reader,
3048 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3053 n_copies = node->klass->subclass_detail;
3055 check_expected_type (reader, DBUS_TYPE_ARRAY);
3059 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3061 _dbus_type_reader_recurse (reader, &sub);
3064 while (i < n_copies)
3068 link = _dbus_list_get_first_link (&container->children);
3069 while (link != NULL)
3071 TestTypeNode *child = link->data;
3072 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3074 if (!node_read_value (child, block, &sub, i))
3077 if (i == (n_copies - 1) && next == NULL)
3078 NEXT_EXPECTING_FALSE (&sub);
3080 NEXT_EXPECTING_TRUE (&sub);
3090 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3097 array_build_signature (TestTypeNode *node,
3100 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3103 orig_len = _dbus_string_get_length (str);
3105 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3108 if (!node_build_signature (_dbus_list_get_first (&container->children),
3115 _dbus_string_set_length (str, orig_len);
3119 /* 10 is random just to add another seed that we use in the suite */
3120 #define VARIANT_SEED 10
3123 variant_write_value (TestTypeNode *node,
3125 DBusTypeWriter *writer,
3128 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3129 DataBlockState saved;
3131 DBusString content_signature;
3132 TestTypeNode *child;
3134 _dbus_assert (container->children != NULL);
3135 _dbus_assert (_dbus_list_length_is_one (&container->children));
3137 child = _dbus_list_get_first (&container->children);
3139 data_block_save (block, &saved);
3141 if (!_dbus_string_init (&content_signature))
3144 if (!node_build_signature (child,
3145 &content_signature))
3148 if (!_dbus_type_writer_recurse_variant (writer,
3149 _dbus_string_get_const_data (&content_signature),
3153 if (!node_write_value (child, block, &sub, VARIANT_SEED))
3156 if (!_dbus_type_writer_unrecurse (writer, &sub))
3159 _dbus_string_free (&content_signature);
3163 data_block_restore (block, &saved);
3164 _dbus_string_free (&content_signature);
3169 variant_read_value (TestTypeNode *node,
3171 DBusTypeReader *reader,
3174 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3176 TestTypeNode *child;
3178 _dbus_assert (container->children != NULL);
3179 _dbus_assert (_dbus_list_length_is_one (&container->children));
3181 child = _dbus_list_get_first (&container->children);
3183 check_expected_type (reader, DBUS_TYPE_VARIANT);
3185 _dbus_type_reader_recurse (reader, &sub);
3187 if (!node_read_value (child, block, &sub, VARIANT_SEED))
3190 NEXT_EXPECTING_FALSE (&sub);
3196 container_destroy (TestTypeNode *node)
3198 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3201 link = _dbus_list_get_first_link (&container->children);
3202 while (link != NULL)
3204 TestTypeNode *child = link->data;
3205 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3207 node_destroy (child);
3209 _dbus_list_free_link (link);
3215 #endif /* DBUS_BUILD_TESTS */