1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c Marshalling routines for recursive types
4 * Copyright (C) 2004, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-marshal-recursive.h"
25 #include "dbus-marshal-basic.h"
26 #include "dbus-internals.h"
29 * @addtogroup DBusMarshal
32 #define RECURSIVE_MARSHAL_TRACE 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 dbus_bool_t (* check_finished) (const DBusTypeReader *reader);
42 void (* next) (DBusTypeReader *reader,
44 void (* init_from_mark) (DBusTypeReader *reader,
45 const DBusTypeMark *mark);
49 first_type_in_signature (const DBusString *str,
54 t = _dbus_string_get_byte (str, pos);
56 if (t == DBUS_STRUCT_BEGIN_CHAR)
57 return DBUS_TYPE_STRUCT;
63 element_type_get_alignment (const DBusString *str,
66 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
70 reader_init (DBusTypeReader *reader,
72 const DBusString *type_str,
74 const DBusString *value_str,
77 reader->byte_order = byte_order;
78 reader->finished = FALSE;
79 reader->type_str = type_str;
80 reader->type_pos = type_pos;
81 reader->value_str = value_str;
82 reader->value_pos = value_pos;
86 base_reader_recurse (DBusTypeReader *sub,
87 DBusTypeReader *parent)
89 /* point subreader at the same place as parent */
99 struct_types_only_reader_recurse (DBusTypeReader *sub,
100 DBusTypeReader *parent)
102 base_reader_recurse (sub, parent);
104 _dbus_assert (_dbus_string_get_byte (sub->type_str,
105 sub->type_pos) == DBUS_STRUCT_BEGIN_CHAR);
111 struct_reader_recurse (DBusTypeReader *sub,
112 DBusTypeReader *parent)
114 struct_types_only_reader_recurse (sub, parent);
116 /* struct has 8 byte alignment */
117 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
121 array_types_only_reader_recurse (DBusTypeReader *sub,
122 DBusTypeReader *parent)
124 base_reader_recurse (sub, parent);
126 /* point type_pos at the array element type */
129 /* Init with values likely to crash things if misused */
130 sub->u.array.start_pos = _DBUS_INT_MAX;
131 sub->array_len_offset = 7;
135 array_reader_get_array_len (const DBusTypeReader *reader)
137 dbus_uint32_t array_len;
140 /* array_len_offset is the offset back from start_pos to end of the len */
141 len_pos = reader->u.array.start_pos - ((int)reader->array_len_offset) - 4;
143 _dbus_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 array_types_only_reader_recurse (sub, parent);
166 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
168 len_pos = sub->value_pos;
170 sub->value_pos += 4; /* for the length */
172 alignment = element_type_get_alignment (sub->type_str,
175 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
177 sub->u.array.start_pos = sub->value_pos;
178 _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */
179 sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);
181 #if RECURSIVE_MARSHAL_TRACE
182 _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",
184 sub->u.array.start_pos,
185 sub->array_len_offset,
186 array_reader_get_array_len (sub),
187 _dbus_type_to_string (first_type_in_signature (sub->type_str,
193 variant_reader_recurse (DBusTypeReader *sub,
194 DBusTypeReader *parent)
198 base_reader_recurse (sub, parent);
200 /* Variant is 1 byte sig length (without nul), signature with nul,
201 * padding to 8-boundary, then values
204 sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);
206 sub->type_str = sub->value_str;
207 sub->type_pos = sub->value_pos + 1;
209 sub->value_pos = sub->type_pos + sig_len + 1;
211 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
213 #if RECURSIVE_MARSHAL_TRACE
214 _dbus_verbose (" type reader %p variant containing '%s'\n",
216 _dbus_string_get_const_data_len (sub->type_str,
222 array_reader_check_finished (const DBusTypeReader *reader)
226 /* return the array element type if elements remain, and
227 * TYPE_INVALID otherwise
230 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
232 _dbus_assert (reader->value_pos <= end_pos);
233 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
235 return reader->value_pos == end_pos;
239 skip_one_complete_type (const DBusString *type_str,
242 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
245 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
252 switch (_dbus_string_get_byte (type_str, *type_pos))
254 case DBUS_STRUCT_BEGIN_CHAR:
257 case DBUS_STRUCT_END_CHAR:
260 case DBUS_TYPE_INVALID:
261 _dbus_assert_not_reached ("unbalanced parens in signature");
272 find_len_of_complete_type (const DBusString *type_str,
279 skip_one_complete_type (type_str, &end);
281 return end - type_pos;
285 base_reader_next (DBusTypeReader *reader,
288 switch (current_type)
290 case DBUS_TYPE_STRUCT:
291 case DBUS_TYPE_VARIANT:
292 /* Scan forward over the entire container contents */
296 /* Recurse into the struct or variant */
297 _dbus_type_reader_recurse (reader, &sub);
299 /* Skip everything in this subreader */
300 while (_dbus_type_reader_next (&sub))
305 /* Now we are at the end of this container; for variants, the
306 * subreader's type_pos is totally inapplicable (it's in the
307 * value string) but we know that we increment by one past the
310 if (current_type == DBUS_TYPE_VARIANT)
311 reader->type_pos += 1;
313 reader->type_pos = sub.type_pos;
315 if (!reader->klass->types_only)
316 reader->value_pos = sub.value_pos;
320 case DBUS_TYPE_ARRAY:
322 if (!reader->klass->types_only)
323 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
324 first_type_in_signature (reader->type_str,
325 reader->type_pos + 1),
328 skip_one_complete_type (reader->type_str, &reader->type_pos);
333 if (!reader->klass->types_only)
334 _dbus_marshal_skip_basic_type (reader->value_str,
335 current_type, reader->byte_order,
338 reader->type_pos += 1;
344 struct_reader_next (DBusTypeReader *reader,
349 base_reader_next (reader, current_type);
351 /* for STRUCT containers we return FALSE at the end of the struct,
352 * for INVALID we return FALSE at the end of the signature.
353 * In both cases we arrange for get_current_type() to return INVALID
354 * which is defined to happen iff we're at the end (no more next())
356 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
357 if (t == DBUS_STRUCT_END_CHAR)
359 reader->type_pos += 1;
360 reader->finished = TRUE;
365 array_types_only_reader_next (DBusTypeReader *reader,
368 /* We have one "element" to be iterated over
369 * in each array, which is its element type.
370 * So the finished flag indicates whether we've
371 * iterated over it yet or not.
373 reader->finished = TRUE;
377 array_reader_next (DBusTypeReader *reader,
380 /* Skip one array element */
383 end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);
385 _dbus_assert (reader->value_pos < end_pos);
386 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
388 switch (first_type_in_signature (reader->type_str,
391 case DBUS_TYPE_STRUCT:
392 case DBUS_TYPE_VARIANT:
396 /* Recurse into the struct or variant */
397 _dbus_type_reader_recurse (reader, &sub);
399 /* Skip everything in this element */
400 while (_dbus_type_reader_next (&sub))
405 /* Now we are at the end of this element */
406 reader->value_pos = sub.value_pos;
410 case DBUS_TYPE_ARRAY:
412 _dbus_marshal_skip_array (reader->value_str, reader->byte_order,
413 first_type_in_signature (reader->type_str,
414 reader->type_pos + 1),
421 _dbus_marshal_skip_basic_type (reader->value_str,
422 current_type, reader->byte_order,
428 _dbus_assert (reader->value_pos <= end_pos);
430 if (reader->value_pos == end_pos)
432 skip_one_complete_type (reader->type_str,
438 array_init_from_mark (DBusTypeReader *reader,
439 const DBusTypeMark *mark)
441 /* Fill in the array-specific fields from the mark. The general
442 * fields are already filled in.
444 reader->u.array.start_pos = mark->array_start_pos;
445 reader->array_len_offset = mark->array_len_offset;
448 static const DBusTypeReaderClass body_reader_class = {
451 NULL, /* body is always toplevel, so doesn't get recursed into */
457 static const DBusTypeReaderClass body_types_only_reader_class = {
460 NULL, /* body is always toplevel, so doesn't get recursed into */
466 static const DBusTypeReaderClass struct_reader_class = {
469 struct_reader_recurse,
475 static const DBusTypeReaderClass struct_types_only_reader_class = {
478 struct_types_only_reader_recurse,
484 static const DBusTypeReaderClass array_reader_class = {
487 array_reader_recurse,
488 array_reader_check_finished,
493 static const DBusTypeReaderClass array_types_only_reader_class = {
496 array_types_only_reader_recurse,
498 array_types_only_reader_next,
502 static const DBusTypeReaderClass variant_reader_class = {
505 variant_reader_recurse,
511 static const DBusTypeReaderClass const *
512 all_reader_classes[] = {
514 &body_types_only_reader_class,
515 &struct_reader_class,
516 &struct_types_only_reader_class,
518 &array_types_only_reader_class,
519 &variant_reader_class
523 _dbus_type_reader_init (DBusTypeReader *reader,
525 const DBusString *type_str,
527 const DBusString *value_str,
530 reader->klass = &body_reader_class;
532 reader_init (reader, byte_order, type_str, type_pos,
533 value_str, value_pos);
535 #if RECURSIVE_MARSHAL_TRACE
536 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
537 reader, reader->type_pos, reader->value_pos,
538 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
543 _dbus_type_reader_init_from_mark (DBusTypeReader *reader,
545 const DBusString *type_str,
546 const DBusString *value_str,
547 const DBusTypeMark *mark)
549 reader->klass = all_reader_classes[mark->container_type];
551 reader_init (reader, byte_order,
552 mark->type_pos_in_value_str ? value_str : type_str,
554 value_str, mark->value_pos);
556 if (reader->klass->init_from_mark)
557 (* reader->klass->init_from_mark) (reader, mark);
559 #if RECURSIVE_MARSHAL_TRACE
560 _dbus_verbose (" type reader %p init from mark type_pos = %d value_pos = %d remaining sig '%s'\n",
561 reader, reader->type_pos, reader->value_pos,
562 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
567 _dbus_type_reader_init_types_only (DBusTypeReader *reader,
568 const DBusString *type_str,
571 reader->klass = &body_types_only_reader_class;
573 reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,
574 type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);
576 #if RECURSIVE_MARSHAL_TRACE
577 _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",
578 reader, reader->type_pos,
579 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
584 _dbus_type_reader_init_types_only_from_mark (DBusTypeReader *reader,
585 const DBusString *type_str,
586 const DBusTypeMark *mark)
588 reader->klass = all_reader_classes[mark->container_type];
589 _dbus_assert (reader->klass->types_only);
590 _dbus_assert (!mark->type_pos_in_value_str);
592 reader_init (reader, DBUS_COMPILER_BYTE_ORDER, /* irrelevant */
593 type_str, mark->type_pos,
594 NULL, _DBUS_INT_MAX /* crashes if we screw up */);
596 if (reader->klass->init_from_mark)
597 (* reader->klass->init_from_mark) (reader, mark);
599 #if RECURSIVE_MARSHAL_TRACE
600 _dbus_verbose (" type reader %p init types only from mark type_pos = %d remaining sig '%s'\n",
601 reader, reader->type_pos,
602 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
607 _dbus_type_reader_save_mark (const DBusTypeReader *reader,
610 mark->type_pos_in_value_str = (reader->type_str == reader->value_str);
611 mark->container_type = reader->klass->id;
612 _dbus_assert (all_reader_classes[reader->klass->id] == reader->klass);
614 mark->type_pos = reader->type_pos;
615 mark->value_pos = reader->value_pos;
617 /* these are just junk if the reader isn't really an array of course */
618 mark->array_len_offset = reader->array_len_offset;
619 mark->array_start_pos = reader->u.array.start_pos;
623 _dbus_type_reader_get_current_type (const DBusTypeReader *reader)
627 if (reader->finished ||
628 (reader->klass->check_finished &&
629 (* reader->klass->check_finished) (reader)))
630 t = DBUS_TYPE_INVALID;
632 t = first_type_in_signature (reader->type_str,
635 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
636 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
639 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
640 reader, reader->type_pos,
641 _dbus_type_to_string (t));
648 _dbus_type_reader_array_is_empty (const DBusTypeReader *reader)
650 dbus_uint32_t array_len;
652 _dbus_assert (_dbus_type_reader_get_current_type (reader) == DBUS_TYPE_ARRAY);
653 _dbus_assert (!reader->klass->types_only);
655 /* reader is supposed to be at an array child */
656 #if RECURSIVE_MARSHAL_TRACE
657 _dbus_verbose ("checking array len at %d\n", reader->value_pos);
660 _dbus_demarshal_basic_type (reader->value_str,
666 #if RECURSIVE_MARSHAL_TRACE
667 _dbus_verbose (" ... array len = %d\n", array_len);
670 return array_len == 0;
674 _dbus_type_reader_read_basic (const DBusTypeReader *reader,
679 _dbus_assert (!reader->klass->types_only);
681 t = _dbus_type_reader_get_current_type (reader);
683 _dbus_demarshal_basic_type (reader->value_str,
686 reader->value_pos, NULL);
689 #if RECURSIVE_MARSHAL_TRACE
690 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",
691 reader, reader->type_pos, reader->value_pos,
692 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
697 _dbus_type_reader_read_array_of_basic (const DBusTypeReader *reader,
702 _dbus_assert (!reader->klass->types_only);
707 * Initialize a new reader pointing to the first type and
708 * corresponding value that's a child of the current container. It's
709 * an error to call this if the current type is a non-container.
711 * Note that DBusTypeReader traverses values, not types. So if you
712 * have an empty array of array of int, you can't recurse into it. You
713 * can only recurse into each element.
715 * @param reader the reader
716 * @param sub a reader to init pointing to the first child
719 _dbus_type_reader_recurse (DBusTypeReader *reader,
724 t = first_type_in_signature (reader->type_str, reader->type_pos);
728 case DBUS_TYPE_STRUCT:
729 if (reader->klass->types_only)
730 sub->klass = &struct_types_only_reader_class;
732 sub->klass = &struct_reader_class;
734 case DBUS_TYPE_ARRAY:
735 if (reader->klass->types_only)
736 sub->klass = &array_types_only_reader_class;
738 sub->klass = &array_reader_class;
740 case DBUS_TYPE_VARIANT:
741 if (reader->klass->types_only)
742 _dbus_assert_not_reached ("can't recurse into variant typecode");
744 sub->klass = &variant_reader_class;
747 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
748 #ifndef DBUS_DISABLE_CHECKS
749 if (t == DBUS_TYPE_INVALID)
750 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
751 #endif /* DBUS_DISABLE_CHECKS */
753 _dbus_assert_not_reached ("don't yet handle recursing into this type");
756 _dbus_assert (sub->klass == all_reader_classes[sub->klass->id]);
758 (* sub->klass->recurse) (sub, reader);
760 #if RECURSIVE_MARSHAL_TRACE
761 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
762 sub, sub->type_pos, sub->value_pos,
763 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
768 * Skip to the next value on this "level". e.g. the next field in a
769 * struct, the next value in an array. Returns FALSE at the end of the
772 * @param reader the reader
773 * @returns FALSE if nothing more to read at or below this level
776 _dbus_type_reader_next (DBusTypeReader *reader)
780 t = _dbus_type_reader_get_current_type (reader);
782 #if RECURSIVE_MARSHAL_TRACE
783 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
784 reader, reader->type_pos, reader->value_pos,
785 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
786 _dbus_type_to_string (t));
789 if (t == DBUS_TYPE_INVALID)
792 (* reader->klass->next) (reader, t);
794 #if RECURSIVE_MARSHAL_TRACE
795 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
796 reader, reader->type_pos, reader->value_pos,
797 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
798 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
801 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
805 * Check whether there's another value on this "level". e.g. the next
806 * field in a struct, the next value in an array. Returns FALSE at the
807 * end of the current container.
809 * You probably don't want to use this; it makes for an awkward for/while
810 * loop. A nicer one is "while ((current_type = get_current_type()) != INVALID)"
812 * @param reader the reader
813 * @returns FALSE if nothing more to read at or below this level
816 _dbus_type_reader_has_next (const DBusTypeReader *reader)
818 /* Not efficient but works for now. */
822 return _dbus_type_reader_next (©);
826 * Gets the string and range of said string containing the signature
827 * of the current value. Essentially a more complete version of
828 * _dbus_type_reader_get_current_type() (returns the full type
829 * rather than only the outside of the onion).
831 * Note though that the first byte in a struct signature is
832 * #DBUS_STRUCT_BEGIN_CHAR while the current type will be
833 * #DBUS_TYPE_STRUCT so it isn't true that the first byte of the
834 * signature is always the same as the current type. Another
835 * difference is that this function will still return a signature when
836 * inside an empty array; say you recurse into empty array of int32,
837 * the signature is "i" but the current type will always be
838 * #DBUS_TYPE_INVALID since there are no elements to be currently
841 * @param reader the reader
842 * @param str_p place to return the string with the type in it
843 * @param start_p place to return start of the type
844 * @param len_p place to return the length of the type
847 _dbus_type_reader_get_signature (const DBusTypeReader *reader,
848 const DBusString **str_p,
852 *str_p = reader->type_str;
853 *start_p = reader->type_pos;
854 *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);
867 * Initialize a write iterator, which is used to write out values in
868 * serialized D-BUS format. #DBusTypeWriter is a value iterator; it
869 * writes out values. You can't use it to write out only types.
871 * The type_pos passed in is expected to be inside an already-valid,
872 * though potentially empty, type signature. This means that the byte
873 * after type_pos must be either #DBUS_TYPE_INVALID (aka nul) or some
874 * other valid type. #DBusTypeWriter won't enforce that the signature
875 * is already valid (you can append the nul byte at the end if you
876 * like), but just be aware that you need the nul byte eventually and
877 * #DBusTypeWriter isn't going to write it for you.
879 * @param writer the writer to init
880 * @param byte_order the byte order to marshal into
881 * @param type_str the string to write typecodes into
882 * @param type_pos where to insert typecodes
883 * @param value_str the string to write values into
884 * @param value_pos where to insert values
888 _dbus_type_writer_init (DBusTypeWriter *writer,
890 DBusString *type_str,
892 DBusString *value_str,
895 writer->byte_order = byte_order;
896 writer->type_str = type_str;
897 writer->type_pos = type_pos;
898 writer->value_str = value_str;
899 writer->value_pos = value_pos;
900 writer->container_type = DBUS_TYPE_INVALID;
901 writer->type_pos_is_expectation = FALSE;
903 #if RECURSIVE_MARSHAL_TRACE
904 _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,
905 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
910 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
914 return _dbus_marshal_basic_type (writer->value_str,
922 /* If our parent is an array, things are a little bit complicated.
924 * The parent must have a complete element type, such as
925 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
926 * unclosed parens, or an "a" with no following type.
928 * To recurse, the only allowed operation is to recurse into the
929 * first type in the element type. So for "i" you can't recurse, for
930 * "ai" you can recurse into the array, for "(ii)" you can recurse
933 * If you recurse into the array for "ai", then you must specify
934 * "i" for the element type of the array you recurse into.
936 * While inside an array at any level, we need to avoid writing to
937 * type_str, since the type only appears once for the whole array,
938 * it does not appear for each array element.
940 * While inside an array type_pos points to the expected next
941 * typecode, rather than the next place we could write a typecode.
944 writer_recurse_init_and_check (DBusTypeWriter *writer,
948 _dbus_type_writer_init (sub,
955 sub->container_type = container_type;
957 if (writer->type_pos_is_expectation ||
958 (sub->container_type == DBUS_TYPE_ARRAY || sub->container_type == DBUS_TYPE_VARIANT))
959 sub->type_pos_is_expectation = TRUE;
961 sub->type_pos_is_expectation = FALSE;
963 #ifndef DBUS_DISABLE_CHECKS
964 if (writer->type_pos_is_expectation)
968 expected = first_type_in_signature (writer->type_str, writer->type_pos);
970 if (expected != sub->container_type)
972 _dbus_warn ("Writing an element of type %s, but the expected type here is %s\n",
973 _dbus_type_to_string (sub->container_type),
974 _dbus_type_to_string (expected));
975 _dbus_assert_not_reached ("bad array element or variant content written");
978 #endif /* DBUS_DISABLE_CHECKS */
980 #if RECURSIVE_MARSHAL_TRACE
981 _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s'\n",
983 _dbus_type_to_string (writer->container_type),
984 writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
985 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
986 _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d\n",
988 _dbus_type_to_string (sub->container_type),
989 sub->type_pos, sub->value_pos,
990 sub->type_pos_is_expectation);
995 write_or_verify_typecode (DBusTypeWriter *writer,
998 /* A subwriter inside an array or variant will have type_pos
999 * pointing to the expected typecode; a writer not inside an array
1000 * or variant has type_pos pointing to the next place to insert a
1003 #if RECURSIVE_MARSHAL_TRACE
1004 _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s'\n",
1005 writer, writer->type_pos,
1006 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1009 if (writer->type_pos_is_expectation)
1011 #ifndef DBUS_DISABLE_CHECKS
1015 expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);
1017 if (expected != typecode)
1019 _dbus_warn ("Array or variant type requires that type %s be written, but %s was written\n",
1020 _dbus_type_to_string (expected), _dbus_type_to_string (typecode));
1021 _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");
1024 #endif /* DBUS_DISABLE_CHECKS */
1026 /* if immediately inside an array we'd always be appending an element,
1027 * so the expected type doesn't change; if inside a struct or something
1028 * below an array, we need to move through said struct or something.
1030 if (writer->container_type != DBUS_TYPE_ARRAY)
1031 writer->type_pos += 1;
1035 if (!_dbus_string_insert_byte (writer->type_str,
1040 writer->type_pos += 1;
1043 #if RECURSIVE_MARSHAL_TRACE
1044 _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",
1045 writer, writer->type_pos,
1046 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1053 _dbus_type_writer_recurse_struct (DBusTypeWriter *writer,
1054 DBusTypeWriter *sub)
1056 writer_recurse_init_and_check (writer, DBUS_TYPE_STRUCT, sub);
1058 /* Ensure that we'll be able to add alignment padding and the typecode */
1059 if (!_dbus_string_alloc_space (sub->value_str, 8))
1062 if (!_dbus_string_alloc_space (sub->type_str, 1))
1065 if (!write_or_verify_typecode (sub, DBUS_STRUCT_BEGIN_CHAR))
1066 _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");
1068 if (!_dbus_string_insert_bytes (sub->value_str,
1070 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1072 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
1073 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1079 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
1080 const char *element_type,
1081 DBusTypeWriter *sub)
1083 int element_type_len;
1084 DBusString element_type_str;
1085 dbus_uint32_t value = 0;
1090 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, sub);
1092 _dbus_string_init_const (&element_type_str, element_type);
1093 element_type_len = find_len_of_complete_type (&element_type_str, 0);
1095 #ifndef DBUS_DISABLE_CHECKS
1096 if (writer->container_type == DBUS_TYPE_ARRAY)
1098 if (!_dbus_string_equal_substring (&element_type_str, 0, element_type_len,
1099 writer->type_str, writer->u.array.element_type_pos + 1))
1101 _dbus_warn ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array\n",
1103 _dbus_assert_not_reached ("incompatible type for child array");
1106 #endif /* DBUS_DISABLE_CHECKS */
1108 /* 4 bytes for the array length and 4 bytes possible padding */
1109 if (!_dbus_string_alloc_space (sub->value_str, 8))
1112 sub->type_pos += 1; /* move to point to the element type, since type_pos
1113 * should be the expected type for further writes
1115 sub->u.array.element_type_pos = sub->type_pos;
1117 if (!writer->type_pos_is_expectation)
1119 /* sub is a toplevel/outermost array so we need to write the type data */
1121 /* alloc space for array typecode, element signature, possible 7
1124 if (!_dbus_string_alloc_space (writer->type_str, 1 + element_type_len + 7))
1127 if (!_dbus_string_insert_byte (writer->type_str,
1130 _dbus_assert_not_reached ("failed to insert array typecode after prealloc");
1132 if (!_dbus_string_copy_len (&element_type_str, 0, element_type_len,
1133 sub->type_str, sub->u.array.element_type_pos))
1134 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
1137 /* If the parent is an array, we hold type_pos pointing at the array element type;
1138 * otherwise advance it to reflect the array value we just recursed into
1140 if (writer->container_type != DBUS_TYPE_ARRAY)
1141 writer->type_pos += 1 + element_type_len;
1143 _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */
1145 /* Write the length */
1146 sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
1148 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
1150 _dbus_assert_not_reached ("should not have failed to insert array len");
1152 _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);
1154 /* Write alignment padding for array elements
1155 * Note that we write the padding *even for empty arrays*
1156 * to avoid wonky special cases
1158 _dbus_string_init_const (&str, element_type);
1159 alignment = element_type_get_alignment (&str, 0);
1161 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
1162 if (aligned != sub->value_pos)
1164 if (!_dbus_string_insert_bytes (sub->value_str,
1166 aligned - sub->value_pos,
1168 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
1170 sub->value_pos = aligned;
1172 sub->u.array.start_pos = sub->value_pos;
1174 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
1175 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
1177 #if RECURSIVE_MARSHAL_TRACE
1178 _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d\n", sub,
1179 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0),
1180 sub->u.array.start_pos, sub->u.array.len_pos);
1186 /* Variant value will normally have:
1187 * 1 byte signature length not including nul
1188 * signature typecodes (nul terminated)
1189 * padding to 8-boundary
1190 * body according to signature
1192 * The signature string can only have a single type
1193 * in it but that type may be complex/recursive.
1195 * So a typical variant type with the integer 3 will have these
1197 * 0x1 'i' '\0' [padding to 8-boundary] 0x0 0x0 0x0 0x3
1199 * For an array of 4-byte types stuffed into variants, the padding to
1200 * 8-boundary is only the 1 byte that is required for the 4-boundary
1201 * anyhow for all array elements after the first one. And for single
1202 * variants in isolation, wasting a few bytes is hardly a big deal.
1204 * The main world of hurt for writing out a variant is that the type
1205 * string is the same string as the value string. Which means
1206 * inserting to the type string will move the value_pos; and it means
1207 * that inserting to the type string could break type alignment.
1209 * This type alignment issue is why the body of the variant is always
1210 * 8-aligned. Then we know that re-8-aligning the start of the body
1211 * will always correctly align the full contents of the variant type.
1214 _dbus_type_writer_recurse_variant (DBusTypeWriter *writer,
1215 const char *contained_type,
1216 DBusTypeWriter *sub)
1218 int contained_type_len;
1219 DBusString contained_type_str;
1221 writer_recurse_init_and_check (writer, DBUS_TYPE_VARIANT, sub);
1223 _dbus_string_init_const (&contained_type_str, contained_type);
1225 contained_type_len = find_len_of_complete_type (&contained_type_str, 0);
1227 /* Allocate space for the worst case, which is 1 byte sig
1228 * length, nul byte at end of sig, and 7 bytes padding to
1231 if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))
1234 /* write VARIANT typecode to the parent's type string */
1235 if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))
1238 if (!_dbus_string_insert_byte (sub->value_str,
1240 contained_type_len))
1241 _dbus_assert_not_reached ("should not have failed to insert variant type sig len");
1243 sub->value_pos += 1;
1245 /* Here we switch over to the expected type sig we're about to write */
1246 sub->type_str = sub->value_str;
1247 sub->type_pos = sub->value_pos;
1249 if (!_dbus_string_copy_len (&contained_type_str, 0, contained_type_len,
1250 sub->value_str, sub->value_pos))
1251 _dbus_assert_not_reached ("should not have failed to insert variant type sig");
1253 sub->value_pos += contained_type_len;
1255 if (!_dbus_string_insert_byte (sub->value_str,
1258 _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");
1260 sub->value_pos += 1;
1262 if (!_dbus_string_insert_bytes (sub->value_str,
1264 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
1266 _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");
1267 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
1273 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
1274 DBusTypeWriter *sub)
1276 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
1278 /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */
1279 _dbus_assert (!writer->type_pos_is_expectation ||
1280 (writer->type_pos_is_expectation && sub->type_pos_is_expectation));
1282 #if RECURSIVE_MARSHAL_TRACE
1283 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1284 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,
1285 _dbus_type_to_string (writer->container_type));
1286 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",
1287 sub, sub->type_pos, sub->value_pos,
1288 sub->type_pos_is_expectation,
1289 _dbus_type_to_string (sub->container_type));
1292 if (sub->container_type == DBUS_TYPE_STRUCT)
1294 if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))
1297 else if (sub->container_type == DBUS_TYPE_ARRAY)
1301 /* Set the array length */
1302 len = sub->value_pos - sub->u.array.start_pos;
1303 _dbus_marshal_set_uint32 (sub->value_str,
1305 sub->u.array.len_pos,
1307 #if RECURSIVE_MARSHAL_TRACE
1308 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
1309 len, sub->u.array.len_pos);
1313 /* Now get type_pos right for the parent writer. Here are the cases:
1315 * Cases !writer->type_pos_is_expectation:
1316 * (in these cases we want to update to the new insertion point)
1318 * - if we recursed into a STRUCT then we didn't know in advance
1319 * what the types in the struct would be; so we have to fill in
1320 * that information now.
1321 * writer->type_pos = sub->type_pos
1323 * - if we recursed into anything else, we knew the full array
1324 * type, or knew the single typecode marking VARIANT, so
1325 * writer->type_pos is already correct.
1326 * writer->type_pos should remain as-is
1328 * - note that the parent is never an ARRAY or VARIANT, if it were
1329 * then type_pos_is_expectation would be TRUE. The parent
1330 * is thus known to be a toplevel or STRUCT.
1332 * Cases where writer->type_pos_is_expectation:
1333 * (in these cases we want to update to next expected type to write)
1335 * - we recursed from STRUCT into STRUCT and we didn't increment
1336 * type_pos in the parent just to stay consistent with the
1337 * !writer->type_pos_is_expectation case (though we could
1338 * special-case this in recurse_struct instead if we wanted)
1339 * writer->type_pos = sub->type_pos
1341 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos
1342 * for parent should have been incremented already
1343 * writer->type_pos should remain as-is
1345 * - we recursed from ARRAY into a sub-element, so type_pos in the
1346 * parent is the element type and should remain the element type
1347 * for the benefit of the next child element
1348 * writer->type_pos should remain as-is
1350 * - we recursed from VARIANT into its value, so type_pos in the
1351 * parent makes no difference since there's only one value
1352 * and we just finished writing it and won't use type_pos again
1353 * writer->type_pos should remain as-is
1355 if (sub->container_type == DBUS_TYPE_STRUCT &&
1356 (writer->container_type == DBUS_TYPE_STRUCT ||
1357 writer->container_type == DBUS_TYPE_INVALID))
1359 /* Advance the parent to the next struct field */
1360 writer->type_pos = sub->type_pos;
1363 writer->value_pos = sub->value_pos;
1365 #if RECURSIVE_MARSHAL_TRACE
1366 _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",
1367 writer, writer->type_pos, writer->value_pos,
1368 _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));
1375 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
1381 /* First ensure that our type realloc will succeed */
1382 if (!_dbus_string_alloc_space (writer->type_str, 1))
1387 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
1390 if (!write_or_verify_typecode (writer, type))
1391 _dbus_assert_not_reached ("failed to write typecode after prealloc");
1396 #if RECURSIVE_MARSHAL_TRACE
1397 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d\n",
1398 writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation);
1405 _dbus_type_writer_write_array (DBusTypeWriter *writer,
1415 * Iterate through all values in the given reader,
1416 * writing a copy of each value to the writer.
1417 * The reader will be moved forward to its end position.
1419 * @param writer the writer to copy to
1420 * @param reader the reader to copy from
1423 _dbus_type_writer_write_reader (DBusTypeWriter *writer,
1424 DBusTypeReader *reader)
1426 DBusTypeWriter orig;
1433 orig_type_len = _dbus_string_get_length (writer->type_str);
1434 orig_value_len = _dbus_string_get_length (writer->value_str);
1436 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
1438 switch (current_type)
1440 case DBUS_TYPE_STRUCT:
1441 case DBUS_TYPE_VARIANT:
1442 case DBUS_TYPE_ARRAY:
1444 DBusTypeReader subreader;
1445 DBusTypeWriter subwriter;
1446 const DBusString *sig_str;
1451 _dbus_type_reader_recurse (reader, &subreader);
1453 _dbus_type_reader_get_signature (&subreader, &sig_str,
1454 &sig_start, &sig_len);
1456 /* FIXME once this is working, mop it up with a generic recurse */
1457 if (current_type == DBUS_TYPE_STRUCT)
1458 ret = _dbus_type_writer_recurse_struct (writer, &subwriter);
1459 else if (current_type == DBUS_TYPE_VARIANT)
1460 ret = _dbus_type_writer_recurse_variant (writer,
1461 _dbus_string_get_const_data_len (sig_str,
1462 sig_start, sig_len),
1465 ret = _dbus_type_writer_recurse_array (writer,
1466 _dbus_string_get_const_data_len (sig_str,
1467 sig_start, sig_len),
1473 if (!_dbus_type_writer_write_reader (&subwriter, &subreader))
1476 if (!_dbus_type_writer_unrecurse (writer, &subwriter))
1485 _dbus_type_reader_read_basic (reader, &val);
1487 if (!_dbus_type_writer_write_basic (writer, current_type, &val))
1493 _dbus_type_reader_next (reader);
1499 if (!writer->type_pos_is_expectation)
1501 new_bytes = orig_type_len - _dbus_string_get_length (writer->type_str);
1502 _dbus_string_delete (writer->type_str, orig.type_pos, new_bytes);
1504 new_bytes = orig_value_len - _dbus_string_get_length (writer->value_str);
1505 _dbus_string_delete (writer->value_str, orig.value_pos, new_bytes);
1512 /** @} */ /* end of DBusMarshal group */
1514 #ifdef DBUS_BUILD_TESTS
1515 #include "dbus-test.h"
1516 #include "dbus-list.h"
1520 /* Whether to do the OOM stuff */
1521 #define TEST_OOM_HANDLING 0
1522 /* We do start offset 0 through 9, to get various alignment cases. Still this
1523 * obviously makes the test suite run 10x as slow.
1525 #define MAX_INITIAL_OFFSET 9
1526 /* Largest iteration count to test copying with. i.e. we only test copying with
1527 * some of the smaller data sets.
1529 #define MAX_ITERATIONS_TO_TEST_COPYING 100
1535 DBusString signature;
1545 #define N_FENCE_BYTES 5
1546 #define FENCE_BYTES_STR "abcde"
1547 #define INITIAL_PADDING_BYTE '\0'
1550 data_block_init (DataBlock *block,
1554 if (!_dbus_string_init (&block->signature))
1557 if (!_dbus_string_init (&block->body))
1559 _dbus_string_free (&block->signature);
1563 if (!_dbus_string_insert_bytes (&block->signature, 0, initial_offset,
1564 INITIAL_PADDING_BYTE) ||
1565 !_dbus_string_insert_bytes (&block->body, 0, initial_offset,
1566 INITIAL_PADDING_BYTE) ||
1567 !_dbus_string_append (&block->signature, FENCE_BYTES_STR) ||
1568 !_dbus_string_append (&block->body, FENCE_BYTES_STR))
1570 _dbus_string_free (&block->signature);
1571 _dbus_string_free (&block->body);
1575 block->byte_order = byte_order;
1576 block->initial_offset = initial_offset;
1582 data_block_save (DataBlock *block,
1583 DataBlockState *state)
1585 state->saved_sig_len = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES;
1586 state->saved_body_len = _dbus_string_get_length (&block->body) - N_FENCE_BYTES;
1590 data_block_restore (DataBlock *block,
1591 DataBlockState *state)
1593 _dbus_string_delete (&block->signature,
1594 state->saved_sig_len,
1595 _dbus_string_get_length (&block->signature) - state->saved_sig_len - N_FENCE_BYTES);
1596 _dbus_string_delete (&block->body,
1597 state->saved_body_len,
1598 _dbus_string_get_length (&block->body) - state->saved_body_len - N_FENCE_BYTES);
1602 data_block_verify (DataBlock *block)
1604 if (!_dbus_string_ends_with_c_str (&block->signature,
1609 offset = _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - 8;
1613 _dbus_verbose_bytes_of_string (&block->signature,
1615 _dbus_string_get_length (&block->signature) - offset);
1616 _dbus_assert_not_reached ("block did not verify: bad bytes at end of signature");
1618 if (!_dbus_string_ends_with_c_str (&block->body,
1623 offset = _dbus_string_get_length (&block->body) - N_FENCE_BYTES - 8;
1627 _dbus_verbose_bytes_of_string (&block->body,
1629 _dbus_string_get_length (&block->body) - offset);
1630 _dbus_assert_not_reached ("block did not verify: bad bytes at end of body");
1633 _dbus_assert (_dbus_string_validate_nul (&block->signature,
1634 0, block->initial_offset));
1635 _dbus_assert (_dbus_string_validate_nul (&block->body,
1636 0, block->initial_offset));
1640 data_block_free (DataBlock *block)
1642 data_block_verify (block);
1644 _dbus_string_free (&block->signature);
1645 _dbus_string_free (&block->body);
1649 data_block_reset (DataBlock *block)
1651 data_block_verify (block);
1653 _dbus_string_delete (&block->signature,
1654 block->initial_offset,
1655 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES - block->initial_offset);
1656 _dbus_string_delete (&block->body,
1657 block->initial_offset,
1658 _dbus_string_get_length (&block->body) - N_FENCE_BYTES - block->initial_offset);
1660 data_block_verify (block);
1664 data_block_init_reader_writer (DataBlock *block,
1665 DBusTypeReader *reader,
1666 DBusTypeWriter *writer)
1669 _dbus_type_reader_init (reader,
1672 block->initial_offset,
1674 block->initial_offset);
1677 _dbus_type_writer_init (writer,
1680 _dbus_string_get_length (&block->signature) - N_FENCE_BYTES,
1682 _dbus_string_get_length (&block->body) - N_FENCE_BYTES);
1686 real_check_expected_type (DBusTypeReader *reader,
1688 const char *funcname,
1693 t = _dbus_type_reader_get_current_type (reader);
1697 _dbus_warn ("Read type %s while expecting %s at %s line %d\n",
1698 _dbus_type_to_string (t),
1699 _dbus_type_to_string (expected),
1706 #define check_expected_type(reader, expected) real_check_expected_type (reader, expected, _DBUS_FUNCTION_NAME, __LINE__)
1708 #define NEXT_EXPECTING_TRUE(reader) do { if (!_dbus_type_reader_next (reader)) \
1710 _dbus_warn ("_dbus_type_reader_next() should have returned TRUE at %s %d\n", \
1711 _DBUS_FUNCTION_NAME, __LINE__); \
1712 _dbus_assert_not_reached ("test failed"); \
1716 #define NEXT_EXPECTING_FALSE(reader) do { if (_dbus_type_reader_next (reader)) \
1718 _dbus_warn ("_dbus_type_reader_next() should have returned FALSE at %s %d\n", \
1719 _DBUS_FUNCTION_NAME, __LINE__); \
1720 _dbus_assert_not_reached ("test failed"); \
1722 check_expected_type (reader, DBUS_TYPE_INVALID); \
1725 typedef struct TestTypeNode TestTypeNode;
1726 typedef struct TestTypeNodeClass TestTypeNodeClass;
1727 typedef struct TestTypeNodeContainer TestTypeNodeContainer;
1728 typedef struct TestTypeNodeContainerClass TestTypeNodeContainerClass;
1732 const TestTypeNodeClass *klass;
1735 struct TestTypeNodeContainer
1741 struct TestTypeNodeClass
1747 int subclass_detail; /* a bad hack to avoid a bunch of subclass casting */
1749 dbus_bool_t (* construct) (TestTypeNode *node);
1750 void (* destroy) (TestTypeNode *node);
1752 dbus_bool_t (* write_value) (TestTypeNode *node,
1754 DBusTypeWriter *writer,
1756 dbus_bool_t (* read_value) (TestTypeNode *node,
1758 DBusTypeReader *reader,
1760 dbus_bool_t (* build_signature) (TestTypeNode *node,
1764 struct TestTypeNodeContainerClass
1766 TestTypeNodeClass base;
1769 static dbus_bool_t int32_write_value (TestTypeNode *node,
1771 DBusTypeWriter *writer,
1773 static dbus_bool_t int32_read_value (TestTypeNode *node,
1775 DBusTypeReader *reader,
1777 static dbus_bool_t int64_write_value (TestTypeNode *node,
1779 DBusTypeWriter *writer,
1781 static dbus_bool_t int64_read_value (TestTypeNode *node,
1783 DBusTypeReader *reader,
1785 static dbus_bool_t string_write_value (TestTypeNode *node,
1787 DBusTypeWriter *writer,
1789 static dbus_bool_t string_read_value (TestTypeNode *node,
1791 DBusTypeReader *reader,
1793 static dbus_bool_t bool_read_value (TestTypeNode *node,
1795 DBusTypeReader *reader,
1797 static dbus_bool_t bool_write_value (TestTypeNode *node,
1799 DBusTypeWriter *writer,
1801 static dbus_bool_t byte_read_value (TestTypeNode *node,
1803 DBusTypeReader *reader,
1805 static dbus_bool_t byte_write_value (TestTypeNode *node,
1807 DBusTypeWriter *writer,
1809 static dbus_bool_t double_read_value (TestTypeNode *node,
1811 DBusTypeReader *reader,
1813 static dbus_bool_t double_write_value (TestTypeNode *node,
1815 DBusTypeWriter *writer,
1817 static dbus_bool_t object_path_read_value (TestTypeNode *node,
1819 DBusTypeReader *reader,
1821 static dbus_bool_t object_path_write_value (TestTypeNode *node,
1823 DBusTypeWriter *writer,
1825 static dbus_bool_t signature_read_value (TestTypeNode *node,
1827 DBusTypeReader *reader,
1829 static dbus_bool_t signature_write_value (TestTypeNode *node,
1831 DBusTypeWriter *writer,
1833 static dbus_bool_t struct_write_value (TestTypeNode *node,
1835 DBusTypeWriter *writer,
1837 static dbus_bool_t struct_read_value (TestTypeNode *node,
1839 DBusTypeReader *reader,
1841 static dbus_bool_t struct_build_signature (TestTypeNode *node,
1843 static dbus_bool_t array_write_value (TestTypeNode *node,
1845 DBusTypeWriter *writer,
1847 static dbus_bool_t array_read_value (TestTypeNode *node,
1849 DBusTypeReader *reader,
1851 static dbus_bool_t array_build_signature (TestTypeNode *node,
1853 static dbus_bool_t variant_write_value (TestTypeNode *node,
1855 DBusTypeWriter *writer,
1857 static dbus_bool_t variant_read_value (TestTypeNode *node,
1859 DBusTypeReader *reader,
1861 static void container_destroy (TestTypeNode *node);
1864 static const TestTypeNodeClass int32_class = {
1866 sizeof (TestTypeNode),
1875 static const TestTypeNodeClass uint32_class = {
1877 sizeof (TestTypeNode),
1881 int32_write_value, /* recycle from int32 */
1882 int32_read_value, /* recycle from int32 */
1886 static const TestTypeNodeClass int64_class = {
1888 sizeof (TestTypeNode),
1897 static const TestTypeNodeClass uint64_class = {
1899 sizeof (TestTypeNode),
1903 int64_write_value, /* recycle from int64 */
1904 int64_read_value, /* recycle from int64 */
1908 static const TestTypeNodeClass string_0_class = {
1910 sizeof (TestTypeNode),
1911 0, /* string length */
1919 static const TestTypeNodeClass string_1_class = {
1921 sizeof (TestTypeNode),
1922 1, /* string length */
1930 /* with nul, a len 3 string should fill 4 bytes and thus is "special" */
1931 static const TestTypeNodeClass string_3_class = {
1933 sizeof (TestTypeNode),
1934 3, /* string length */
1942 /* with nul, a len 8 string should fill 9 bytes and thus is "special" (far-fetched I suppose) */
1943 static const TestTypeNodeClass string_8_class = {
1945 sizeof (TestTypeNode),
1946 8, /* string length */
1954 static const TestTypeNodeClass bool_class = {
1956 sizeof (TestTypeNode),
1965 static const TestTypeNodeClass byte_class = {
1967 sizeof (TestTypeNode),
1976 static const TestTypeNodeClass double_class = {
1978 sizeof (TestTypeNode),
1987 static const TestTypeNodeClass object_path_class = {
1988 DBUS_TYPE_OBJECT_PATH,
1989 sizeof (TestTypeNode),
1993 object_path_write_value,
1994 object_path_read_value,
1998 static const TestTypeNodeClass signature_class = {
1999 DBUS_TYPE_SIGNATURE,
2000 sizeof (TestTypeNode),
2004 signature_write_value,
2005 signature_read_value,
2009 static const TestTypeNodeClass struct_1_class = {
2011 sizeof (TestTypeNodeContainer),
2012 1, /* number of times children appear as fields */
2017 struct_build_signature
2020 static const TestTypeNodeClass struct_2_class = {
2022 sizeof (TestTypeNodeContainer),
2023 2, /* number of times children appear as fields */
2028 struct_build_signature
2031 static const TestTypeNodeClass array_0_class = {
2033 sizeof (TestTypeNodeContainer),
2034 0, /* number of array elements */
2039 array_build_signature
2042 static const TestTypeNodeClass array_1_class = {
2044 sizeof (TestTypeNodeContainer),
2045 1, /* number of array elements */
2050 array_build_signature
2053 static const TestTypeNodeClass array_2_class = {
2055 sizeof (TestTypeNodeContainer),
2056 2, /* number of array elements */
2061 array_build_signature
2064 static const TestTypeNodeClass array_9_class = {
2066 sizeof (TestTypeNodeContainer),
2067 9, /* number of array elements */
2072 array_build_signature
2075 static const TestTypeNodeClass variant_class = {
2077 sizeof (TestTypeNodeContainer),
2081 variant_write_value,
2086 static const TestTypeNodeClass* const
2102 #define N_BASICS (_DBUS_N_ELEMENTS (basic_nodes))
2104 static const TestTypeNodeClass* const
2105 container_nodes[] = {
2112 /* array_9_class is omitted on purpose, it's too slow;
2113 * we only use it in one hardcoded test below
2116 #define N_CONTAINERS (_DBUS_N_ELEMENTS (container_nodes))
2118 static TestTypeNode*
2119 node_new (const TestTypeNodeClass *klass)
2123 node = dbus_malloc0 (klass->instance_size);
2127 node->klass = klass;
2129 if (klass->construct)
2131 if (!(* klass->construct) (node))
2142 node_destroy (TestTypeNode *node)
2144 if (node->klass->destroy)
2145 (* node->klass->destroy) (node);
2150 node_write_value (TestTypeNode *node,
2152 DBusTypeWriter *writer,
2157 retval = (* node->klass->write_value) (node, block, writer, seed);
2160 /* Handy to see where things break, but too expensive to do all the time */
2161 data_block_verify (block);
2168 node_read_value (TestTypeNode *node,
2170 DBusTypeReader *reader,
2174 DBusTypeReader restored;
2176 _dbus_type_reader_save_mark (reader, &mark);
2178 if (!(* node->klass->read_value) (node, block, reader, seed))
2181 _dbus_type_reader_init_from_mark (&restored,
2182 reader->byte_order, /* a bit of a cheat,
2183 * since we didn't bother
2184 * to store this in DataBlock
2190 if (!(* node->klass->read_value) (node, block, &restored, seed))
2197 node_build_signature (TestTypeNode *node,
2200 if (node->klass->build_signature)
2201 return (* node->klass->build_signature) (node, str);
2203 return _dbus_string_append_byte (str, node->klass->typecode);
2207 node_append_child (TestTypeNode *node,
2208 TestTypeNode *child)
2210 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2212 _dbus_assert (node->klass->instance_size >= (int) sizeof (TestTypeNodeContainer));
2214 if (!_dbus_list_append (&container->children, child))
2215 _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 */
2221 run_test_copy (DataBlock *src)
2225 DBusTypeReader reader;
2226 DBusTypeWriter writer;
2230 if (!data_block_init (&dest, src->byte_order, src->initial_offset))
2233 data_block_init_reader_writer (src, &reader, NULL);
2234 data_block_init_reader_writer (&dest, NULL, &writer);
2236 /* DBusTypeWriter assumes it's writing into an existing signature,
2237 * so doesn't add nul on its own. We have to do that.
2239 if (!_dbus_string_insert_byte (&dest.signature,
2240 dest.initial_offset, '\0'))
2243 if (!_dbus_type_writer_write_reader (&writer, &reader))
2246 /* Data blocks should now be identical */
2247 if (!_dbus_string_equal (&src->signature, &dest.signature))
2249 _dbus_verbose ("SOURCE\n");
2250 _dbus_verbose_bytes_of_string (&src->signature, 0,
2251 _dbus_string_get_length (&src->signature));
2252 _dbus_verbose ("DEST\n");
2253 _dbus_verbose_bytes_of_string (&dest.signature, 0,
2254 _dbus_string_get_length (&dest.signature));
2255 _dbus_assert_not_reached ("signatures did not match");
2258 if (!_dbus_string_equal (&src->body, &dest.body))
2260 _dbus_verbose ("SOURCE\n");
2261 _dbus_verbose_bytes_of_string (&src->body, 0,
2262 _dbus_string_get_length (&src->body));
2263 _dbus_verbose ("DEST\n");
2264 _dbus_verbose_bytes_of_string (&dest.body, 0,
2265 _dbus_string_get_length (&dest.body));
2266 _dbus_assert_not_reached ("bodies did not match");
2273 data_block_free (&dest);
2278 static int n_iterations_completed_total = 0;
2279 static int n_iterations_completed_this_test = 0;
2280 static int n_iterations_expected_this_test = 0;
2284 const DBusString *signature;
2287 TestTypeNode **nodes;
2289 } NodeIterationData;
2292 run_test_nodes_iteration (void *data)
2294 NodeIterationData *nid = data;
2295 DBusTypeReader reader;
2296 DBusTypeWriter writer;
2301 * 1. write the value
2302 * 2. strcmp-compare with the signature we built
2304 * 4. type-iterate the signature and the value and see if they are the same type-wise
2308 data_block_init_reader_writer (nid->block,
2311 /* DBusTypeWriter assumes it's writing into an existing signature,
2312 * so doesn't add nul on its own. We have to do that.
2314 if (!_dbus_string_insert_byte (&nid->block->signature,
2315 nid->type_offset, '\0'))
2319 while (i < nid->n_nodes)
2321 if (!node_write_value (nid->nodes[i], nid->block, &writer, i))
2327 if (!_dbus_string_equal_substring (nid->signature, 0, _dbus_string_get_length (nid->signature),
2328 &nid->block->signature, nid->type_offset))
2330 _dbus_warn ("Expected signature '%s' and got '%s' with initial offset %d\n",
2331 _dbus_string_get_const_data (nid->signature),
2332 _dbus_string_get_const_data_len (&nid->block->signature, nid->type_offset, 0),
2334 _dbus_assert_not_reached ("wrong signature");
2338 while (i < nid->n_nodes)
2340 if (!node_read_value (nid->nodes[i], nid->block, &reader, i))
2343 if (i + 1 == nid->n_nodes)
2344 NEXT_EXPECTING_FALSE (&reader);
2346 NEXT_EXPECTING_TRUE (&reader);
2351 if (n_iterations_expected_this_test <= MAX_ITERATIONS_TO_TEST_COPYING)
2352 run_test_copy (nid->block);
2354 /* FIXME type-iterate both signature and value and compare the resulting
2355 * tree to the node tree perhaps
2362 data_block_reset (nid->block);
2368 run_test_nodes_in_one_configuration (TestTypeNode **nodes,
2370 const DBusString *signature,
2375 NodeIterationData nid;
2377 if (!data_block_init (&block, byte_order, initial_offset))
2378 _dbus_assert_not_reached ("no memory");
2380 nid.signature = signature;
2382 nid.type_offset = initial_offset;
2384 nid.n_nodes = n_nodes;
2386 #if TEST_OOM_HANDLING
2387 _dbus_test_oom_handling ("running test node",
2388 run_test_nodes_iteration,
2391 if (!run_test_nodes_iteration (&nid))
2392 _dbus_assert_not_reached ("no memory");
2395 data_block_free (&block);
2399 run_test_nodes (TestTypeNode **nodes,
2403 DBusString signature;
2405 if (!_dbus_string_init (&signature))
2406 _dbus_assert_not_reached ("no memory");
2411 if (! node_build_signature (nodes[i], &signature))
2412 _dbus_assert_not_reached ("no memory");
2417 _dbus_verbose (">>> test nodes with signature '%s'\n",
2418 _dbus_string_get_const_data (&signature));
2421 while (i <= MAX_INITIAL_OFFSET)
2423 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2424 DBUS_LITTLE_ENDIAN, i);
2425 run_test_nodes_in_one_configuration (nodes, n_nodes, &signature,
2426 DBUS_BIG_ENDIAN, i);
2431 n_iterations_completed_this_test += 1;
2432 n_iterations_completed_total += 1;
2434 if (n_iterations_completed_this_test == n_iterations_expected_this_test)
2436 fprintf (stderr, " 100%% %d this test (%d cumulative)\n",
2437 n_iterations_completed_this_test,
2438 n_iterations_completed_total);
2440 /* this happens to turn out well with mod == 1 */
2441 else if ((n_iterations_completed_this_test %
2442 (int)(n_iterations_expected_this_test / 10.0)) == 1)
2444 fprintf (stderr, " %d%% ", (int) (n_iterations_completed_this_test / (double) n_iterations_expected_this_test * 100));
2447 _dbus_string_free (&signature);
2450 #define N_VALUES (N_BASICS * N_CONTAINERS + N_BASICS)
2452 static TestTypeNode*
2453 value_generator (int *ip)
2456 const TestTypeNodeClass *child_klass;
2457 const TestTypeNodeClass *container_klass;
2458 TestTypeNode *child;
2461 _dbus_assert (i <= N_VALUES);
2467 else if (i < N_BASICS)
2469 node = node_new (basic_nodes[i]);
2473 /* imagine an array:
2474 * container 0 of basic 0
2475 * container 0 of basic 1
2476 * container 0 of basic 2
2477 * container 1 of basic 0
2478 * container 1 of basic 1
2479 * container 1 of basic 2
2483 container_klass = container_nodes[i / N_BASICS];
2484 child_klass = basic_nodes[i % N_BASICS];
2486 node = node_new (container_klass);
2487 child = node_new (child_klass);
2489 node_append_child (node, child);
2492 *ip += 1; /* increment the generator */
2498 make_and_run_values_inside_container (const TestTypeNodeClass *container_klass,
2502 TestTypeNode *container;
2503 TestTypeNode *child;
2506 root = node_new (container_klass);
2508 for (i = 1; i < n_nested; i++)
2510 child = node_new (container_klass);
2511 node_append_child (container, child);
2515 /* container should now be the most-nested container */
2518 while ((child = value_generator (&i)))
2520 node_append_child (container, child);
2522 run_test_nodes (&root, 1);
2524 _dbus_list_clear (&((TestTypeNodeContainer*)container)->children);
2525 node_destroy (child);
2528 node_destroy (root);
2532 start_next_test (const char *format,
2535 n_iterations_completed_this_test = 0;
2536 n_iterations_expected_this_test = expected;
2538 fprintf (stderr, ">>> >>> ");
2539 fprintf (stderr, format,
2540 n_iterations_expected_this_test);
2544 make_and_run_test_nodes (void)
2548 /* We try to do this in order of "complicatedness" so that test
2549 * failures tend to show up in the simplest test case that
2550 * demonstrates the failure. There are also some tests that run
2551 * more than once for this reason, first while going through simple
2552 * cases, second while going through a broader range of complex
2555 /* Each basic node. The basic nodes should include:
2557 * - each fixed-size type (in such a way that it has different values each time,
2558 * so we can tell if we mix two of them up)
2559 * - strings of various lengths
2563 /* Each container node. The container nodes should include:
2565 * struct with 1 and 2 copies of the contained item
2566 * array with 0, 1, 2 copies of the contained item
2569 /* Let a "value" be a basic node, or a container containing a single basic node.
2570 * Let n_values be the number of such values i.e. (n_container * n_basic + n_basic)
2571 * When iterating through all values to make combinations, do the basic types
2572 * first and the containers second.
2574 /* Each item is shown with its number of iterations to complete so
2575 * we can keep a handle on this unit test
2578 /* FIXME test just an empty body, no types at all */
2580 start_next_test ("Each value by itself %d iterations\n", N_VALUES);
2584 while ((node = value_generator (&i)))
2586 run_test_nodes (&node, 1);
2588 node_destroy (node);
2592 start_next_test ("All values in one big toplevel %d iteration\n", 1);
2594 TestTypeNode *nodes[N_VALUES];
2597 while ((nodes[i] = value_generator (&i)))
2600 run_test_nodes (nodes, N_VALUES);
2602 for (i = 0; i < N_VALUES; i++)
2603 node_destroy (nodes[i]);
2606 start_next_test ("Each value,value pair combination as toplevel, in both orders %d iterations\n",
2607 N_VALUES * N_VALUES);
2609 TestTypeNode *nodes[2];
2612 while ((nodes[0] = value_generator (&i)))
2615 while ((nodes[1] = value_generator (&j)))
2617 run_test_nodes (nodes, 2);
2619 node_destroy (nodes[1]);
2622 node_destroy (nodes[0]);
2626 start_next_test ("Each container containing each value %d iterations\n",
2627 N_CONTAINERS * N_VALUES);
2628 for (i = 0; i < N_CONTAINERS; i++)
2630 const TestTypeNodeClass *container_klass = container_nodes[i];
2632 make_and_run_values_inside_container (container_klass, 1);
2635 n_iterations_completed_this_test = 0;
2636 n_iterations_expected_this_test = N_CONTAINERS * N_VALUES;
2637 _dbus_verbose (">>> >>> Each container of same container of each value %d iterations\n",
2638 n_iterations_completed_this_test);
2639 for (i = 0; i < N_CONTAINERS; i++)
2641 const TestTypeNodeClass *container_klass = container_nodes[i];
2643 make_and_run_values_inside_container (container_klass, 2);
2646 start_next_test ("Each container of same container of same container of each value %d iterations\n",
2647 N_CONTAINERS * N_VALUES);
2648 for (i = 0; i < N_CONTAINERS; i++)
2650 const TestTypeNodeClass *container_klass = container_nodes[i];
2652 make_and_run_values_inside_container (container_klass, 3);
2655 start_next_test ("Each value,value pair inside a struct %d iterations\n",
2656 N_VALUES * N_VALUES);
2658 TestTypeNode *val1, *val2;
2661 node = node_new (&struct_1_class);
2664 while ((val1 = value_generator (&i)))
2667 while ((val2 = value_generator (&j)))
2669 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2671 node_append_child (node, val1);
2672 node_append_child (node, val2);
2674 run_test_nodes (&node, 1);
2676 _dbus_list_clear (&container->children);
2677 node_destroy (val2);
2679 node_destroy (val1);
2681 node_destroy (node);
2684 start_next_test ("All values in one big struct %d iteration\n",
2688 TestTypeNode *child;
2690 node = node_new (&struct_1_class);
2693 while ((child = value_generator (&i)))
2694 node_append_child (node, child);
2696 run_test_nodes (&node, 1);
2698 node_destroy (node);
2701 start_next_test ("Each value in a large array %d iterations\n",
2707 node = node_new (&array_9_class);
2710 while ((val = value_generator (&i)))
2712 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
2714 node_append_child (node, val);
2716 run_test_nodes (&node, 1);
2718 _dbus_list_clear (&container->children);
2722 node_destroy (node);
2725 start_next_test ("Each container of each container of each value %d iterations\n",
2726 N_CONTAINERS * N_CONTAINERS * N_VALUES);
2727 for (i = 0; i < N_CONTAINERS; i++)
2729 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2730 TestTypeNode *outer_container = node_new (outer_container_klass);
2732 for (j = 0; j < N_CONTAINERS; j++)
2734 TestTypeNode *child;
2735 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2736 TestTypeNode *inner_container = node_new (inner_container_klass);
2738 node_append_child (outer_container, inner_container);
2741 while ((child = value_generator (&m)))
2743 node_append_child (inner_container, child);
2745 run_test_nodes (&outer_container, 1);
2747 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2748 node_destroy (child);
2750 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2751 node_destroy (inner_container);
2753 node_destroy (outer_container);
2756 start_next_test ("Each container of each container of each container of each value %d iterations\n",
2757 N_CONTAINERS * N_CONTAINERS * N_CONTAINERS * N_VALUES);
2758 for (i = 0; i < N_CONTAINERS; i++)
2760 const TestTypeNodeClass *outer_container_klass = container_nodes[i];
2761 TestTypeNode *outer_container = node_new (outer_container_klass);
2763 for (j = 0; j < N_CONTAINERS; j++)
2765 const TestTypeNodeClass *inner_container_klass = container_nodes[j];
2766 TestTypeNode *inner_container = node_new (inner_container_klass);
2768 node_append_child (outer_container, inner_container);
2770 for (k = 0; k < N_CONTAINERS; k++)
2772 TestTypeNode *child;
2773 const TestTypeNodeClass *center_container_klass = container_nodes[k];
2774 TestTypeNode *center_container = node_new (center_container_klass);
2776 node_append_child (inner_container, center_container);
2779 while ((child = value_generator (&m)))
2781 node_append_child (center_container, child);
2783 run_test_nodes (&outer_container, 1);
2785 _dbus_list_clear (&((TestTypeNodeContainer*)center_container)->children);
2786 node_destroy (child);
2788 _dbus_list_clear (&((TestTypeNodeContainer*)inner_container)->children);
2789 node_destroy (center_container);
2791 _dbus_list_clear (&((TestTypeNodeContainer*)outer_container)->children);
2792 node_destroy (inner_container);
2794 node_destroy (outer_container);
2798 /* This one takes a really long time, so comment it out for now */
2799 start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
2800 N_VALUES * N_VALUES * N_VALUES);
2802 TestTypeNode *nodes[3];
2805 while ((nodes[0] = value_generator (&i)))
2808 while ((nodes[1] = value_generator (&j)))
2811 while ((nodes[2] = value_generator (&k)))
2813 run_test_nodes (nodes, 3);
2815 node_destroy (nodes[2]);
2817 node_destroy (nodes[1]);
2819 node_destroy (nodes[0]);
2822 #endif /* #if 0 expensive test */
2824 fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
2825 n_iterations_completed_total);
2826 fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
2827 MAX_INITIAL_OFFSET);
2828 fprintf (stderr, "out of memory handling %s tested\n",
2829 TEST_OOM_HANDLING ? "was" : "was not");
2832 dbus_bool_t _dbus_marshal_recursive_test (void);
2835 _dbus_marshal_recursive_test (void)
2837 make_and_run_test_nodes ();
2843 dbus_bool_t _dbus_marshal_test (void);
2845 main (int argc, char **argv)
2847 _dbus_marshal_test ();
2849 _dbus_marshal_recursive_test ();
2859 * Implementations of each type node class
2866 #define SAMPLE_INT32 12345678
2867 #define SAMPLE_INT32_ALTERNATE 53781429
2869 int32_from_seed (int seed)
2871 /* Generate an integer value that's predictable from seed. We could
2872 * just use seed itself, but that would only ever touch one byte of
2873 * the int so would miss some kinds of bug.
2877 v = 42; /* just to quiet compiler afaik */
2884 v = SAMPLE_INT32_ALTERNATE;
2898 v *= seed; /* wraps around eventually, which is fine */
2904 int32_write_value (TestTypeNode *node,
2906 DBusTypeWriter *writer,
2909 /* also used for uint32 */
2912 v = int32_from_seed (seed);
2914 return _dbus_type_writer_write_basic (writer,
2915 node->klass->typecode,
2920 int32_read_value (TestTypeNode *node,
2922 DBusTypeReader *reader,
2925 /* also used for uint32 */
2928 check_expected_type (reader, node->klass->typecode);
2930 _dbus_type_reader_read_basic (reader,
2931 (dbus_int32_t*) &v);
2933 _dbus_assert (v == int32_from_seed (seed));
2938 #ifdef DBUS_HAVE_INT64
2940 int64_from_seed (int seed)
2945 v32 = int32_from_seed (seed);
2947 v = - (dbus_int32_t) ~ v32;
2948 v |= (((dbus_int64_t)v32) << 32);
2955 int64_write_value (TestTypeNode *node,
2957 DBusTypeWriter *writer,
2960 #ifdef DBUS_HAVE_INT64
2961 /* also used for uint64 */
2964 v = int64_from_seed (seed);
2966 return _dbus_type_writer_write_basic (writer,
2967 node->klass->typecode,
2975 int64_read_value (TestTypeNode *node,
2977 DBusTypeReader *reader,
2980 #ifdef DBUS_HAVE_INT64
2981 /* also used for uint64 */
2984 check_expected_type (reader, node->klass->typecode);
2986 _dbus_type_reader_read_basic (reader,
2987 (dbus_int64_t*) &v);
2989 _dbus_assert (v == int64_from_seed (seed));
2997 #define MAX_SAMPLE_STRING_LEN 10
2999 string_from_seed (char *buf,
3006 _dbus_assert (len < MAX_SAMPLE_STRING_LEN);
3008 v = (unsigned char) ('A' + seed);
3013 if (v < 'A' || v > 'z')
3026 string_write_value (TestTypeNode *node,
3028 DBusTypeWriter *writer,
3031 char buf[MAX_SAMPLE_STRING_LEN];
3032 const char *v_string = buf;
3034 string_from_seed (buf, node->klass->subclass_detail,
3037 return _dbus_type_writer_write_basic (writer,
3038 node->klass->typecode,
3043 string_read_value (TestTypeNode *node,
3045 DBusTypeReader *reader,
3049 char buf[MAX_SAMPLE_STRING_LEN];
3051 check_expected_type (reader, node->klass->typecode);
3053 _dbus_type_reader_read_basic (reader,
3054 (const char **) &v);
3056 string_from_seed (buf, node->klass->subclass_detail,
3059 if (strcmp (buf, v) != 0)
3061 _dbus_warn ("read string '%s' expected '%s'\n",
3063 _dbus_assert_not_reached ("test failed");
3069 #define BOOL_FROM_SEED(seed) (seed % 2)
3072 bool_write_value (TestTypeNode *node,
3074 DBusTypeWriter *writer,
3079 v = BOOL_FROM_SEED (seed);
3081 return _dbus_type_writer_write_basic (writer,
3082 node->klass->typecode,
3087 bool_read_value (TestTypeNode *node,
3089 DBusTypeReader *reader,
3094 check_expected_type (reader, node->klass->typecode);
3096 _dbus_type_reader_read_basic (reader,
3097 (unsigned char*) &v);
3099 _dbus_assert (v == BOOL_FROM_SEED (seed));
3104 #define BYTE_FROM_SEED(seed) ((unsigned char) int32_from_seed (seed))
3107 byte_write_value (TestTypeNode *node,
3109 DBusTypeWriter *writer,
3114 v = BYTE_FROM_SEED (seed);
3116 return _dbus_type_writer_write_basic (writer,
3117 node->klass->typecode,
3122 byte_read_value (TestTypeNode *node,
3124 DBusTypeReader *reader,
3129 check_expected_type (reader, node->klass->typecode);
3131 _dbus_type_reader_read_basic (reader,
3132 (unsigned char*) &v);
3134 _dbus_assert (v == BYTE_FROM_SEED (seed));
3140 double_from_seed (int seed)
3142 return SAMPLE_INT32 * (double) seed + 0.3;
3146 double_write_value (TestTypeNode *node,
3148 DBusTypeWriter *writer,
3153 v = double_from_seed (seed);
3155 return _dbus_type_writer_write_basic (writer,
3156 node->klass->typecode,
3161 double_read_value (TestTypeNode *node,
3163 DBusTypeReader *reader,
3169 check_expected_type (reader, node->klass->typecode);
3171 _dbus_type_reader_read_basic (reader,
3174 expected = double_from_seed (seed);
3176 if (!_DBUS_DOUBLES_BITWISE_EQUAL (v, expected))
3178 #ifdef DBUS_HAVE_INT64
3179 _dbus_warn ("Expected double %g got %g\n bits = 0x%llx vs.\n bits = 0x%llx)\n",
3181 *(dbus_uint64_t*)&expected,
3182 *(dbus_uint64_t*)&v);
3184 _dbus_assert_not_reached ("test failed");
3191 #define MAX_SAMPLE_OBJECT_PATH_LEN 10
3193 object_path_from_seed (char *buf,
3199 v = (unsigned char) ('A' + seed);
3204 if (v < 'A' || v > 'z')
3219 object_path_write_value (TestTypeNode *node,
3221 DBusTypeWriter *writer,
3224 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3225 const char *v_string = buf;
3227 object_path_from_seed (buf, seed);
3229 return _dbus_type_writer_write_basic (writer,
3230 node->klass->typecode,
3235 object_path_read_value (TestTypeNode *node,
3237 DBusTypeReader *reader,
3241 char buf[MAX_SAMPLE_OBJECT_PATH_LEN];
3243 check_expected_type (reader, node->klass->typecode);
3245 _dbus_type_reader_read_basic (reader,
3246 (const char **) &v);
3248 object_path_from_seed (buf, seed);
3250 if (strcmp (buf, v) != 0)
3252 _dbus_warn ("read object path '%s' expected '%s'\n",
3254 _dbus_assert_not_reached ("test failed");
3261 #define MAX_SAMPLE_SIGNATURE_LEN 10
3263 signature_from_seed (char *buf,
3268 const char *sample_signatures[] = {
3276 s = sample_signatures[seed % _DBUS_N_ELEMENTS(sample_signatures)];
3278 for (i = 0; s[i]; i++)
3286 signature_write_value (TestTypeNode *node,
3288 DBusTypeWriter *writer,
3291 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3292 const char *v_string = buf;
3294 signature_from_seed (buf, seed);
3296 return _dbus_type_writer_write_basic (writer,
3297 node->klass->typecode,
3302 signature_read_value (TestTypeNode *node,
3304 DBusTypeReader *reader,
3308 char buf[MAX_SAMPLE_SIGNATURE_LEN];
3310 check_expected_type (reader, node->klass->typecode);
3312 _dbus_type_reader_read_basic (reader,
3313 (const char **) &v);
3315 signature_from_seed (buf, seed);
3317 if (strcmp (buf, v) != 0)
3319 _dbus_warn ("read signature value '%s' expected '%s'\n",
3321 _dbus_assert_not_reached ("test failed");
3328 struct_write_value (TestTypeNode *node,
3330 DBusTypeWriter *writer,
3333 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3334 DataBlockState saved;
3339 n_copies = node->klass->subclass_detail;
3341 _dbus_assert (container->children != NULL);
3343 data_block_save (block, &saved);
3345 if (!_dbus_type_writer_recurse_struct (writer,
3350 while (i < n_copies)
3354 link = _dbus_list_get_first_link (&container->children);
3355 while (link != NULL)
3357 TestTypeNode *child = link->data;
3358 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3360 if (!node_write_value (child, block, &sub, i))
3362 data_block_restore (block, &saved);
3372 if (!_dbus_type_writer_unrecurse (writer, &sub))
3374 data_block_restore (block, &saved);
3382 struct_read_value (TestTypeNode *node,
3384 DBusTypeReader *reader,
3387 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3392 n_copies = node->klass->subclass_detail;
3394 check_expected_type (reader, DBUS_TYPE_STRUCT);
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);
3427 struct_build_signature (TestTypeNode *node,
3430 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3435 n_copies = node->klass->subclass_detail;
3437 orig_len = _dbus_string_get_length (str);
3439 if (!_dbus_string_append_byte (str, DBUS_STRUCT_BEGIN_CHAR))
3443 while (i < n_copies)
3447 link = _dbus_list_get_first_link (&container->children);
3448 while (link != NULL)
3450 TestTypeNode *child = link->data;
3451 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3453 if (!node_build_signature (child, str))
3462 if (!_dbus_string_append_byte (str, DBUS_STRUCT_END_CHAR))
3468 _dbus_string_set_length (str, orig_len);
3473 array_write_value (TestTypeNode *node,
3475 DBusTypeWriter *writer,
3478 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3479 DataBlockState saved;
3481 DBusString element_signature;
3485 n_copies = node->klass->subclass_detail;
3487 _dbus_assert (container->children != NULL);
3489 data_block_save (block, &saved);
3491 if (!_dbus_string_init (&element_signature))
3494 if (!node_build_signature (_dbus_list_get_first (&container->children),
3495 &element_signature))
3498 if (!_dbus_type_writer_recurse_array (writer,
3499 _dbus_string_get_const_data (&element_signature),
3504 while (i < n_copies)
3508 link = _dbus_list_get_first_link (&container->children);
3509 while (link != NULL)
3511 TestTypeNode *child = link->data;
3512 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3514 if (!node_write_value (child, block, &sub, i))
3523 if (!_dbus_type_writer_unrecurse (writer, &sub))
3526 _dbus_string_free (&element_signature);
3530 data_block_restore (block, &saved);
3531 _dbus_string_free (&element_signature);
3536 array_read_value (TestTypeNode *node,
3538 DBusTypeReader *reader,
3541 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3546 n_copies = node->klass->subclass_detail;
3548 check_expected_type (reader, DBUS_TYPE_ARRAY);
3552 _dbus_assert (!_dbus_type_reader_array_is_empty (reader));
3554 _dbus_type_reader_recurse (reader, &sub);
3557 while (i < n_copies)
3561 link = _dbus_list_get_first_link (&container->children);
3562 while (link != NULL)
3564 TestTypeNode *child = link->data;
3565 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3567 if (!node_read_value (child, block, &sub, i))
3570 if (i == (n_copies - 1) && next == NULL)
3571 NEXT_EXPECTING_FALSE (&sub);
3573 NEXT_EXPECTING_TRUE (&sub);
3583 _dbus_assert (_dbus_type_reader_array_is_empty (reader));
3590 array_build_signature (TestTypeNode *node,
3593 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3596 orig_len = _dbus_string_get_length (str);
3598 if (!_dbus_string_append_byte (str, DBUS_TYPE_ARRAY))
3601 if (!node_build_signature (_dbus_list_get_first (&container->children),
3608 _dbus_string_set_length (str, orig_len);
3612 /* 10 is random just to add another seed that we use in the suite */
3613 #define VARIANT_SEED 10
3616 variant_write_value (TestTypeNode *node,
3618 DBusTypeWriter *writer,
3621 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3622 DataBlockState saved;
3624 DBusString content_signature;
3625 TestTypeNode *child;
3627 _dbus_assert (container->children != NULL);
3628 _dbus_assert (_dbus_list_length_is_one (&container->children));
3630 child = _dbus_list_get_first (&container->children);
3632 data_block_save (block, &saved);
3634 if (!_dbus_string_init (&content_signature))
3637 if (!node_build_signature (child,
3638 &content_signature))
3641 if (!_dbus_type_writer_recurse_variant (writer,
3642 _dbus_string_get_const_data (&content_signature),
3646 if (!node_write_value (child, block, &sub, VARIANT_SEED))
3649 if (!_dbus_type_writer_unrecurse (writer, &sub))
3652 _dbus_string_free (&content_signature);
3656 data_block_restore (block, &saved);
3657 _dbus_string_free (&content_signature);
3662 variant_read_value (TestTypeNode *node,
3664 DBusTypeReader *reader,
3667 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3669 TestTypeNode *child;
3671 _dbus_assert (container->children != NULL);
3672 _dbus_assert (_dbus_list_length_is_one (&container->children));
3674 child = _dbus_list_get_first (&container->children);
3676 check_expected_type (reader, DBUS_TYPE_VARIANT);
3678 _dbus_type_reader_recurse (reader, &sub);
3680 if (!node_read_value (child, block, &sub, VARIANT_SEED))
3683 NEXT_EXPECTING_FALSE (&sub);
3689 container_destroy (TestTypeNode *node)
3691 TestTypeNodeContainer *container = (TestTypeNodeContainer*) node;
3694 link = _dbus_list_get_first_link (&container->children);
3695 while (link != NULL)
3697 TestTypeNode *child = link->data;
3698 DBusList *next = _dbus_list_get_next_link (&container->children, link);
3700 node_destroy (child);
3702 _dbus_list_free_link (link);
3708 #endif /* DBUS_BUILD_TESTS */