1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-marshal-recursive.c Marshalling routines for recursive types
4 * Copyright (C) 2004 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-marshal-recursive.h"
25 #include "dbus-internals.h"
28 * @addtogroup DBusMarshal
33 first_type_in_signature (const DBusString *str,
38 t = _dbus_string_get_byte (str, pos);
40 if (t == DBUS_STRUCT_BEGIN_CHAR)
41 return DBUS_TYPE_STRUCT;
47 element_type_get_alignment (const DBusString *str,
50 return _dbus_type_get_alignment (first_type_in_signature (str, pos));
54 _dbus_type_reader_init (DBusTypeReader *reader,
56 const DBusString *type_str,
58 const DBusString *value_str,
61 reader->byte_order = byte_order;
62 reader->type_str = type_str;
63 reader->type_pos = type_pos;
64 reader->value_str = value_str;
65 reader->value_pos = value_pos;
66 reader->container_type = DBUS_TYPE_INVALID;
68 _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
69 reader, reader->type_pos, reader->value_pos,
70 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
74 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
78 /* for INVALID t will == DBUS_TYPE_INVALID when we
79 * reach the end of type_str, for STRUCT we have to
80 * check the finished flag
82 if (reader->container_type == DBUS_TYPE_INVALID)
84 t = first_type_in_signature (reader->type_str,
87 else if (reader->container_type == DBUS_TYPE_STRUCT)
89 if (reader->u.strct.finished)
90 t = DBUS_TYPE_INVALID;
92 t = first_type_in_signature (reader->type_str,
95 else if (reader->container_type == DBUS_TYPE_ARRAY)
97 /* return the array element type if elements remain, and
98 * TYPE_INVALID otherwise
102 end_pos = reader->u.array.start_pos + reader->u.array.len;
104 _dbus_assert (reader->value_pos <= end_pos);
105 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
107 if (reader->value_pos < end_pos)
108 t = reader->u.array.element_type;
110 t = DBUS_TYPE_INVALID;
114 _dbus_assert_not_reached ("reader->container_type should not be set to this");
115 t = DBUS_TYPE_INVALID; /* quiet gcc */
118 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
119 _dbus_assert (t != DBUS_STRUCT_BEGIN_CHAR);
122 _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",
123 reader, reader->type_pos,
124 _dbus_type_to_string (t));
131 _dbus_type_reader_get_array_length (DBusTypeReader *reader)
133 /* FIXME if this is in number of elements I don't know how to compute it
134 * since we only have bytes and elements are variable-length
139 _dbus_type_reader_read_basic (DBusTypeReader *reader,
142 if (reader->container_type == DBUS_TYPE_INVALID ||
143 reader->container_type == DBUS_TYPE_STRUCT ||
144 reader->container_type == DBUS_TYPE_ARRAY)
149 t = _dbus_type_reader_get_current_type (reader);
151 next = reader->value_pos;
152 _dbus_demarshal_basic_type (reader->value_str,
158 _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
159 reader, reader->type_pos, reader->value_pos, next,
160 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
162 _dbus_verbose_bytes_of_string (reader->value_str,
165 _dbus_string_get_length (reader->value_str) - reader->value_pos));
169 _dbus_assert_not_reached ("reader->container_type should not be set to this");
174 _dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
184 * Initialize a new reader pointing to the first type and
185 * corresponding value that's a child of the current container. It's
186 * an error to call this if the current type is a non-container.
188 * @param reader the reader
189 * @param sub a reader to init pointing to the first child
192 _dbus_type_reader_recurse (DBusTypeReader *reader,
197 /* FIXME are we recursing over the type signature or over the values.
198 * Arrays don't necessarily have values for each element of the type
199 * signature. Thus we get a mismatch where we need to "bail out" and
200 * return the signature of each element, but can't return an element
201 * or recurse into the element signature. Not sure how to handle this;
202 * maybe think about how we will handle variant types and do something
203 * similar since they also have the idea of a signature for the whole
207 t = first_type_in_signature (reader->type_str, reader->type_pos);
209 /* point subreader at the same place as reader */
210 _dbus_type_reader_init (sub,
217 if (t == DBUS_TYPE_STRUCT)
219 sub->container_type = DBUS_TYPE_STRUCT;
223 /* struct has 8 byte alignment */
224 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
226 sub->u.strct.finished = FALSE;
228 else if (t == DBUS_TYPE_ARRAY)
230 dbus_uint32_t array_len;
233 sub->container_type = DBUS_TYPE_ARRAY;
235 /* point type_pos at the array element type */
238 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);
240 _dbus_demarshal_basic_type (sub->value_str,
246 sub->u.array.len = array_len;
248 alignment = element_type_get_alignment (sub->type_str,
251 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
253 sub->u.array.element_type = first_type_in_signature (sub->type_str,
255 sub->u.array.start_pos = sub->value_pos;
257 _dbus_verbose (" type reader %p array start = %d array len = %d array element type = %s\n",
259 sub->u.array.start_pos,
261 _dbus_type_to_string (sub->u.array.element_type));
265 _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));
266 if (t == DBUS_TYPE_INVALID)
267 _dbus_warn ("You can't recurse into an empty array or off the end of a message body\n");
269 _dbus_assert_not_reached ("don't yet handle recursing into this type");
272 _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",
273 sub, sub->type_pos, sub->value_pos,
274 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
278 skip_one_complete_type (const DBusString *type_str,
281 while (_dbus_string_get_byte (type_str, *type_pos) == DBUS_TYPE_ARRAY)
284 if (_dbus_string_get_byte (type_str, *type_pos) == DBUS_STRUCT_BEGIN_CHAR)
291 switch (_dbus_string_get_byte (type_str, *type_pos))
293 case DBUS_STRUCT_BEGIN_CHAR:
296 case DBUS_STRUCT_END_CHAR:
299 case DBUS_TYPE_INVALID:
300 _dbus_assert_not_reached ("unbalanced parens in signature");
311 * Skip to the next value on this "level". e.g. the next field in a
312 * struct, the next value in an array, the next key or value in a
313 * dict. Returns FALSE at the end of the current container.
315 * @param reader the reader
316 * @returns FALSE if nothing more to read at or below this level
319 _dbus_type_reader_next (DBusTypeReader *reader)
323 t = _dbus_type_reader_get_current_type (reader);
325 _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
326 reader, reader->type_pos, reader->value_pos,
327 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
328 _dbus_type_to_string (t));
330 if (t == DBUS_TYPE_INVALID)
333 if (reader->container_type == DBUS_TYPE_INVALID ||
334 reader->container_type == DBUS_TYPE_STRUCT)
338 case DBUS_TYPE_STRUCT:
339 case DBUS_TYPE_ARRAY:
340 /* Scan forward over the entire container contents */
341 /* FIXME this is super slow for arrays. We need to special
342 * case skipping all the elements at once instead of scanning.
347 /* Recurse into the struct */
348 _dbus_type_reader_recurse (reader, &sub);
350 /* Skip everything in this subreader */
351 while (_dbus_type_reader_next (&sub))
356 /* Now we are at the end of this container */
357 reader->type_pos = sub.type_pos;
358 reader->value_pos = sub.value_pos;
363 _dbus_marshal_skip_basic_type (reader->value_str,
364 t, reader->byte_order,
366 reader->type_pos += 1;
370 /* for STRUCT containers we return FALSE at the end of the struct,
371 * for INVALID we return FALSE at the end of the signature.
372 * In both cases we arrange for get_current_type() to return INVALID
373 * which is defined to happen iff we're at the end (no more next())
375 if (reader->container_type == DBUS_TYPE_STRUCT)
377 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
378 if (t == DBUS_STRUCT_END_CHAR)
380 reader->type_pos += 1;
381 reader->u.strct.finished = TRUE;
385 else if (reader->container_type == DBUS_TYPE_ARRAY)
387 /* Skip one array element */
390 end_pos = reader->u.array.start_pos + reader->u.array.len;
392 _dbus_assert (reader->value_pos < end_pos);
393 _dbus_assert (reader->value_pos >= reader->u.array.start_pos);
395 if (reader->u.array.element_type == DBUS_TYPE_ARRAY ||
396 reader->u.array.element_type == DBUS_TYPE_STRUCT)
400 /* Recurse into the array element */
401 _dbus_type_reader_recurse (reader, &sub);
403 /* Skip everything in this element */
404 while (_dbus_type_reader_next (&sub))
409 /* Now we are at the end of this element */
410 reader->value_pos = sub.value_pos;
414 _dbus_marshal_skip_basic_type (reader->value_str,
415 t, reader->byte_order,
419 _dbus_assert (reader->value_pos <= end_pos);
421 if (reader->value_pos == end_pos)
423 skip_one_complete_type (reader->type_str,
429 _dbus_assert_not_reached ("reader->container_type should not be set to this");
432 _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",
433 reader, reader->type_pos, reader->value_pos,
434 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),
435 _dbus_type_to_string (_dbus_type_reader_get_current_type (reader)));
437 return _dbus_type_reader_get_current_type (reader) != DBUS_TYPE_INVALID;
441 _dbus_type_writer_init (DBusTypeWriter *writer,
443 DBusString *type_str,
445 DBusString *value_str,
448 writer->byte_order = byte_order;
449 writer->type_str = type_str;
450 writer->type_pos = type_pos;
451 writer->value_str = value_str;
452 writer->value_pos = value_pos;
453 writer->container_type = DBUS_TYPE_INVALID;
454 writer->inside_array = FALSE;
458 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,
465 old_value_len = _dbus_string_get_length (writer->value_str);
467 if (!_dbus_marshal_basic_type (writer->value_str,
474 bytes_written = _dbus_string_get_length (writer->value_str) - old_value_len;
476 writer->value_pos += bytes_written;
482 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
488 /* First ensure that our type realloc will succeed */
489 if (!_dbus_string_alloc_space (writer->type_str, 1))
494 if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))
497 /* Now insert the type unless we're already covered by the array signature */
498 if (!writer->inside_array)
500 if (!_dbus_string_insert_byte (writer->type_str,
503 _dbus_assert_not_reached ("failed to insert byte after prealloc");
505 writer->type_pos += 1;
511 _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d inside_array = %d\n",
512 writer, writer->type_pos, writer->value_pos, writer->inside_array);
518 _dbus_type_writer_write_array (DBusTypeWriter *writer,
528 writer_recurse_init_and_check (DBusTypeWriter *writer,
530 const char *array_element_type,
533 _dbus_type_writer_init (sub,
540 sub->container_type = container_type;
542 /* While inside an array, we never want to write to the type str.
543 * We are inside an array if we're currently recursing into one.
545 if (writer->inside_array || sub->container_type == DBUS_TYPE_ARRAY)
546 sub->inside_array = TRUE;
548 sub->inside_array = FALSE;
550 /* If our parent is an array, things are a little bit complicated.
552 * The parent must have a complete element type, such as
553 * "i" or "aai" or "(ii)" or "a(ii)". There can't be
554 * unclosed parens, or an "a" with no following type.
556 * To recurse, the only allowed operation is to recurse into the
557 * first type in the element type. So for "i" you can't recurse, for
558 * "ai" you can recurse into the array, for "(ii)" you can recurse
561 * If you recurse into the array for "ai", then you must specify
562 * "i" for the element type of the array you recurse into.
564 * While inside an array at any level, we need to avoid writing to
565 * type_str, since the type only appears once for the whole array,
566 * it does not appear for each array element.
568 #ifndef DBUS_DISABLE_CHECKS
569 if (writer->container_type == DBUS_TYPE_ARRAY)
571 if ((sub->container_type == DBUS_TYPE_STRUCT &&
572 writer->u.array.element_type[0] != DBUS_STRUCT_BEGIN_CHAR) ||
573 (sub->container_type != DBUS_TYPE_STRUCT &&
574 writer->u.array.element_type[0] != sub->container_type))
576 _dbus_warn ("Recursing into an array with element type %s not allowed with container type %s\n",
577 writer->u.array.element_type, _dbus_type_to_string (sub->container_type));
580 if (sub->container_type == DBUS_TYPE_ARRAY)
582 DBusString parent_elements;
583 DBusString our_elements;
585 _dbus_assert (writer->u.array.element_type[0] == DBUS_TYPE_ARRAY);
587 _dbus_string_init_const (&parent_elements, &writer->u.array.element_type[1]);
588 _dbus_string_init_const (&our_elements, array_element_type);
590 if (!_dbus_string_equal (&parent_elements, &our_elements))
592 _dbus_warn ("Parent array expects elements '%s' and we are writing an array of '%s'\n",
593 writer->u.array.element_type,
598 #endif /* DBUS_DISABLE_CHECKS */
600 _dbus_verbose (" type writer %p recurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
601 writer, writer->type_pos, writer->value_pos, writer->inside_array,
602 _dbus_type_to_string (writer->container_type));
603 _dbus_verbose (" type writer %p new sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
604 sub, sub->type_pos, sub->value_pos,
606 _dbus_type_to_string (sub->container_type),
607 array_element_type ? array_element_type : "n/a");
611 _dbus_type_writer_recurse (DBusTypeWriter *writer,
615 writer_recurse_init_and_check (writer, container_type, NULL, sub);
617 switch (container_type)
619 case DBUS_TYPE_STRUCT:
621 if (!writer->inside_array)
623 /* Ensure that we'll be able to add alignment padding */
624 if (!_dbus_string_alloc_space (sub->value_str, 8))
627 if (!_dbus_string_insert_byte (sub->type_str,
629 DBUS_STRUCT_BEGIN_CHAR))
635 if (!_dbus_string_insert_bytes (sub->value_str,
637 _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,
639 _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");
640 sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);
643 case DBUS_TYPE_ARRAY:
644 _dbus_assert_not_reached ("use recurse_array() for arrays");
647 _dbus_assert_not_reached ("container_type unhandled");
655 _dbus_type_writer_recurse_array (DBusTypeWriter *writer,
656 const char *element_type,
659 int element_type_len;
660 DBusString element_type_str;
662 writer_recurse_init_and_check (writer, DBUS_TYPE_ARRAY, element_type, sub);
664 _dbus_string_init_const (&element_type_str, element_type);
665 element_type_len = _dbus_string_get_length (&element_type_str);
667 /* 4 bytes for the array length and 4 bytes possible padding */
668 if (!_dbus_string_alloc_space (sub->value_str, 8))
671 if (!writer->inside_array)
673 /* alloc space for array typecode, element signature, possible 7
676 if (!_dbus_string_alloc_space (sub->type_str, 1 + element_type_len + 7))
680 if (!_dbus_string_copy_data (&element_type_str,
681 &sub->u.array.element_type))
684 if (!writer->inside_array)
686 if (!_dbus_string_insert_byte (sub->type_str,
689 _dbus_assert_not_reached ("should not have failed to insert array typecode");
693 if (!_dbus_string_copy (&element_type_str, 0,
694 sub->type_str, sub->type_pos))
695 _dbus_assert_not_reached ("should not have failed to insert array element typecodes");
697 sub->type_pos += element_type_len;
700 sub->u.array.len_pos = sub->value_pos;
703 dbus_uint32_t value = 0;
708 if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,
710 _dbus_assert_not_reached ("should not have failed to insert array len");
712 _dbus_string_init_const (&str, element_type);
713 alignment = element_type_get_alignment (&str, 0);
715 aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);
716 if (aligned != sub->value_pos)
718 if (!_dbus_string_insert_bytes (sub->value_str,
720 aligned - sub->value_pos,
722 _dbus_assert_not_reached ("should not have failed to insert alignment padding");
724 sub->value_pos = aligned;
726 sub->u.array.start_pos = sub->value_pos;
729 _dbus_assert (sub->u.array.start_pos == sub->value_pos);
730 _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);
732 /* value_pos now points to the place for array data, and len_pos to the length */
738 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
741 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
743 _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d inside_array = %d container_type = %s\n",
744 writer, writer->type_pos, writer->value_pos, writer->inside_array,
745 _dbus_type_to_string (writer->container_type));
746 _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d inside_array = %d container_type = %s element_type = '%s'\n",
747 sub, sub->type_pos, sub->value_pos,
749 _dbus_type_to_string (sub->container_type),
750 sub->container_type == DBUS_TYPE_ARRAY ?
751 sub->u.array.element_type : "n/a");
753 if (sub->container_type == DBUS_TYPE_STRUCT)
755 if (!sub->inside_array)
757 if (!_dbus_string_insert_byte (sub->type_str,
759 DBUS_STRUCT_END_CHAR))
764 else if (sub->container_type == DBUS_TYPE_ARRAY)
768 dbus_free (sub->u.array.element_type);
769 sub->u.array.element_type = NULL;
771 /* Set the array length */
772 len = sub->value_pos - sub->u.array.start_pos;
773 _dbus_marshal_set_uint32 (sub->value_str,
775 sub->u.array.len_pos,
777 _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",
778 len, sub->u.array.len_pos);
781 /* Jump the parent writer to the new location */
782 writer->type_pos = sub->type_pos;
783 writer->value_pos = sub->value_pos;
788 /** @} */ /* end of DBusMarshal group */
790 #ifdef DBUS_BUILD_TESTS
791 #include "dbus-test.h"
797 DBusString signature;
808 data_block_init (DataBlock *block)
810 if (!_dbus_string_init (&block->signature))
813 if (!_dbus_string_init (&block->body))
815 _dbus_string_free (&block->signature);
823 data_block_free (DataBlock *block)
825 _dbus_string_free (&block->signature);
826 _dbus_string_free (&block->body);
830 data_block_save (DataBlock *block,
831 DataBlockState *state)
833 state->saved_sig_len = _dbus_string_get_length (&block->signature);
834 state->saved_body_len = _dbus_string_get_length (&block->body);
838 data_block_restore (DataBlock *block,
839 DataBlockState *state)
841 /* These set_length should be shortening things so should always work */
843 if (!_dbus_string_set_length (&block->signature,
844 state->saved_sig_len))
845 _dbus_assert_not_reached ("could not restore signature length");
847 if (!_dbus_string_set_length (&block->body,
848 state->saved_body_len))
849 _dbus_assert_not_reached ("could not restore body length");
853 data_block_init_reader_writer (DataBlock *block,
855 DBusTypeReader *reader,
856 DBusTypeWriter *writer)
858 _dbus_type_reader_init (reader,
861 _dbus_string_get_length (&block->signature),
863 _dbus_string_get_length (&block->body));
865 _dbus_type_writer_init (writer,
868 _dbus_string_get_length (&block->signature),
870 _dbus_string_get_length (&block->body));
873 #define SAMPLE_INT32 12345678
874 #define SAMPLE_INT32_ALTERNATE 53781429
876 write_int32 (DataBlock *block,
877 DBusTypeWriter *writer)
879 dbus_int32_t v = SAMPLE_INT32;
881 return _dbus_type_writer_write_basic (writer,
887 check_expected_type (DBusTypeReader *reader,
892 t = _dbus_type_reader_get_current_type (reader);
896 _dbus_warn ("Read type %s while expecting %s\n",
897 _dbus_type_to_string (t),
898 _dbus_type_to_string (expected));
900 _dbus_verbose_bytes_of_string (reader->type_str, 0,
901 _dbus_string_get_length (reader->type_str));
902 _dbus_verbose_bytes_of_string (reader->value_str, 0,
903 _dbus_string_get_length (reader->value_str));
910 read_int32 (DataBlock *block,
911 DBusTypeReader *reader)
915 check_expected_type (reader, DBUS_TYPE_INT32);
917 _dbus_type_reader_read_basic (reader,
920 _dbus_assert (v == SAMPLE_INT32);
926 write_struct_with_int32s (DataBlock *block,
927 DBusTypeWriter *writer)
930 DataBlockState saved;
933 data_block_save (block, &saved);
935 if (!_dbus_type_writer_recurse (writer,
941 if (!_dbus_type_writer_write_basic (&sub,
945 data_block_restore (block, &saved);
949 v = SAMPLE_INT32_ALTERNATE;
950 if (!_dbus_type_writer_write_basic (&sub,
954 data_block_restore (block, &saved);
958 if (!_dbus_type_writer_unrecurse (writer, &sub))
960 data_block_restore (block, &saved);
968 read_struct_with_int32s (DataBlock *block,
969 DBusTypeReader *reader)
974 check_expected_type (reader, DBUS_TYPE_STRUCT);
976 _dbus_type_reader_recurse (reader, &sub);
978 check_expected_type (&sub, DBUS_TYPE_INT32);
980 _dbus_type_reader_read_basic (&sub,
983 _dbus_assert (v == SAMPLE_INT32);
985 _dbus_type_reader_next (&sub);
986 check_expected_type (&sub, DBUS_TYPE_INT32);
988 _dbus_type_reader_read_basic (&sub,
991 _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
997 write_struct_of_structs (DataBlock *block,
998 DBusTypeWriter *writer)
1000 DataBlockState saved;
1003 data_block_save (block, &saved);
1005 if (!_dbus_type_writer_recurse (writer,
1010 if (!write_struct_with_int32s (block, &sub))
1012 data_block_restore (block, &saved);
1015 if (!write_struct_with_int32s (block, &sub))
1017 data_block_restore (block, &saved);
1020 if (!write_struct_with_int32s (block, &sub))
1022 data_block_restore (block, &saved);
1026 if (!_dbus_type_writer_unrecurse (writer, &sub))
1028 data_block_restore (block, &saved);
1036 read_struct_of_structs (DataBlock *block,
1037 DBusTypeReader *reader)
1041 check_expected_type (reader, DBUS_TYPE_STRUCT);
1043 _dbus_type_reader_recurse (reader, &sub);
1045 if (!read_struct_with_int32s (block, &sub))
1047 _dbus_type_reader_next (&sub);
1048 if (!read_struct_with_int32s (block, &sub))
1050 _dbus_type_reader_next (&sub);
1051 if (!read_struct_with_int32s (block, &sub))
1058 write_struct_of_structs_of_structs (DataBlock *block,
1059 DBusTypeWriter *writer)
1061 DataBlockState saved;
1064 data_block_save (block, &saved);
1066 if (!_dbus_type_writer_recurse (writer,
1071 if (!write_struct_of_structs (block, &sub))
1073 data_block_restore (block, &saved);
1076 if (!write_struct_of_structs (block, &sub))
1078 data_block_restore (block, &saved);
1082 if (!_dbus_type_writer_unrecurse (writer, &sub))
1084 data_block_restore (block, &saved);
1092 read_struct_of_structs_of_structs (DataBlock *block,
1093 DBusTypeReader *reader)
1097 check_expected_type (reader, DBUS_TYPE_STRUCT);
1099 _dbus_type_reader_recurse (reader, &sub);
1101 if (!read_struct_of_structs (block, &sub))
1103 _dbus_type_reader_next (&sub);
1104 if (!read_struct_of_structs (block, &sub))
1111 write_array_of_int32 (DataBlock *block,
1112 DBusTypeWriter *writer)
1115 DataBlockState saved;
1118 data_block_save (block, &saved);
1120 if (!_dbus_type_writer_recurse_array (writer,
1121 DBUS_TYPE_INT32_AS_STRING,
1125 v = SAMPLE_INT32_ALTERNATE;
1126 if (!_dbus_type_writer_write_basic (&sub,
1130 data_block_restore (block, &saved);
1135 if (!_dbus_type_writer_write_basic (&sub,
1139 data_block_restore (block, &saved);
1144 if (!_dbus_type_writer_write_basic (&sub,
1148 data_block_restore (block, &saved);
1152 if (!_dbus_type_writer_unrecurse (writer, &sub))
1154 data_block_restore (block, &saved);
1162 read_array_of_int32 (DataBlock *block,
1163 DBusTypeReader *reader)
1168 check_expected_type (reader, DBUS_TYPE_ARRAY);
1170 _dbus_type_reader_recurse (reader, &sub);
1172 check_expected_type (&sub, DBUS_TYPE_INT32);
1174 _dbus_type_reader_read_basic (&sub,
1175 (dbus_int32_t*) &v);
1177 _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
1179 _dbus_type_reader_next (&sub);
1180 check_expected_type (&sub, DBUS_TYPE_INT32);
1182 _dbus_type_reader_read_basic (&sub,
1183 (dbus_int32_t*) &v);
1185 _dbus_assert (v == SAMPLE_INT32);
1187 _dbus_type_reader_next (&sub);
1188 check_expected_type (&sub, DBUS_TYPE_INT32);
1190 _dbus_type_reader_read_basic (&sub,
1191 (dbus_int32_t*) &v);
1193 _dbus_assert (v == SAMPLE_INT32);
1200 write_array_of_int32_empty (DataBlock *block,
1201 DBusTypeWriter *writer)
1203 DataBlockState saved;
1206 data_block_save (block, &saved);
1208 if (!_dbus_type_writer_recurse_array (writer,
1209 DBUS_TYPE_INT32_AS_STRING,
1213 if (!_dbus_type_writer_unrecurse (writer, &sub))
1215 data_block_restore (block, &saved);
1223 read_array_of_int32_empty (DataBlock *block,
1224 DBusTypeReader *reader)
1228 check_expected_type (reader, DBUS_TYPE_ARRAY);
1230 _dbus_type_reader_recurse (reader, &sub);
1232 check_expected_type (&sub, DBUS_TYPE_INVALID);
1238 write_array_of_array_of_int32 (DataBlock *block,
1239 DBusTypeWriter *writer)
1241 DataBlockState saved;
1244 data_block_save (block, &saved);
1246 if (!_dbus_type_writer_recurse_array (writer,
1247 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1251 if (!write_array_of_int32 (block, &sub))
1253 data_block_restore (block, &saved);
1257 if (!write_array_of_int32 (block, &sub))
1259 data_block_restore (block, &saved);
1263 if (!write_array_of_int32_empty (block, &sub))
1265 data_block_restore (block, &saved);
1269 if (!write_array_of_int32 (block, &sub))
1271 data_block_restore (block, &saved);
1275 if (!_dbus_type_writer_unrecurse (writer, &sub))
1277 data_block_restore (block, &saved);
1285 read_array_of_array_of_int32 (DataBlock *block,
1286 DBusTypeReader *reader)
1290 check_expected_type (reader, DBUS_TYPE_ARRAY);
1292 _dbus_type_reader_recurse (reader, &sub);
1294 if (!read_array_of_int32 (block, &sub))
1296 _dbus_type_reader_next (&sub);
1297 if (!read_array_of_int32 (block, &sub))
1299 _dbus_type_reader_next (&sub);
1300 if (!read_array_of_int32_empty (block, &sub))
1302 _dbus_type_reader_next (&sub);
1303 if (!read_array_of_int32 (block, &sub))
1305 _dbus_type_reader_next (&sub);
1312 write_array_of_array_of_int32_empty (DataBlock *block,
1313 DBusTypeWriter *writer)
1315 DataBlockState saved;
1318 data_block_save (block, &saved);
1320 if (!_dbus_type_writer_recurse_array (writer,
1321 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1325 if (!_dbus_type_writer_unrecurse (writer, &sub))
1327 data_block_restore (block, &saved);
1335 read_array_of_array_of_int32_empty (DataBlock *block,
1336 DBusTypeReader *reader)
1339 DBusTypeReader sub2;
1341 check_expected_type (reader, DBUS_TYPE_ARRAY);
1343 _dbus_type_reader_recurse (reader, &sub);
1345 check_expected_type (reader, DBUS_TYPE_ARRAY);
1347 _dbus_type_reader_recurse (&sub, &sub2);
1349 check_expected_type (reader, DBUS_TYPE_INVALID);
1355 write_array_of_array_of_array_of_int32 (DataBlock *block,
1356 DBusTypeWriter *writer)
1358 DataBlockState saved;
1361 data_block_save (block, &saved);
1363 if (!_dbus_type_writer_recurse_array (writer,
1364 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_INT32_AS_STRING,
1368 if (!write_array_of_array_of_int32 (block, &sub))
1370 data_block_restore (block, &saved);
1374 if (!write_array_of_array_of_int32 (block, &sub))
1376 data_block_restore (block, &saved);
1380 if (!write_array_of_array_of_int32_empty (block, &sub))
1382 data_block_restore (block, &saved);
1386 if (!_dbus_type_writer_unrecurse (writer, &sub))
1388 data_block_restore (block, &saved);
1396 read_array_of_array_of_array_of_int32 (DataBlock *block,
1397 DBusTypeReader *reader)
1401 check_expected_type (reader, DBUS_TYPE_ARRAY);
1403 _dbus_type_reader_recurse (reader, &sub);
1405 if (!read_array_of_array_of_int32 (block, &sub))
1407 _dbus_type_reader_next (&sub);
1408 if (!read_array_of_array_of_int32 (block, &sub))
1410 _dbus_type_reader_next (&sub);
1411 if (!read_array_of_array_of_int32_empty (block, &sub))
1413 _dbus_type_reader_next (&sub);
1421 ITEM_STRUCT_WITH_INT32S,
1422 ITEM_STRUCT_OF_STRUCTS,
1423 ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
1424 ITEM_ARRAY_OF_INT32,
1425 ITEM_ARRAY_OF_INT32_EMPTY,
1426 ITEM_ARRAY_OF_ARRAY_OF_INT32,
1427 ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
1428 ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
1433 typedef dbus_bool_t (* WriteItemFunc) (DataBlock *block,
1434 DBusTypeWriter *writer);
1435 typedef dbus_bool_t (* ReadItemFunc) (DataBlock *block,
1436 DBusTypeReader *reader);
1442 WriteItemFunc write_item_func;
1443 ReadItemFunc read_item_func;
1446 static CheckMarshalItem items[] = {
1448 ITEM_INT32, write_int32, read_int32 },
1449 { "struct with two int32",
1450 ITEM_STRUCT_WITH_INT32S, write_struct_with_int32s, read_struct_with_int32s },
1451 { "struct with three structs of two int32",
1452 ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
1453 { "struct of two structs of three structs of two int32",
1454 ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
1455 write_struct_of_structs_of_structs,
1456 read_struct_of_structs_of_structs },
1458 ITEM_ARRAY_OF_INT32, write_array_of_int32, read_array_of_int32 },
1459 { "empty array of int32",
1460 ITEM_ARRAY_OF_INT32_EMPTY, write_array_of_int32_empty, read_array_of_int32_empty },
1461 { "array of array of int32",
1462 ITEM_ARRAY_OF_ARRAY_OF_INT32,
1463 write_array_of_array_of_int32, read_array_of_array_of_int32 },
1464 { "empty array of array of int32",
1465 ITEM_ARRAY_OF_ARRAY_OF_INT32_EMPTY,
1466 write_array_of_array_of_int32_empty, read_array_of_array_of_int32_empty },
1467 { "array of array of array of int32",
1468 ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32,
1469 write_array_of_array_of_array_of_int32, read_array_of_array_of_array_of_int32 }
1474 /* Array of items from the above items[]; -1 terminated */
1478 static TestRun runs[] = {
1479 { { ITEM_INVALID } },
1482 { { ITEM_INT32, ITEM_INVALID } },
1483 { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
1484 { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
1486 /* STRUCT_WITH_INT32S */
1487 { { ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1488 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1489 { { ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1490 { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1491 { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
1493 /* STRUCT_OF_STRUCTS */
1494 { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1495 { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1496 { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1497 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1498 { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1499 { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
1501 /* STRUCT_OF_STRUCTS_OF_STRUCTS */
1502 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1503 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1504 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1505 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1506 { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1507 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1509 /* ARRAY_OF_INT32 */
1510 { { ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1511 { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1512 { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1513 { { ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1514 { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1515 { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1516 { { ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1517 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1518 { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1519 { { ITEM_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_INT32, ITEM_INVALID } },
1521 /* ARRAY_OF_ARRAY_OF_INT32 */
1522 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1523 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1524 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1525 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1526 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1527 { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1528 { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1529 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1530 { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1531 { { ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1533 /* ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32 */
1534 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1535 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1536 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1537 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1538 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_INVALID } },
1539 { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1540 { { ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1541 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
1542 { { ITEM_STRUCT_WITH_INT32S, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } },
1543 { { ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INT32, ITEM_ARRAY_OF_ARRAY_OF_ARRAY_OF_INT32, ITEM_INVALID } }
1549 perform_one_run (DataBlock *block,
1553 DBusTypeReader reader;
1554 DBusTypeWriter writer;
1556 DataBlockState saved;
1562 _dbus_verbose ("run byteorder %s items ",
1563 byte_order == DBUS_LITTLE_ENDIAN ? "little" : "big");
1565 while (run->items[i] != ITEM_INVALID)
1567 CheckMarshalItem *item = &items[run->items[i]];
1569 _dbus_verbose ("%s ", item->desc);
1572 _dbus_verbose (" = %d items\n", i);
1575 data_block_save (block, &saved);
1577 data_block_init_reader_writer (block,
1582 while (run->items[i] != ITEM_INVALID)
1584 CheckMarshalItem *item = &items[run->items[i]];
1586 _dbus_verbose (">>writing %s\n", item->desc);
1588 if (!(* item->write_item_func) (block, &writer))
1594 while (run->items[i] != ITEM_INVALID)
1596 CheckMarshalItem *item = &items[run->items[i]];
1598 _dbus_verbose (">>reading %s\n", item->desc);
1600 if (!(* item->read_item_func) (block, &reader))
1603 _dbus_type_reader_next (&reader);
1611 data_block_restore (block, &saved);
1616 perform_all_runs (int byte_order,
1625 if (!data_block_init (&block))
1628 if (!_dbus_string_lengthen (&block.signature, initial_offset))
1631 if (!_dbus_string_lengthen (&block.body, initial_offset))
1635 while (i < _DBUS_N_ELEMENTS (runs))
1637 if (!perform_one_run (&block, byte_order, &runs[i]))
1646 data_block_free (&block);
1652 perform_all_items (int byte_order,
1662 if (!data_block_init (&block))
1666 if (!_dbus_string_lengthen (&block.signature, initial_offset))
1669 if (!_dbus_string_lengthen (&block.body, initial_offset))
1672 /* Create a run containing all the items */
1674 while (i < _DBUS_N_ELEMENTS (items))
1676 _dbus_assert (i == items[i].which);
1678 run.items[i] = items[i].which;
1683 run.items[i] = ITEM_INVALID;
1685 if (!perform_one_run (&block, byte_order, &run))
1691 data_block_free (&block);
1697 recursive_marshal_test_iteration (void *data)
1704 if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
1706 if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
1708 if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
1710 if (!perform_all_items (DBUS_BIG_ENDIAN, i))
1719 dbus_bool_t _dbus_marshal_recursive_test (void);
1722 _dbus_marshal_recursive_test (void)
1724 _dbus_test_oom_handling ("recursive marshaling",
1725 recursive_marshal_test_iteration,
1733 main (int argc, char **argv)
1735 _dbus_marshal_recursive_test ();
1741 #endif /* DBUS_BUILD_TESTS */