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 int id; /* index in all_reader_classes */
38 dbus_bool_t types_only; /* only iterates over types, not values */
39 void (* recurse) (DBusTypeReader *sub,
40 DBusTypeReader *parent);
41 int (* get_current_type) (const DBusTypeReader *reader);
42 void (* next) (DBusTypeReader *reader,
44 void (* init_from_mark) (DBusTypeReader *reader,
45 const DBusTypeMark *mark);
49 first_type_in_signature (const DBusString *str,
54 t = _dbus_string_get_byte (str, pos);
56 if (t == DBUS_STRUCT_BEGIN_CHAR)
57 return DBUS_TYPE_STRUCT;
63 element_type_get_alignment (const DBusString *str,
66 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
70 reader_init (DBusTypeReader *reader,
72 const DBusString *type_str,
74 const DBusString *value_str,
77 reader->byte_order = byte_order;
78 reader->finished = FALSE;
79 reader->type_str = type_str;
80 reader->type_pos = type_pos;
81 reader->value_str = value_str;
82 reader->value_pos = value_pos;
86 base_reader_recurse (DBusTypeReader *sub,
87 DBusTypeReader *parent)
89 /* point subreader at the same place as parent */
99 struct_types_only_reader_recurse (DBusTypeReader *sub,
100 DBusTypeReader *parent)
102 base_reader_recurse (sub, parent);
104 _dbus_assert (_dbus_string_get_byte (sub->type_str,
105 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
111 struct_reader_recurse (DBusTypeReader *sub,
112 DBusTypeReader *parent)
114 struct_types_only_reader_recurse (sub, parent);
116 /* struct has 8 byte alignment */
117 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
121 array_types_only_reader_recurse (DBusTypeReader *sub,
122 DBusTypeReader *parent)
124 base_reader_recurse (sub, parent);
126 /* point type_pos at the array element type */
129 /* Init with values likely to crash things if misused */
130 sub->u.array.start_pos = _DBUS_INT_MAX;
131 sub->array_len_offset = 7;
135 array_reader_get_array_len (const DBusTypeReader *reader)
137 dbus_uint32_t array_len;
140 /* array_len_offset is the offset back from start_pos to end of the len */
141 len_pos = reader->u.array.start_pos - ((int)reader->array_len_offset) - 4;
143 _dbus_demarshal_basic_type (reader->value_str,
149 _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n",
150 reader, len_pos, array_len, reader->array_len_offset);
152 _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);
158 array_reader_recurse (DBusTypeReader *sub,
159 DBusTypeReader *parent)
164 _dbus_assert (!_dbus_type_reader_array_is_empty (parent));
166 array_types_only_reader_recurse (sub, parent);
168 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
170 len_pos = sub->value_pos;
172 sub->value_pos += 4; /* for the length */
174 alignment = element_type_get_alignment (sub->type_str,
177 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
179 sub->u.array.start_pos = sub->value_pos;
180 _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
181 sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
183 #if RECURSIVE_MARSHAL_TRACE
184 _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
186 sub->u.array.start_pos,
187 sub->array_len_offset,
188 array_reader_get_array_len (sub),
189 _dbus_type_to_string (first_type_in_signature (sub->type_str,
195 variant_reader_recurse (DBusTypeReader *sub,
196 DBusTypeReader *parent)
200 base_reader_recurse (sub, parent);
202 /* Variant is 1 byte sig length (without nul), signature with nul,
203 * padding to 8-boundary, then values
206 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
208 sub->type_str = sub->value_str;
209 sub->type_pos = sub->value_pos + 1;
211 sub->value_pos = sub->type_pos + sig_len + 1;
213 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
215 #if RECURSIVE_MARSHAL_TRACE
216 _dbus_verbose (" type reader %p variant containing '%s'\n",
218 _dbus_string_get_const_data_len (sub->type_str,
224 base_reader_get_current_type (const DBusTypeReader *reader)
228 t = first_type_in_signature (reader->type_str,
235 struct_reader_get_current_type (const DBusTypeReader *reader)
239 if (reader->finished)
240 t = DBUS_TYPE_INVALID;
242 t = first_type_in_signature (reader->type_str,
249 array_types_only_reader_get_current_type (const DBusTypeReader *reader)
253 if (reader->finished)
254 t = DBUS_TYPE_INVALID;
256 t = first_type_in_signature (reader->type_str,
263 array_reader_get_current_type (const DBusTypeReader *reader)
268 /* return the array element type if elements remain, and
269 * TYPE_INVALID otherwise
272 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
274 _dbus_assert (reader->value_pos <= end_pos);
275 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
277 if (reader->value_pos < end_pos)
278 t = first_type_in_signature (reader->type_str,
281 t = DBUS_TYPE_INVALID;
287 skip_one_complete_type (const DBusString *type_str,
290 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
293 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
300 switch (_dbus_string_get_byte (type_str, *type_pos))
302 case DBUS_STRUCT_BEGIN_CHAR:
305 case DBUS_STRUCT_END_CHAR:
308 case DBUS_TYPE_INVALID:
309 _dbus_assert_not_reached ("unbalanced parens in signature");
320 base_reader_next (DBusTypeReader *reader,
323 switch (current_type)
325 case DBUS_TYPE_STRUCT:
326 case DBUS_TYPE_VARIANT:
327 /* Scan forward over the entire container contents */
331 /* Recurse into the struct or variant */
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; for variants, the
341 * subreader's type_pos is totally inapplicable (it's in the
342 * value string) but we know that we increment by one past the
345 if (current_type == DBUS_TYPE_VARIANT)
346 reader->type_pos += 1;
348 reader->type_pos = sub.type_pos;
350 if (!reader->klass->types_only)
351 reader->value_pos = sub.value_pos;
355 case DBUS_TYPE_ARRAY:
357 if (!reader->klass->types_only)
358 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
359 first_type_in_signature (reader->type_str,
360 reader->type_pos + 1),
363 skip_one_complete_type (reader->type_str, &reader->type_pos);
368 if (!reader->klass->types_only)
369 _dbus_marshal_skip_basic_type (reader->value_str,
370 current_type, reader->byte_order,
373 reader->type_pos += 1;
379 struct_reader_next (DBusTypeReader *reader,
384 base_reader_next (reader, current_type);
386 /* for STRUCT containers we return FALSE at the end of the struct,
387 * for INVALID we return FALSE at the end of the signature.
388 * In both cases we arrange for get_current_type() to return INVALID
389 * which is defined to happen iff we're at the end (no more next())
391 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
392 if (t == DBUS_STRUCT_END_CHAR)
394 reader->type_pos += 1;
395 reader->finished = TRUE;
400 array_types_only_reader_next (DBusTypeReader *reader,
403 /* We have one "element" to be iterated over
404 * in each array, which is its element type.
405 * So the finished flag indicates whether we've
406 * iterated over it yet or not.
408 reader->finished = TRUE;
412 array_reader_next (DBusTypeReader *reader,
415 /* Skip one array element */
418 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
420 _dbus_assert (reader->value_pos < end_pos);
421 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
423 switch (first_type_in_signature (reader->type_str,
426 case DBUS_TYPE_STRUCT:
427 case DBUS_TYPE_VARIANT:
431 /* Recurse into the struct or variant */
432 _dbus_type_reader_recurse (reader, &sub);
434 /* Skip everything in this element */
435 while (_dbus_type_reader_next (&sub))
440 /* Now we are at the end of this element */
441 reader->value_pos = sub.value_pos;
445 case DBUS_TYPE_ARRAY:
447 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
448 first_type_in_signature (reader->type_str,
449 reader->type_pos + 1),
456 _dbus_marshal_skip_basic_type (reader->value_str,
457 current_type, reader->byte_order,
463 _dbus_assert (reader->value_pos <= end_pos);
465 if (reader->value_pos == end_pos)
467 skip_one_complete_type (reader->type_str,
473 array_init_from_mark (DBusTypeReader *reader,
474 const DBusTypeMark *mark)
476 /* Fill in the array-specific fields from the mark. The general
477 * fields are already filled in.
479 reader->u.array.start_pos = mark->array_start_pos;
480 reader->array_len_offset = mark->array_len_offset;
483 static const DBusTypeReaderClass body_reader_class = {
486 NULL, /* body is always toplevel, so doesn't get recursed into */
487 base_reader_get_current_type,
492 static const DBusTypeReaderClass body_types_only_reader_class = {
495 NULL, /* body is always toplevel, so doesn't get recursed into */
496 base_reader_get_current_type,
501 static const DBusTypeReaderClass struct_reader_class = {
504 struct_reader_recurse,
505 struct_reader_get_current_type,
510 static const DBusTypeReaderClass struct_types_only_reader_class = {
513 struct_types_only_reader_recurse,
514 struct_reader_get_current_type,
519 static const DBusTypeReaderClass array_reader_class = {
522 array_reader_recurse,
523 array_reader_get_current_type,
528 static const DBusTypeReaderClass array_types_only_reader_class = {
531 array_types_only_reader_recurse,
532 array_types_only_reader_get_current_type,
533 array_types_only_reader_next,
537 static const DBusTypeReaderClass variant_reader_class = {
540 variant_reader_recurse,
541 base_reader_get_current_type,
546 static const DBusTypeReaderClass const *
547 all_reader_classes[] = {
549 &body_types_only_reader_class,
550 &struct_reader_class,
551 &struct_types_only_reader_class,
553 &array_types_only_reader_class,
554 &variant_reader_class
558 _dbus_type_reader_init (DBusTypeReader *reader,
560 const DBusString *type_str,
562 const DBusString *value_str,
565 reader->klass = &body_reader_class;
567 reader_init (reader, byte_order, type_str, type_pos,
568 value_str, value_pos);
570 #if RECURSIVE_MARSHAL_TRACE
571 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
572 reader, reader->type_pos, reader->value_pos,
573 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
578 _dbus_type_reader_init_from_mark (DBusTypeReader *reader,
580 const DBusString *type_str,
581 const DBusString *value_str,
582 const DBusTypeMark *mark)
584 reader->klass = all_reader_classes[mark->container_type];
586 reader_init (reader, byte_order,
587 mark->type_pos_in_value_str ? value_str : type_str,
589 value_str, mark->value_pos);
591 if (reader->klass->init_from_mark)
592 (* reader->klass->init_from_mark) (reader, mark);
594 #if RECURSIVE_MARSHAL_TRACE
595 _dbus_verbose (" type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",
596 reader, reader->type_pos, reader->value_pos,
597 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
602 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
603 const DBusString *type_str,
606 reader->klass = &body_types_only_reader_class;
608 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
609 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
611 #if RECURSIVE_MARSHAL_TRACE
612 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
613 reader, reader->type_pos,
614 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
619 _dbus_type_reader_init_types_only_from_mark (DBusTypeReader *reader,
620 const DBusString *type_str,
621 const DBusTypeMark *mark)
623 reader->klass = all_reader_classes[mark->container_type];
624 _dbus_assert (reader->klass->types_only);
625 _dbus_assert (!mark->type_pos_in_value_str);
627 reader_init (reader, DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
628 type_str, mark->type_pos,
629 NULL, _DBUS_INT_MAX /* crashes if we screw up */);
631 if (reader->klass->init_from_mark)
632 (* reader->klass->init_from_mark) (reader, mark);
634 #if RECURSIVE_MARSHAL_TRACE
635 _dbus_verbose (" type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",
636 reader, reader->type_pos,
637 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
642 _dbus_type_reader_save_mark (const DBusTypeReader *reader,
645 mark->type_pos_in_value_str = (reader->type_str == reader->value_str);
646 mark->container_type = reader->klass->id;
647 _dbus_assert (all_reader_classes[reader->klass->id] == reader->klass);
649 mark->type_pos = reader->type_pos;
650 mark->value_pos = reader->value_pos;
652 /* these are just junk if the reader isn't really an array of course */
653 mark->array_len_offset = reader->array_len_offset;
654 mark->array_start_pos = reader->u.array.start_pos;
658 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
662 t = (* reader->klass->get_current_type) (reader);
664 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
665 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
668 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
669 reader, reader->type_pos,
670 _dbus_type_to_string (t));
677 _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)
679 dbus_uint32_t array_len;
681 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
682 _dbus_assert (!reader->klass->types_only);
684 /* reader is supposed to be at an array child */
685 #if RECURSIVE_MARSHAL_TRACE
686 _dbus_verbose ("checking array len at %d\n", reader->value_pos);
689 _dbus_demarshal_basic_type (reader->value_str,
695 #if RECURSIVE_MARSHAL_TRACE
696 _dbus_verbose (" ... array len = %d\n", array_len);
699 return array_len == 0;
703 _dbus_type_reader_read_basic (const DBusTypeReader *reader,
708 _dbus_assert (!reader->klass->types_only);
710 t = _dbus_type_reader_get_current_type (reader);
712 _dbus_demarshal_basic_type (reader->value_str,
715 reader->value_pos, NULL);
718 #if RECURSIVE_MARSHAL_TRACE
719 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
720 reader, reader->type_pos, reader->value_pos,
721 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
726 _dbus_type_reader_read_array_of_basic (const DBusTypeReader *reader,
731 _dbus_assert (!reader->klass->types_only);
736 * Initialize a new reader pointing to the first type and
737 * corresponding value that's a child of the current container. It's
738 * an error to call this if the current type is a non-container.
740 * Note that DBusTypeReader traverses values, not types. So if you
741 * have an empty array of array of int, you can't recurse into it. You
742 * can only recurse into each element.
744 * @param reader the reader
745 * @param sub a reader to init pointing to the first child
748 _dbus_type_reader_recurse (DBusTypeReader *reader,
753 t = first_type_in_signature (reader->type_str, reader->type_pos);
757 case DBUS_TYPE_STRUCT:
758 if (reader->klass->types_only)
759 sub->klass = &struct_types_only_reader_class;
761 sub->klass = &struct_reader_class;
763 case DBUS_TYPE_ARRAY:
764 if (reader->klass->types_only)
765 sub->klass = &array_types_only_reader_class;
767 sub->klass = &array_reader_class;
769 case DBUS_TYPE_VARIANT:
770 if (reader->klass->types_only)
771 _dbus_assert_not_reached ("can't recurse into variant typecode");
773 sub->klass = &variant_reader_class;
776 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
777 #ifndef DBUS_DISABLE_CHECKS
778 if (t == DBUS_TYPE_INVALID)
779 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
780 #endif /* DBUS_DISABLE_CHECKS */
782 _dbus_assert_not_reached ("don't yet handle recursing into this type");
785 _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
787 (* sub->klass->recurse) (sub, reader);
789 #if RECURSIVE_MARSHAL_TRACE
790 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
791 sub, sub->type_pos, sub->value_pos,
792 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
797 * Skip to the next value on this "level". e.g. the next field in a
798 * struct, the next value in an array. Returns FALSE at the end of the
801 * @param reader the reader
802 * @returns FALSE if nothing more to read at or below this level
805 _dbus_type_reader_next (DBusTypeReader *reader)
809 t = _dbus_type_reader_get_current_type (reader);
811 #if RECURSIVE_MARSHAL_TRACE
812 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
813 reader, reader->type_pos, reader->value_pos,
814 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
815 _dbus_type_to_string (t));
818 if (t == DBUS_TYPE_INVALID)
821 (* reader->klass->next) (reader, t);
823 #if RECURSIVE_MARSHAL_TRACE
824 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
825 reader, reader->type_pos, reader->value_pos,
826 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
827 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
830 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
834 * Check whether there's another value on this "level". e.g. the next
835 * field in a struct, the next value in an array. Returns FALSE at the
836 * end of the current container.
838 * @param reader the reader
839 * @returns FALSE if nothing more to read at or below this level
842 _dbus_type_reader_has_next (const DBusTypeReader *reader)
844 /* Not efficient but works for now. */
848 return _dbus_type_reader_next (©);
861 * Initialize a write iterator, which is used to write out values in
862 * serialized D-BUS format. #DBusTypeWriter is a value iterator; it
863 * writes out values. You can't use it to write out only types.
865 * The type_pos passed in is expected to be inside an already-valid,
866 * though potentially empty, type signature. This means that the byte
867 * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
868 * other valid type. #DBusTypeWriter won't enforce that the signature
869 * is already valid (you can append the nul byte at the end if you
870 * like), but just be aware that you need the nul byte eventually and
871 * #DBusTypeWriter isn't going to write it for you.
873 * @param writer the writer to init
874 * @param byte_order the byte order to marshal into
875 * @param type_str the string to write typecodes into
876 * @param type_pos where to insert typecodes
877 * @param value_str the string to write values into
878 * @param value_pos where to insert values
882 _dbus_type_writer_init (DBusTypeWriter *writer,
884 DBusString *type_str,
886 DBusString *value_str,
889 writer->byte_order = byte_order;
890 writer->type_str = type_str;
891 writer->type_pos = type_pos;
892 writer->value_str = value_str;
893 writer->value_pos = value_pos;
894 writer->container_type = DBUS_TYPE_INVALID;
895 writer->type_pos_is_expectation = FALSE;
897 #if RECURSIVE_MARSHAL_TRACE
898 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
899 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
904 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
908 return _dbus_marshal_basic_type (writer->value_str,
916 /* If our parent is an array, things are a little bit complicated.
918 * The parent must have a complete element type, such as
919 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
920 * unclosed parens, or an "a" with no following type.
922 * To recurse, the only allowed operation is to recurse into the
923 * first type in the element type. So for "i" you can't recurse, for
924 * "ai" you can recurse into the array, for "(ii)" you can recurse
927 * If you recurse into the array for "ai", then you must specify
928 * "i" for the element type of the array you recurse into.
930 * While inside an array at any level, we need to avoid writing to
931 * type_str, since the type only appears once for the whole array,
932 * it does not appear for each array element.
934 * While inside an array type_pos points to the expected next
935 * typecode, rather than the next place we could write a typecode.
938 writer_recurse_init_and_check (DBusTypeWriter *writer,
942 _dbus_type_writer_init (sub,
949 sub->container_type = container_type;
951 if (writer->type_pos_is_expectation ||
952 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
953 sub->type_pos_is_expectation = TRUE;
955 sub->type_pos_is_expectation = FALSE;
957 #ifndef DBUS_DISABLE_CHECKS
958 if (writer->type_pos_is_expectation)
962 expected = first_type_in_signature (writer->type_str, writer->type_pos);
964 if (expected != sub->container_type)
966 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
967 _dbus_type_to_string (sub->container_type),
968 _dbus_type_to_string (expected));
969 _dbus_assert_not_reached ("bad array element or variant content written");
972 #endif /* DBUS_DISABLE_CHECKS */
974 #if RECURSIVE_MARSHAL_TRACE
975 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
977 _dbus_type_to_string (writer->container_type),
978 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
979 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
980 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d\n",
982 _dbus_type_to_string (sub->container_type),
983 sub->type_pos, sub->value_pos,
984 sub->type_pos_is_expectation);
989 write_or_verify_typecode (DBusTypeWriter *writer,
992 /* A subwriter inside an array or variant will have type_pos
993 * pointing to the expected typecode; a writer not inside an array
994 * or variant has type_pos pointing to the next place to insert a
997 #if RECURSIVE_MARSHAL_TRACE
998 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
999 writer, writer->type_pos,
1000 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1003 if (writer->type_pos_is_expectation)
1005 #ifndef DBUS_DISABLE_CHECKS
1009 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1011 if (expected != typecode)
1013 _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1014 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1015 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1018 #endif /* DBUS_DISABLE_CHECKS */
1020 /* if immediately inside an array we'd always be appending an element,
1021 * so the expected type doesn't change; if inside a struct or something
1022 * below an array, we need to move through said struct or something.
1024 if (writer->container_type != DBUS_TYPE_ARRAY)
1025 writer->type_pos += 1;
1029 if (!_dbus_string_insert_byte (writer->type_str,
1034 writer->type_pos += 1;
1037 #if RECURSIVE_MARSHAL_TRACE
1038 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1039 writer, writer->type_pos,
1040 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1047 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
1048 DBusTypeWriter *sub)
1050 writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
1052 /* Ensure that we'll be able to add alignment padding and the typecode */
1053 if (!_dbus_string_alloc_space (sub->value_str, 8))
1056 if (!_dbus_string_alloc_space (sub->type_str, 1))
1059 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1060 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1062 if (!_dbus_string_insert_bytes (sub->value_str,
1064 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1066 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1067 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1073 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
1074 const char *element_type,
1075 DBusTypeWriter *sub)
1077 int element_type_len;
1078 DBusString element_type_str;
1079 dbus_uint32_t value = 0;
1084 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
1086 _dbus_string_init_const (&element_type_str, element_type);
1087 element_type_len = _dbus_string_get_length (&element_type_str);
1089 #ifndef DBUS_DISABLE_CHECKS
1090 if (writer->container_type == DBUS_TYPE_ARRAY)
1092 if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
1093 writer->type_str, writer->u.array.element_type_pos + 1))
1095 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1097 _dbus_assert_not_reached ("incompatible type for child array");
1100 #endif /* DBUS_DISABLE_CHECKS */
1102 /* 4 bytes for the array length and 4 bytes possible padding */
1103 if (!_dbus_string_alloc_space (sub->value_str, 8))
1106 sub->type_pos += 1; /* move to point to the element type, since type_pos
1107 * should be the expected type for further writes
1109 sub->u.array.element_type_pos = sub->type_pos;
1111 if (!writer->type_pos_is_expectation)
1113 /* sub is a toplevel/outermost array so we need to write the type data */
1115 /* alloc space for array typecode, element signature, possible 7
1118 if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
1121 if (!_dbus_string_insert_byte (writer->type_str,
1124 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1126 if (!_dbus_string_copy (&element_type_str, 0,
1127 sub->type_str, sub->u.array.element_type_pos))
1128 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1131 /* If the parent is an array, we hold type_pos pointing at the array element type;
1132 * otherwise advance it to reflect the array value we just recursed into
1134 if (writer->container_type != DBUS_TYPE_ARRAY)
1135 writer->type_pos += 1 + element_type_len;
1137 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1139 /* Write the length */
1140 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1142 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1144 _dbus_assert_not_reached ("should not have failed to insert array len");
1146 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1148 /* Write alignment padding for array elements */
1149 _dbus_string_init_const (&str, element_type);
1150 alignment = element_type_get_alignment (&str, 0);
1152 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1153 if (aligned != sub->value_pos)
1155 if (!_dbus_string_insert_bytes (sub->value_str,
1157 aligned - sub->value_pos,
1159 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1161 sub->value_pos = aligned;
1163 sub->u.array.start_pos = sub->value_pos;
1165 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1166 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1168 #if RECURSIVE_MARSHAL_TRACE
1169 _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1170 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0),
1171 sub->u.array.start_pos, sub->u.array.len_pos);
1177 /* Variant value will normally have:
1178 * 1 byte signature length not including nul
1179 * signature typecodes (nul terminated)
1180 * padding to 8-boundary
1181 * body according to signature
1183 * The signature string can only have a single type
1184 * in it but that type may be complex/recursive.
1186 * So a typical variant type with the integer 3 will have these
1188 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1190 * For an array of 4-byte types stuffed into variants, the padding to
1191 * 8-boundary is only the 1 byte that is required for the 4-boundary
1192 * anyhow for all array elements after the first one. And for single
1193 * variants in isolation, wasting a few bytes is hardly a big deal.
1195 * The main world of hurt for writing out a variant is that the type
1196 * string is the same string as the value string. Which means
1197 * inserting to the type string will move the value_pos; and it means
1198 * that inserting to the type string could break type alignment.
1200 * This type alignment issue is why the body of the variant is always
1201 * 8-aligned. Then we know that re-8-aligning the start of the body
1202 * will always correctly align the full contents of the variant type.
1205 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1206 const char *contained_type,
1207 DBusTypeWriter *sub)
1209 int contained_type_len;
1210 DBusString contained_type_str;
1212 writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1214 _dbus_string_init_const (&contained_type_str, contained_type);
1216 contained_type_len = _dbus_string_get_length (&contained_type_str);
1218 /* Allocate space for the worst case, which is 1 byte sig
1219 * length, nul byte at end of sig, and 7 bytes padding to
1222 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1225 /* write VARIANT typecode to the parent's type string */
1226 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1229 if (!_dbus_string_insert_byte (sub->value_str,
1231 contained_type_len))
1232 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1234 sub->value_pos += 1;
1236 /* Here we switch over to the expected type sig we're about to write */
1237 sub->type_str = sub->value_str;
1238 sub->type_pos = sub->value_pos;
1240 if (!_dbus_string_copy (&contained_type_str, 0,
1241 sub->value_str, sub->value_pos))
1242 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1244 sub->value_pos += contained_type_len;
1246 if (!_dbus_string_insert_byte (sub->value_str,
1249 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1251 sub->value_pos += 1;
1253 if (!_dbus_string_insert_bytes (sub->value_str,
1255 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1257 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1258 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1264 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1265 DBusTypeWriter *sub)
1267 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1269 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1270 _dbus_assert (!writer->type_pos_is_expectation ||
1271 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1273 #if RECURSIVE_MARSHAL_TRACE
1274 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1275 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1276 _dbus_type_to_string (writer->container_type));
1277 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1278 sub, sub->type_pos, sub->value_pos,
1279 sub->type_pos_is_expectation,
1280 _dbus_type_to_string (sub->container_type));
1283 if (sub->container_type == DBUS_TYPE_STRUCT)
1285 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1288 else if (sub->container_type == DBUS_TYPE_ARRAY)
1292 /* Set the array length */
1293 len = sub->value_pos - sub->u.array.start_pos;
1294 _dbus_marshal_set_uint32 (sub->value_str,
1296 sub->u.array.len_pos,
1298 #if RECURSIVE_MARSHAL_TRACE
1299 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1300 len, sub->u.array.len_pos);
1304 /* Now get type_pos right for the parent writer. Here are the cases:
1306 * Cases !writer->type_pos_is_expectation:
1307 * (in these cases we want to update to the new insertion point)
1309 * - if we recursed into a STRUCT then we didn't know in advance
1310 * what the types in the struct would be; so we have to fill in
1311 * that information now.
1312 * writer->type_pos = sub->type_pos
1314 * - if we recursed into anything else, we knew the full array
1315 * type, or knew the single typecode marking VARIANT, so
1316 * writer->type_pos is already correct.
1317 * writer->type_pos should remain as-is
1319 * - note that the parent is never an ARRAY or VARIANT, if it were
1320 * then type_pos_is_expectation would be TRUE. The parent
1321 * is thus known to be a toplevel or STRUCT.
1323 * Cases where writer->type_pos_is_expectation:
1324 * (in these cases we want to update to next expected type to write)
1326 * - we recursed from STRUCT into STRUCT and we didn't increment
1327 * type_pos in the parent just to stay consistent with the
1328 * !writer->type_pos_is_expectation case (though we could
1329 * special-case this in recurse_struct instead if we wanted)
1330 * writer->type_pos = sub->type_pos
1332 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1333 * for parent should have been incremented already
1334 * writer->type_pos should remain as-is
1336 * - we recursed from ARRAY into a sub-element, so type_pos in the
1337 * parent is the element type and should remain the element type
1338 * for the benefit of the next child element
1339 * writer->type_pos should remain as-is
1341 * - we recursed from VARIANT into its value, so type_pos in the
1342 * parent makes no difference since there's only one value
1343 * and we just finished writing it and won't use type_pos again
1344 * writer->type_pos should remain as-is
1346 if (sub->container_type == DBUS_TYPE_STRUCT &&
1347 (writer->container_type == DBUS_TYPE_STRUCT ||
1348 writer->container_type == DBUS_TYPE_INVALID))
1350 /* Advance the parent to the next struct field */
1351 writer->type_pos = sub->type_pos;
1354 writer->value_pos = sub->value_pos;
1356 #if RECURSIVE_MARSHAL_TRACE
1357 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1358 writer, writer->type_pos, writer->value_pos,
1359 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1366 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1372 /* First ensure that our type realloc will succeed */
1373 if (!_dbus_string_alloc_space (writer->type_str, 1))
1378 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1381 if (!write_or_verify_typecode (writer, type))
1382 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1387 #if RECURSIVE_MARSHAL_TRACE
1388 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1389 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1396 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1406 * Iterate through all values in the given reader,
1407 * writing a copy of each value to the writer.
1408 * The reader will be moved forward to its end position.
1410 * @param writer the writer to copy to
1411 * @param reader the reader to copy from
1414 _dbus_type_writer_write_reader (DBusTypeWriter *writer,
1415 DBusTypeReader *reader)
1422 /** @} */ /* end of DBusMarshal group */
1424 #ifdef DBUS_BUILD_TESTS
1425 #include "dbus-test.h"
1426 #include "dbus-list.h"
1434 DBusString signature;
1444 #define N_FENCE_BYTES 5
1445 #define FENCE_BYTES_STR "abcde"
1446 #define INITIAL_PADDING_BYTE '\0'
1449 data_block_init (DataBlock *block,
1453 if (!_dbus_string_init (&block->signature))
1456 if (!_dbus_string_init (&block->body))
1458 _dbus_string_free (&block->signature);
1462 if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
1463 INITIAL_PADDING_BYTE) ||
1464 !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
1465 INITIAL_PADDING_BYTE) ||
1466 !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
1467 !_dbus_string_append (&block->body, FENCE_BYTES_STR))
1469 _dbus_string_free (&block->signature);
1470 _dbus_string_free (&block->body);
1474 block->byte_order = byte_order;
1475 block->initial_offset = initial_offset;
1481 data_block_save (DataBlock *block,
1482 DataBlockState *state)
1484 state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
1485 state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
1489 data_block_restore (DataBlock *block,
1490 DataBlockState *state)
1492 _dbus_string_delete (&block->signature,
1493 state->saved_sig_len,
1494 _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
1495 _dbus_string_delete (&block->body,
1496 state->saved_body_len,
1497 _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
1501 data_block_verify (DataBlock *block)
1503 if (!_dbus_string_ends_with_c_str (&block->signature,
1508 offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
1512 _dbus_verbose_bytes_of_string (&block->signature,
1514 _dbus_string_get_length (&block->signature) - offset);
1515 _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
1517 if (!_dbus_string_ends_with_c_str (&block->body,
1522 offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
1526 _dbus_verbose_bytes_of_string (&block->body,
1528 _dbus_string_get_length (&block->body) - offset);
1529 _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
1532 _dbus_assert (_dbus_string_validate_nul (&block->signature,
1533 0, block->initial_offset));
1534 _dbus_assert (_dbus_string_validate_nul (&block->body,
1535 0, block->initial_offset));
1539 data_block_free (DataBlock *block)
1541 data_block_verify (block);
1543 _dbus_string_free (&block->signature);
1544 _dbus_string_free (&block->body);
1548 data_block_reset (DataBlock *block)
1550 data_block_verify (block);
1552 _dbus_string_delete (&block->signature,
1553 block->initial_offset,
1554 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
1555 _dbus_string_delete (&block->body,
1556 block->initial_offset,
1557 _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
1559 data_block_verify (block);
1563 data_block_init_reader_writer (DataBlock *block,
1564 DBusTypeReader *reader,
1565 DBusTypeWriter *writer)
1567 _dbus_type_reader_init (reader,
1570 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
1572 _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
1574 _dbus_type_writer_init (writer,
1577 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
1579 _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
1583 real_check_expected_type (DBusTypeReader *reader,
1585 const char *funcname,
1590 t = _dbus_type_reader_get_current_type (reader);
1594 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1595 _dbus_type_to_string (t),
1596 _dbus_type_to_string (expected),
1603 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1605 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
1607 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
1608 _DBUS_FUNCTION_NAME, __LINE__); \
1609 _dbus_assert_not_reached ("test failed"); \
1613 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
1615 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
1616 _DBUS_FUNCTION_NAME, __LINE__); \
1617 _dbus_assert_not_reached ("test failed"); \
1619 check_expected_type (reader, DBUS_TYPE_INVALID); \
1622 typedef struct TestTypeNode TestTypeNode;
1623 typedef struct TestTypeNodeClass TestTypeNodeClass;
1624 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
1625 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1629 const TestTypeNodeClass *klass;
1632 struct TestTypeNodeContainer
1638 struct TestTypeNodeClass
1644 int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
1646 dbus_bool_t (* construct) (TestTypeNode *node);
1647 void (* destroy) (TestTypeNode *node);
1649 dbus_bool_t (* write_value) (TestTypeNode *node,
1651 DBusTypeWriter *writer,
1653 dbus_bool_t (* read_value) (TestTypeNode *node,
1655 DBusTypeReader *reader,
1657 dbus_bool_t (* build_signature) (TestTypeNode *node,
1661 struct TestTypeNodeContainerClass
1663 TestTypeNodeClass base;
1666 static dbus_bool_t int32_write_value (TestTypeNode *node,
1668 DBusTypeWriter *writer,
1670 static dbus_bool_t int32_read_value (TestTypeNode *node,
1672 DBusTypeReader *reader,
1674 static dbus_bool_t int64_write_value (TestTypeNode *node,
1676 DBusTypeWriter *writer,
1678 static dbus_bool_t int64_read_value (TestTypeNode *node,
1680 DBusTypeReader *reader,
1682 static dbus_bool_t string_write_value (TestTypeNode *node,
1684 DBusTypeWriter *writer,
1686 static dbus_bool_t string_read_value (TestTypeNode *node,
1688 DBusTypeReader *reader,
1690 static dbus_bool_t bool_read_value (TestTypeNode *node,
1692 DBusTypeReader *reader,
1694 static dbus_bool_t bool_write_value (TestTypeNode *node,
1696 DBusTypeWriter *writer,
1698 static dbus_bool_t byte_read_value (TestTypeNode *node,
1700 DBusTypeReader *reader,
1702 static dbus_bool_t byte_write_value (TestTypeNode *node,
1704 DBusTypeWriter *writer,
1706 static dbus_bool_t double_read_value (TestTypeNode *node,
1708 DBusTypeReader *reader,
1710 static dbus_bool_t double_write_value (TestTypeNode *node,
1712 DBusTypeWriter *writer,
1714 static dbus_bool_t object_path_read_value (TestTypeNode *node,
1716 DBusTypeReader *reader,
1718 static dbus_bool_t object_path_write_value (TestTypeNode *node,
1720 DBusTypeWriter *writer,
1722 static dbus_bool_t signature_read_value (TestTypeNode *node,
1724 DBusTypeReader *reader,
1726 static dbus_bool_t signature_write_value (TestTypeNode *node,
1728 DBusTypeWriter *writer,
1730 static dbus_bool_t struct_write_value (TestTypeNode *node,
1732 DBusTypeWriter *writer,
1734 static dbus_bool_t struct_read_value (TestTypeNode *node,
1736 DBusTypeReader *reader,
1738 static dbus_bool_t struct_build_signature (TestTypeNode *node,
1740 static dbus_bool_t array_write_value (TestTypeNode *node,
1742 DBusTypeWriter *writer,
1744 static dbus_bool_t array_read_value (TestTypeNode *node,
1746 DBusTypeReader *reader,
1748 static dbus_bool_t array_build_signature (TestTypeNode *node,
1750 static dbus_bool_t variant_write_value (TestTypeNode *node,
1752 DBusTypeWriter *writer,
1754 static dbus_bool_t variant_read_value (TestTypeNode *node,
1756 DBusTypeReader *reader,
1758 static void container_destroy (TestTypeNode *node);
1761 static const TestTypeNodeClass int32_class = {
1763 sizeof (TestTypeNode),
1772 static const TestTypeNodeClass uint32_class = {
1774 sizeof (TestTypeNode),
1778 int32_write_value, /* recycle from int32 */
1779 int32_read_value, /* recycle from int32 */
1783 static const TestTypeNodeClass int64_class = {
1785 sizeof (TestTypeNode),
1794 static const TestTypeNodeClass uint64_class = {
1796 sizeof (TestTypeNode),
1800 int64_write_value, /* recycle from int64 */
1801 int64_read_value, /* recycle from int64 */
1805 static const TestTypeNodeClass string_0_class = {
1807 sizeof (TestTypeNode),
1808 0, /* string length */
1816 static const TestTypeNodeClass string_1_class = {
1818 sizeof (TestTypeNode),
1819 1, /* string length */
1827 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
1828 static const TestTypeNodeClass string_3_class = {
1830 sizeof (TestTypeNode),
1831 3, /* string length */
1839 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
1840 static const TestTypeNodeClass string_8_class = {
1842 sizeof (TestTypeNode),
1843 8, /* string length */
1851 static const TestTypeNodeClass bool_class = {
1853 sizeof (TestTypeNode),
1862 static const TestTypeNodeClass byte_class = {
1864 sizeof (TestTypeNode),
1873 static const TestTypeNodeClass double_class = {
1875 sizeof (TestTypeNode),
1884 static const TestTypeNodeClass object_path_class = {
1885 DBUS_TYPE_OBJECT_PATH,
1886 sizeof (TestTypeNode),
1890 object_path_write_value,
1891 object_path_read_value,
1895 static const TestTypeNodeClass signature_class = {
1896 DBUS_TYPE_SIGNATURE,
1897 sizeof (TestTypeNode),
1901 signature_write_value,
1902 signature_read_value,
1906 static const TestTypeNodeClass struct_1_class = {
1908 sizeof (TestTypeNodeContainer),
1909 1, /* number of times children appear as fields */
1914 struct_build_signature
1917 static const TestTypeNodeClass struct_2_class = {
1919 sizeof (TestTypeNodeContainer),
1920 2, /* number of times children appear as fields */
1925 struct_build_signature
1928 static const TestTypeNodeClass array_0_class = {
1930 sizeof (TestTypeNodeContainer),
1931 0, /* number of array elements */
1936 array_build_signature
1939 static const TestTypeNodeClass array_1_class = {
1941 sizeof (TestTypeNodeContainer),
1942 1, /* number of array elements */
1947 array_build_signature
1950 static const TestTypeNodeClass array_2_class = {
1952 sizeof (TestTypeNodeContainer),
1953 2, /* number of array elements */
1958 array_build_signature
1961 static const TestTypeNodeClass array_9_class = {
1963 sizeof (TestTypeNodeContainer),
1964 9, /* number of array elements */
1969 array_build_signature
1972 static const TestTypeNodeClass variant_class = {
1974 sizeof (TestTypeNodeContainer),
1978 variant_write_value,
1983 static const TestTypeNodeClass* const
1999 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2001 static const TestTypeNodeClass* const
2002 container_nodes[] = {
2009 /* array_9_class is omitted on purpose, it's too slow;
2010 * we only use it in one hardcoded test below
2013 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2015 static TestTypeNode*
2016 node_new (const TestTypeNodeClass *klass)
2020 node = dbus_malloc0 (klass->instance_size);
2024 node->klass = klass;
2026 if (klass->construct)
2028 if (!(* klass->construct) (node))
2039 node_destroy (TestTypeNode *node)
2041 if (node->klass->destroy)
2042 (* node->klass->destroy) (node);
2047 node_write_value (TestTypeNode *node,
2049 DBusTypeWriter *writer,
2054 retval = (* node->klass->write_value) (node, block, writer, seed);
2057 /* Handy to see where things break, but too expensive to do all the time */
2058 data_block_verify (block);
2065 node_read_value (TestTypeNode *node,
2067 DBusTypeReader *reader,
2071 DBusTypeReader restored;
2073 _dbus_type_reader_save_mark (reader, &mark);
2075 if (!(* node->klass->read_value) (node, block, reader, seed))
2078 _dbus_type_reader_init_from_mark (&restored,
2079 reader->byte_order, /* a bit of a cheat,
2080 * since we didn't bother
2081 * to store this in DataBlock
2087 if (!(* node->klass->read_value) (node, block, &restored, seed))
2094 node_build_signature (TestTypeNode *node,
2097 if (node->klass->build_signature)
2098 return (* node->klass->build_signature) (node, str);
2100 return _dbus_string_append_byte (str, node->klass->typecode);
2104 node_append_child (TestTypeNode *node,
2105 TestTypeNode *child)
2107 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2109 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2111 if (!_dbus_list_append (&container->children, child))
2112 _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 */
2117 static int n_iterations_completed_total = 0;
2118 static int n_iterations_completed_this_test = 0;
2119 static int n_iterations_expected_this_test = 0;
2123 const DBusString *signature;
2126 TestTypeNode **nodes;
2128 } NodeIterationData;
2131 run_test_nodes_iteration (void *data)
2133 NodeIterationData *nid = data;
2134 DBusTypeReader reader;
2135 DBusTypeWriter writer;
2140 * 1. write the value
2141 * 2. strcmp-compare with the signature we built
2143 * 4. type-iterate the signature and the value and see if they are the same type-wise
2147 data_block_init_reader_writer (nid->block,
2150 /* DBusTypeWriter assumes it's writing into an existing signature,
2151 * so doesn't add nul on its own. We have to do that.
2153 if (!_dbus_string_insert_byte (&nid->block->signature,
2154 nid->type_offset, '\0'))
2158 while (i < nid->n_nodes)
2160 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2166 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2167 &nid->block->signature, nid->type_offset))
2169 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2170 _dbus_string_get_const_data (nid->signature),
2171 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2173 _dbus_assert_not_reached ("wrong signature");
2177 while (i < nid->n_nodes)
2179 if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
2182 if (i + 1 == nid->n_nodes)
2183 NEXT_EXPECTING_FALSE (&reader);
2185 NEXT_EXPECTING_TRUE (&reader);
2190 /* FIXME type-iterate both signature and value and compare the resulting
2191 * tree to the node tree
2198 data_block_reset (nid->block);
2203 #define TEST_OOM_HANDLING 0
2204 /* We do start offset 0 through 9, to get various alignment cases. Still this
2205 * obviously makes the test suite run 10x as slow.
2207 #define MAX_INITIAL_OFFSET 9
2210 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
2212 const DBusString *signature,
2217 NodeIterationData nid;
2219 if (!data_block_init (&block, byte_order, initial_offset))
2220 _dbus_assert_not_reached ("no memory");
2222 nid.signature = signature;
2224 nid.type_offset = initial_offset;
2226 nid.n_nodes = n_nodes;
2228 #if TEST_OOM_HANDLING
2229 _dbus_test_oom_handling ("running test node",
2230 run_test_nodes_iteration,
2233 if (!run_test_nodes_iteration (&nid))
2234 _dbus_assert_not_reached ("no memory");
2237 data_block_free (&block);
2241 run_test_nodes (TestTypeNode **nodes,
2245 DBusString signature;
2247 if (!_dbus_string_init (&signature))
2248 _dbus_assert_not_reached ("no memory");
2253 if (! node_build_signature (nodes[i], &signature))
2254 _dbus_assert_not_reached ("no memory");
2259 _dbus_verbose (">>> test nodes with signature '%s'\n",
2260 _dbus_string_get_const_data (&signature));
2263 while (i <= MAX_INITIAL_OFFSET)
2265 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2266 DBUS_LITTLE_ENDIAN, i);
2267 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2268 DBUS_BIG_ENDIAN, i);
2273 n_iterations_completed_this_test += 1;
2274 n_iterations_completed_total += 1;
2276 if (n_iterations_completed_this_test == n_iterations_expected_this_test)
2278 fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
2279 n_iterations_completed_this_test,
2280 n_iterations_completed_total);
2282 /* this happens to turn out well with mod == 1 */
2283 else if ((n_iterations_completed_this_test %
2284 (int)(n_iterations_expected_this_test / 10.0)) == 1)
2286 fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
2289 _dbus_string_free (&signature);
2292 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
2294 static TestTypeNode*
2295 value_generator (int *ip)
2298 const TestTypeNodeClass *child_klass;
2299 const TestTypeNodeClass *container_klass;
2300 TestTypeNode *child;
2303 _dbus_assert (i <= N_VALUES);
2309 else if (i < N_BASICS)
2311 node = node_new (basic_nodes[i]);
2315 /* imagine an array:
2316 * container 0 of basic 0
2317 * container 0 of basic 1
2318 * container 0 of basic 2
2319 * container 1 of basic 0
2320 * container 1 of basic 1
2321 * container 1 of basic 2
2325 container_klass = container_nodes[i / N_BASICS];
2326 child_klass = basic_nodes[i % N_BASICS];
2328 node = node_new (container_klass);
2329 child = node_new (child_klass);
2331 node_append_child (node, child);
2334 *ip += 1; /* increment the generator */
2340 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2344 TestTypeNode *container;
2345 TestTypeNode *child;
2348 root = node_new (container_klass);
2350 for (i = 1; i < n_nested; i++)
2352 child = node_new (container_klass);
2353 node_append_child (container, child);
2357 /* container should now be the most-nested container */
2360 while ((child = value_generator (&i)))
2362 node_append_child (container, child);
2364 run_test_nodes (&root, 1);
2366 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2367 node_destroy (child);
2370 node_destroy (root);
2374 start_next_test (const char *format,
2377 n_iterations_completed_this_test = 0;
2378 n_iterations_expected_this_test = expected;
2380 fprintf (stderr, ">>> >>> ");
2381 fprintf (stderr, format,
2382 n_iterations_expected_this_test);
2386 make_and_run_test_nodes (void)
2390 /* We try to do this in order of "complicatedness" so that test
2391 * failures tend to show up in the simplest test case that
2392 * demonstrates the failure. There are also some tests that run
2393 * more than once for this reason, first while going through simple
2394 * cases, second while going through a broader range of complex
2397 /* Each basic node. The basic nodes should include:
2399 * - each fixed-size type (in such a way that it has different values each time,
2400 * so we can tell if we mix two of them up)
2401 * - strings of various lengths
2405 /* Each container node. The container nodes should include:
2407 * struct with 1 and 2 copies of the contained item
2408 * array with 0, 1, 2 copies of the contained item
2411 /* Let a "value" be a basic node, or a container containing a single basic node.
2412 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2413 * When iterating through all values to make combinations, do the basic types
2414 * first and the containers second.
2416 /* Each item is shown with its number of iterations to complete so
2417 * we can keep a handle on this unit test
2420 /* FIXME test just an empty body, no types at all */
2422 start_next_test ("Each value by itself %d iterations\n", N_VALUES);
2426 while ((node = value_generator (&i)))
2428 run_test_nodes (&node, 1);
2430 node_destroy (node);
2434 start_next_test ("All values in one big toplevel %d iteration\n", 1);
2436 TestTypeNode *nodes[N_VALUES];
2439 while ((nodes[i] = value_generator (&i)))
2442 run_test_nodes (nodes, N_VALUES);
2444 for (i = 0; i < N_VALUES; i++)
2445 node_destroy (nodes[i]);
2448 start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
2449 N_VALUES * N_VALUES);
2451 TestTypeNode *nodes[2];
2454 while ((nodes[0] = value_generator (&i)))
2457 while ((nodes[1] = value_generator (&j)))
2459 run_test_nodes (nodes, 2);
2461 node_destroy (nodes[1]);
2464 node_destroy (nodes[0]);
2468 start_next_test ("Each container containing each value %d iterations\n",
2469 N_CONTAINERS * N_VALUES);
2470 for (i = 0; i < N_CONTAINERS; i++)
2472 const TestTypeNodeClass *container_klass = container_nodes[i];
2474 make_and_run_values_inside_container (container_klass, 1);
2477 n_iterations_completed_this_test = 0;
2478 n_iterations_expected_this_test = N_CONTAINERS * N_VALUES;
2479 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2480 n_iterations_completed_this_test);
2481 for (i = 0; i < N_CONTAINERS; i++)
2483 const TestTypeNodeClass *container_klass = container_nodes[i];
2485 make_and_run_values_inside_container (container_klass, 2);
2488 start_next_test ("Each container of same container of same container of each value %d iterations\n",
2489 N_CONTAINERS * N_VALUES);
2490 for (i = 0; i < N_CONTAINERS; i++)
2492 const TestTypeNodeClass *container_klass = container_nodes[i];
2494 make_and_run_values_inside_container (container_klass, 3);
2497 start_next_test ("Each value,value pair inside a struct %d iterations\n",
2498 N_VALUES * N_VALUES);
2500 TestTypeNode *val1, *val2;
2503 node = node_new (&struct_1_class);
2506 while ((val1 = value_generator (&i)))
2509 while ((val2 = value_generator (&j)))
2511 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2513 node_append_child (node, val1);
2514 node_append_child (node, val2);
2516 run_test_nodes (&node, 1);
2518 _dbus_list_clear (&container->children);
2519 node_destroy (val2);
2521 node_destroy (val1);
2523 node_destroy (node);
2526 start_next_test ("All values in one big struct %d iteration\n",
2530 TestTypeNode *child;
2532 node = node_new (&struct_1_class);
2535 while ((child = value_generator (&i)))
2536 node_append_child (node, child);
2538 run_test_nodes (&node, 1);
2540 node_destroy (node);
2543 start_next_test ("Each value in a large array %d iterations\n",
2549 node = node_new (&array_9_class);
2552 while ((val = value_generator (&i)))
2554 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2556 node_append_child (node, val);
2558 run_test_nodes (&node, 1);
2560 _dbus_list_clear (&container->children);
2564 node_destroy (node);
2567 start_next_test ("Each container of each container of each value %d iterations\n",
2568 N_CONTAINERS * N_CONTAINERS * N_VALUES);
2569 for (i = 0; i < N_CONTAINERS; i++)
2571 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2572 TestTypeNode *outer_container = node_new (outer_container_klass);
2574 for (j = 0; j < N_CONTAINERS; j++)
2576 TestTypeNode *child;
2577 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2578 TestTypeNode *inner_container = node_new (inner_container_klass);
2580 node_append_child (outer_container, inner_container);
2583 while ((child = value_generator (&m)))
2585 node_append_child (inner_container, child);
2587 run_test_nodes (&outer_container, 1);
2589 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2590 node_destroy (child);
2592 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2593 node_destroy (inner_container);
2595 node_destroy (outer_container);
2598 start_next_test ("Each container of each container of each container of each value %d iterations\n",
2599 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2600 for (i = 0; i < N_CONTAINERS; i++)
2602 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2603 TestTypeNode *outer_container = node_new (outer_container_klass);
2605 for (j = 0; j < N_CONTAINERS; j++)
2607 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2608 TestTypeNode *inner_container = node_new (inner_container_klass);
2610 node_append_child (outer_container, inner_container);
2612 for (k = 0; k < N_CONTAINERS; k++)
2614 TestTypeNode *child;
2615 const TestTypeNodeClass *center_container_klass = container_nodes[k];
2616 TestTypeNode *center_container = node_new (center_container_klass);
2618 node_append_child (inner_container, center_container);
2621 while ((child = value_generator (&m)))
2623 node_append_child (center_container, child);
2625 run_test_nodes (&outer_container, 1);
2627 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2628 node_destroy (child);
2630 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2631 node_destroy (center_container);
2633 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2634 node_destroy (inner_container);
2636 node_destroy (outer_container);
2640 /* This one takes a really long time, so comment it out for now */
2641 start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2642 N_VALUES * N_VALUES * N_VALUES);
2644 TestTypeNode *nodes[3];
2647 while ((nodes[0] = value_generator (&i)))
2650 while ((nodes[1] = value_generator (&j)))
2653 while ((nodes[2] = value_generator (&k)))
2655 run_test_nodes (nodes, 3);
2657 node_destroy (nodes[2]);
2659 node_destroy (nodes[1]);
2661 node_destroy (nodes[0]);
2664 #endif /* #if 0 expensive test */
2666 fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
2667 n_iterations_completed_total);
2668 fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
2669 MAX_INITIAL_OFFSET);
2670 fprintf (stderr, "out of memory handling %s tested\n",
2671 TEST_OOM_HANDLING ? "was" : "was not");
2674 dbus_bool_t _dbus_marshal_recursive_test (void);
2677 _dbus_marshal_recursive_test (void)
2679 make_and_run_test_nodes ();
2685 dbus_bool_t _dbus_marshal_test (void);
2687 main (int argc, char **argv)
2689 _dbus_marshal_test ();
2691 _dbus_marshal_recursive_test ();
2701 * Implementations of each type node class
2708 #define SAMPLE_INT32 12345678
2709 #define SAMPLE_INT32_ALTERNATE 53781429
2711 int32_from_seed (int seed)
2713 /* Generate an integer value that's predictable from seed. We could
2714 * just use seed itself, but that would only ever touch one byte of
2715 * the int so would miss some kinds of bug.
2719 v = 42; /* just to quiet compiler afaik */
2726 v = SAMPLE_INT32_ALTERNATE;
2740 v *= seed; /* wraps around eventually, which is fine */
2746 int32_write_value (TestTypeNode *node,
2748 DBusTypeWriter *writer,
2751 /* also used for uint32 */
2754 v = int32_from_seed (seed);
2756 return _dbus_type_writer_write_basic (writer,
2757 node->klass->typecode,
2762 int32_read_value (TestTypeNode *node,
2764 DBusTypeReader *reader,
2767 /* also used for uint32 */
2770 check_expected_type (reader, node->klass->typecode);
2772 _dbus_type_reader_read_basic (reader,
2773 (dbus_int32_t*) &v);
2775 _dbus_assert (v == int32_from_seed (seed));
2780 #ifdef DBUS_HAVE_INT64
2782 int64_from_seed (int seed)
2787 v32 = int32_from_seed (seed);
2789 v = - (dbus_int32_t) ~ v32;
2790 v |= (((dbus_int64_t)v32) << 32);
2797 int64_write_value (TestTypeNode *node,
2799 DBusTypeWriter *writer,
2802 #ifdef DBUS_HAVE_INT64
2803 /* also used for uint64 */
2806 v = int64_from_seed (seed);
2808 return _dbus_type_writer_write_basic (writer,
2809 node->klass->typecode,
2817 int64_read_value (TestTypeNode *node,
2819 DBusTypeReader *reader,
2822 #ifdef DBUS_HAVE_INT64
2823 /* also used for uint64 */
2826 check_expected_type (reader, node->klass->typecode);
2828 _dbus_type_reader_read_basic (reader,
2829 (dbus_int64_t*) &v);
2831 _dbus_assert (v == int64_from_seed (seed));
2839 #define MAX_SAMPLE_STRING_LEN 10
2841 string_from_seed (char *buf,
2848 _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
2850 v = (unsigned char) ('A' + seed);
2855 if (v < 'A' || v > 'z')
2868 string_write_value (TestTypeNode *node,
2870 DBusTypeWriter *writer,
2873 char buf[MAX_SAMPLE_STRING_LEN];
2874 const char *v_string = buf;
2876 string_from_seed (buf, node->klass->subclass_detail,
2879 return _dbus_type_writer_write_basic (writer,
2880 node->klass->typecode,
2885 string_read_value (TestTypeNode *node,
2887 DBusTypeReader *reader,
2891 char buf[MAX_SAMPLE_STRING_LEN];
2893 check_expected_type (reader, node->klass->typecode);
2895 _dbus_type_reader_read_basic (reader,
2896 (const char **) &v);
2898 string_from_seed (buf, node->klass->subclass_detail,
2901 if (strcmp (buf, v) != 0)
2903 _dbus_warn ("read string '%s' expected '%s'\n",
2905 _dbus_assert_not_reached ("test failed");
2911 #define BOOL_FROM_SEED(seed) (seed % 2)
2914 bool_write_value (TestTypeNode *node,
2916 DBusTypeWriter *writer,
2921 v = BOOL_FROM_SEED (seed);
2923 return _dbus_type_writer_write_basic (writer,
2924 node->klass->typecode,
2929 bool_read_value (TestTypeNode *node,
2931 DBusTypeReader *reader,
2936 check_expected_type (reader, node->klass->typecode);
2938 _dbus_type_reader_read_basic (reader,
2939 (unsigned char*) &v);
2941 _dbus_assert (v == BOOL_FROM_SEED (seed));
2946 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
2949 byte_write_value (TestTypeNode *node,
2951 DBusTypeWriter *writer,
2956 v = BYTE_FROM_SEED (seed);
2958 return _dbus_type_writer_write_basic (writer,
2959 node->klass->typecode,
2964 byte_read_value (TestTypeNode *node,
2966 DBusTypeReader *reader,
2971 check_expected_type (reader, node->klass->typecode);
2973 _dbus_type_reader_read_basic (reader,
2974 (unsigned char*) &v);
2976 _dbus_assert (v == BYTE_FROM_SEED (seed));
2982 double_from_seed (int seed)
2984 return SAMPLE_INT32 * (double) seed + 0.3;
2988 double_write_value (TestTypeNode *node,
2990 DBusTypeWriter *writer,
2995 v = double_from_seed (seed);
2997 return _dbus_type_writer_write_basic (writer,
2998 node->klass->typecode,
3003 double_read_value (TestTypeNode *node,
3005 DBusTypeReader *reader,
3011 check_expected_type (reader, node->klass->typecode);
3013 _dbus_type_reader_read_basic (reader,
3016 expected = double_from_seed (seed);
3018 if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
3020 #ifdef DBUS_HAVE_INT64
3021 _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
3023 *(dbus_uint64_t*)&expected,
3024 *(dbus_uint64_t*)&v);
3026 _dbus_assert_not_reached ("test failed");
3033 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
3035 object_path_from_seed (char *buf,
3041 v = (unsigned char) ('A' + seed);
3046 if (v < 'A' || v > 'z')
3061 object_path_write_value (TestTypeNode *node,
3063 DBusTypeWriter *writer,
3066 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3067 const char *v_string = buf;
3069 object_path_from_seed (buf, seed);
3071 return _dbus_type_writer_write_basic (writer,
3072 node->klass->typecode,
3077 object_path_read_value (TestTypeNode *node,
3079 DBusTypeReader *reader,
3083 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3085 check_expected_type (reader, node->klass->typecode);
3087 _dbus_type_reader_read_basic (reader,
3088 (const char **) &v);
3090 object_path_from_seed (buf, seed);
3092 if (strcmp (buf, v) != 0)
3094 _dbus_warn ("read object path '%s' expected '%s'\n",
3096 _dbus_assert_not_reached ("test failed");
3103 #define MAX_SAMPLE_SIGNATURE_LEN 10
3105 signature_from_seed (char *buf,
3110 const char *sample_signatures[] = {
3118 s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
3120 for (i = 0; s[i]; i++)
3128 signature_write_value (TestTypeNode *node,
3130 DBusTypeWriter *writer,
3133 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3134 const char *v_string = buf;
3136 signature_from_seed (buf, seed);
3138 return _dbus_type_writer_write_basic (writer,
3139 node->klass->typecode,
3144 signature_read_value (TestTypeNode *node,
3146 DBusTypeReader *reader,
3150 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3152 check_expected_type (reader, node->klass->typecode);
3154 _dbus_type_reader_read_basic (reader,
3155 (const char **) &v);
3157 signature_from_seed (buf, seed);
3159 if (strcmp (buf, v) != 0)
3161 _dbus_warn ("read signature value '%s' expected '%s'\n",
3163 _dbus_assert_not_reached ("test failed");
3170 struct_write_value (TestTypeNode *node,
3172 DBusTypeWriter *writer,
3175 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3176 DataBlockState saved;
3181 n_copies = node->klass->subclass_detail;
3183 _dbus_assert (container->children != NULL);
3185 data_block_save (block, &saved);
3187 if (!_dbus_type_writer_recurse_struct (writer,
3192 while (i < n_copies)
3196 link = _dbus_list_get_first_link (&container->children);
3197 while (link != NULL)
3199 TestTypeNode *child = link->data;
3200 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3202 if (!node_write_value (child, block, &sub, i))
3204 data_block_restore (block, &saved);
3214 if (!_dbus_type_writer_unrecurse (writer, &sub))
3216 data_block_restore (block, &saved);
3224 struct_read_value (TestTypeNode *node,
3226 DBusTypeReader *reader,
3229 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3234 n_copies = node->klass->subclass_detail;
3236 check_expected_type (reader, DBUS_TYPE_STRUCT);
3238 _dbus_type_reader_recurse (reader, &sub);
3241 while (i < n_copies)
3245 link = _dbus_list_get_first_link (&container->children);
3246 while (link != NULL)
3248 TestTypeNode *child = link->data;
3249 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3251 if (!node_read_value (child, block, &sub, i))
3254 if (i == (n_copies - 1) && next == NULL)
3255 NEXT_EXPECTING_FALSE (&sub);
3257 NEXT_EXPECTING_TRUE (&sub);
3269 struct_build_signature (TestTypeNode *node,
3272 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3277 n_copies = node->klass->subclass_detail;
3279 orig_len = _dbus_string_get_length (str);
3281 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3285 while (i < n_copies)
3289 link = _dbus_list_get_first_link (&container->children);
3290 while (link != NULL)
3292 TestTypeNode *child = link->data;
3293 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3295 if (!node_build_signature (child, str))
3304 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3310 _dbus_string_set_length (str, orig_len);
3315 array_write_value (TestTypeNode *node,
3317 DBusTypeWriter *writer,
3320 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3321 DataBlockState saved;
3323 DBusString element_signature;
3327 n_copies = node->klass->subclass_detail;
3329 _dbus_assert (container->children != NULL);
3331 data_block_save (block, &saved);
3333 if (!_dbus_string_init (&element_signature))
3336 if (!node_build_signature (_dbus_list_get_first (&container->children),
3337 &element_signature))
3340 if (!_dbus_type_writer_recurse_array (writer,
3341 _dbus_string_get_const_data (&element_signature),
3346 while (i < n_copies)
3350 link = _dbus_list_get_first_link (&container->children);
3351 while (link != NULL)
3353 TestTypeNode *child = link->data;
3354 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3356 if (!node_write_value (child, block, &sub, i))
3365 if (!_dbus_type_writer_unrecurse (writer, &sub))
3368 _dbus_string_free (&element_signature);
3372 data_block_restore (block, &saved);
3373 _dbus_string_free (&element_signature);
3378 array_read_value (TestTypeNode *node,
3380 DBusTypeReader *reader,
3383 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3388 n_copies = node->klass->subclass_detail;
3390 check_expected_type (reader, DBUS_TYPE_ARRAY);
3394 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3396 _dbus_type_reader_recurse (reader, &sub);
3399 while (i < n_copies)
3403 link = _dbus_list_get_first_link (&container->children);
3404 while (link != NULL)
3406 TestTypeNode *child = link->data;
3407 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3409 if (!node_read_value (child, block, &sub, i))
3412 if (i == (n_copies - 1) && next == NULL)
3413 NEXT_EXPECTING_FALSE (&sub);
3415 NEXT_EXPECTING_TRUE (&sub);
3425 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3432 array_build_signature (TestTypeNode *node,
3435 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3438 orig_len = _dbus_string_get_length (str);
3440 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3443 if (!node_build_signature (_dbus_list_get_first (&container->children),
3450 _dbus_string_set_length (str, orig_len);
3454 /* 10 is random just to add another seed that we use in the suite */
3455 #define VARIANT_SEED 10
3458 variant_write_value (TestTypeNode *node,
3460 DBusTypeWriter *writer,
3463 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3464 DataBlockState saved;
3466 DBusString content_signature;
3467 TestTypeNode *child;
3469 _dbus_assert (container->children != NULL);
3470 _dbus_assert (_dbus_list_length_is_one (&container->children));
3472 child = _dbus_list_get_first (&container->children);
3474 data_block_save (block, &saved);
3476 if (!_dbus_string_init (&content_signature))
3479 if (!node_build_signature (child,
3480 &content_signature))
3483 if (!_dbus_type_writer_recurse_variant (writer,
3484 _dbus_string_get_const_data (&content_signature),
3488 if (!node_write_value (child, block, &sub, VARIANT_SEED))
3491 if (!_dbus_type_writer_unrecurse (writer, &sub))
3494 _dbus_string_free (&content_signature);
3498 data_block_restore (block, &saved);
3499 _dbus_string_free (&content_signature);
3504 variant_read_value (TestTypeNode *node,
3506 DBusTypeReader *reader,
3509 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3511 TestTypeNode *child;
3513 _dbus_assert (container->children != NULL);
3514 _dbus_assert (_dbus_list_length_is_one (&container->children));
3516 child = _dbus_list_get_first (&container->children);
3518 check_expected_type (reader, DBUS_TYPE_VARIANT);
3520 _dbus_type_reader_recurse (reader, &sub);
3522 if (!node_read_value (child, block, &sub, VARIANT_SEED))
3525 NEXT_EXPECTING_FALSE (&sub);
3531 container_destroy (TestTypeNode *node)
3533 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3536 link = _dbus_list_get_first_link (&container->children);
3537 while (link != NULL)
3539 TestTypeNode *child = link->data;
3540 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3542 node_destroy (child);
3544 _dbus_list_free_link (link);
3550 #endif /* DBUS_BUILD_TESTS */