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 _dbus_type_reader_init (DBusTypeReader *reader,
35 const DBusString *type_str,
37 const DBusString *value_str,
40 reader->byte_order = byte_order;
41 reader->type_str = type_str;
42 reader->type_pos = type_pos;
43 reader->value_str = value_str;
44 reader->value_pos = value_pos;
46 _dbus_verbose ("type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",
47 reader, reader->type_pos, reader->value_pos,
48 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
52 _dbus_type_reader_get_current_type (DBusTypeReader *reader)
56 t = _dbus_string_get_byte (reader->type_str,
59 if (t == DBUS_STRUCT_BEGIN_CHAR)
62 /* this should never be a stopping place */
63 _dbus_assert (t != DBUS_STRUCT_END_CHAR);
66 _dbus_verbose ("type reader %p current type_pos = %d type = %s\n",
67 reader, reader->type_pos,
68 _dbus_type_to_string (t));
75 _dbus_type_reader_get_array_type (DBusTypeReader *reader)
79 t = _dbus_type_reader_get_current_type (reader);
81 if (t != DBUS_TYPE_ARRAY)
82 return DBUS_TYPE_INVALID;
84 t = _dbus_string_get_byte (reader->type_str,
85 reader->type_pos + 1);
91 _dbus_type_reader_read_basic (DBusTypeReader *reader,
97 t = _dbus_type_reader_get_current_type (reader);
99 next = reader->value_pos;
100 _dbus_demarshal_basic_type (reader->value_str,
105 _dbus_verbose ("type reader %p read basic type_pos = %d value_pos = %d next = %d remaining sig '%s'\n",
106 reader, reader->type_pos, reader->value_pos, next,
107 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
109 _dbus_verbose_bytes_of_string (reader->value_str,
112 _dbus_string_get_length (reader->value_str) - reader->value_pos));
116 _dbus_type_reader_read_array_of_basic (DBusTypeReader *reader,
126 * Initialize a new reader pointing to the first type and
127 * corresponding value that's a child of the current container. It's
128 * an error to call this if the current type is a non-container.
130 * @param reader the reader
131 * @param sub a reader to init pointing to the first child
134 _dbus_type_reader_recurse (DBusTypeReader *reader,
139 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
141 /* point subreader at the same place as reader */
142 _dbus_type_reader_init (sub,
149 _dbus_assert (t == DBUS_STRUCT_BEGIN_CHAR); /* only this works right now */
153 /* no value_pos increment since the struct itself doesn't take up value space */
155 _dbus_verbose ("type reader %p recursed type_pos = %d value_pos = %d remaining sig '%s'\n",
156 sub, sub->type_pos, sub->value_pos,
157 _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));
161 * Skip to the next value on this "level". e.g. the next field in a
162 * struct, the next value in an array, the next key or value in a
163 * dict. Returns FALSE at the end of the current container.
165 * @param reader the reader
166 * @returns FALSE if nothing more to read at or below this level
169 _dbus_type_reader_next (DBusTypeReader *reader)
173 /* FIXME handled calling next when there's no next */
175 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
177 _dbus_verbose ("type reader %p next() { type_pos = %d value_pos = %d remaining sig '%s'\n",
178 reader, reader->type_pos, reader->value_pos,
179 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
183 case DBUS_STRUCT_BEGIN_CHAR:
184 /* Scan forward over the entire container contents */
188 /* Recurse into the struct */
189 _dbus_type_reader_recurse (reader, &sub);
191 /* Skip everything in this subreader */
192 while (_dbus_type_reader_next (&sub))
197 /* Now we are at the end of this container */
198 reader->type_pos = sub.type_pos;
199 reader->value_pos = sub.value_pos;
204 /* FIXME for array etc. this is more complicated */
205 _dbus_marshal_skip_basic_type (reader->value_str,
206 t, reader->byte_order,
208 reader->type_pos += 1;
212 _dbus_verbose ("type reader %p } type_pos = %d value_pos = %d remaining sig '%s'\n",
213 reader, reader->type_pos, reader->value_pos,
214 _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));
216 /* FIXME this is wrong; we need to return FALSE when we finish the
217 * container we've recursed into; even if the signature continues.
220 t = _dbus_string_get_byte (reader->type_str, reader->type_pos);
222 if (t == DBUS_STRUCT_END_CHAR)
224 reader->type_pos += 1;
227 if (t == DBUS_TYPE_INVALID)
234 _dbus_type_writer_init (DBusTypeWriter *writer,
236 DBusString *type_str,
238 DBusString *value_str,
241 writer->byte_order = byte_order;
242 writer->type_str = type_str;
243 writer->type_pos = type_pos;
244 writer->value_str = value_str;
245 writer->value_pos = value_pos;
246 writer->container_type = DBUS_TYPE_INVALID;
250 _dbus_type_writer_write_basic (DBusTypeWriter *writer,
257 old_value_len = _dbus_string_get_length (writer->value_str);
259 /* First ensure that our type realloc will succeed */
260 if (!_dbus_string_alloc_space (writer->type_str, 1))
265 if (!_dbus_marshal_basic_type (writer->value_str,
272 writer->value_pos += _dbus_string_get_length (writer->value_str) - old_value_len;
274 /* Now insert the type */
275 if (!_dbus_string_insert_byte (writer->type_str,
278 _dbus_assert_not_reached ("failed to insert byte after prealloc");
280 writer->type_pos += 1;
289 _dbus_type_writer_write_array (DBusTypeWriter *writer,
299 _dbus_type_writer_recurse (DBusTypeWriter *writer,
303 _dbus_type_writer_init (sub,
309 sub->container_type = container_type;
311 switch (container_type)
313 case DBUS_TYPE_STRUCT:
315 if (!_dbus_string_insert_byte (sub->type_str,
317 DBUS_STRUCT_BEGIN_CHAR))
324 _dbus_assert_not_reached ("container_type unhandled");
332 _dbus_type_writer_unrecurse (DBusTypeWriter *writer,
335 _dbus_assert (sub->type_pos > 0); /* can't be recursed if this fails */
337 if (sub->container_type == DBUS_TYPE_STRUCT)
339 if (!_dbus_string_insert_byte (sub->type_str,
341 DBUS_STRUCT_END_CHAR))
346 /* Jump the parent writer to the new location */
347 writer->type_pos = sub->type_pos;
348 writer->value_pos = sub->value_pos;
353 /** @} */ /* end of DBusMarshal group */
355 #ifdef DBUS_BUILD_TESTS
356 #include "dbus-test.h"
362 DBusString signature;
373 data_block_init (DataBlock *block)
375 if (!_dbus_string_init (&block->signature))
378 if (!_dbus_string_init (&block->body))
380 _dbus_string_free (&block->signature);
388 data_block_free (DataBlock *block)
390 _dbus_string_free (&block->signature);
391 _dbus_string_free (&block->body);
395 data_block_save (DataBlock *block,
396 DataBlockState *state)
398 state->saved_sig_len = _dbus_string_get_length (&block->signature);
399 state->saved_body_len = _dbus_string_get_length (&block->body);
403 data_block_restore (DataBlock *block,
404 DataBlockState *state)
406 /* These set_length should be shortening things so should always work */
408 if (!_dbus_string_set_length (&block->signature,
409 state->saved_sig_len))
410 _dbus_assert_not_reached ("could not restore signature length");
412 if (!_dbus_string_set_length (&block->body,
413 state->saved_body_len))
414 _dbus_assert_not_reached ("could not restore body length");
418 data_block_init_reader_writer (DataBlock *block,
420 DBusTypeReader *reader,
421 DBusTypeWriter *writer)
423 _dbus_type_reader_init (reader,
426 _dbus_string_get_length (&block->signature),
428 _dbus_string_get_length (&block->body));
430 _dbus_type_writer_init (writer,
433 _dbus_string_get_length (&block->signature),
435 _dbus_string_get_length (&block->body));
438 #define SAMPLE_INT32 12345678
439 #define SAMPLE_INT32_ALTERNATE 53781429
441 write_int32 (DataBlock *block,
442 DBusTypeWriter *writer)
444 dbus_int32_t v = SAMPLE_INT32;
446 return _dbus_type_writer_write_basic (writer,
452 check_expected_type (DBusTypeReader *reader,
457 t = _dbus_type_reader_get_current_type (reader);
461 _dbus_warn ("Read type %s while expecting %s\n",
462 _dbus_type_to_string (t),
463 _dbus_type_to_string (expected));
465 _dbus_verbose_bytes_of_string (reader->type_str, 0,
466 _dbus_string_get_length (reader->type_str));
467 _dbus_verbose_bytes_of_string (reader->value_str, 0,
468 _dbus_string_get_length (reader->value_str));
475 read_int32 (DataBlock *block,
476 DBusTypeReader *reader)
480 check_expected_type (reader, DBUS_TYPE_INT32);
482 _dbus_type_reader_read_basic (reader,
485 _dbus_assert (v == SAMPLE_INT32);
491 write_struct_with_int32s (DataBlock *block,
492 DBusTypeWriter *writer)
495 DataBlockState saved;
498 data_block_save (block, &saved);
500 if (!_dbus_type_writer_recurse (writer,
506 if (!_dbus_type_writer_write_basic (&sub,
510 data_block_restore (block, &saved);
514 v = SAMPLE_INT32_ALTERNATE;
515 if (!_dbus_type_writer_write_basic (&sub,
519 data_block_restore (block, &saved);
523 if (!_dbus_type_writer_unrecurse (writer, &sub))
525 data_block_restore (block, &saved);
533 read_struct_with_int32s (DataBlock *block,
534 DBusTypeReader *reader)
539 check_expected_type (reader, DBUS_TYPE_STRUCT);
541 _dbus_type_reader_recurse (reader, &sub);
543 check_expected_type (&sub, DBUS_TYPE_INT32);
545 _dbus_type_reader_read_basic (&sub,
548 _dbus_assert (v == SAMPLE_INT32);
550 _dbus_type_reader_next (&sub);
551 check_expected_type (&sub, DBUS_TYPE_INT32);
553 _dbus_type_reader_read_basic (&sub,
556 _dbus_assert (v == SAMPLE_INT32_ALTERNATE);
562 write_struct_of_structs (DataBlock *block,
563 DBusTypeWriter *writer)
565 DataBlockState saved;
568 data_block_save (block, &saved);
570 if (!_dbus_type_writer_recurse (writer,
575 if (!write_struct_with_int32s (block, &sub))
577 data_block_restore (block, &saved);
580 if (!write_struct_with_int32s (block, &sub))
582 data_block_restore (block, &saved);
585 if (!write_struct_with_int32s (block, &sub))
587 data_block_restore (block, &saved);
591 if (!_dbus_type_writer_unrecurse (writer, &sub))
593 data_block_restore (block, &saved);
601 read_struct_of_structs (DataBlock *block,
602 DBusTypeReader *reader)
606 check_expected_type (reader, DBUS_TYPE_STRUCT);
608 _dbus_type_reader_recurse (reader, &sub);
610 if (!read_struct_with_int32s (block, &sub))
612 _dbus_type_reader_next (&sub);
613 if (!read_struct_with_int32s (block, &sub))
615 _dbus_type_reader_next (&sub);
616 if (!read_struct_with_int32s (block, &sub))
623 write_struct_of_structs_of_structs (DataBlock *block,
624 DBusTypeWriter *writer)
626 DataBlockState saved;
629 data_block_save (block, &saved);
631 if (!_dbus_type_writer_recurse (writer,
636 if (!write_struct_of_structs (block, &sub))
638 data_block_restore (block, &saved);
641 if (!write_struct_of_structs (block, &sub))
643 data_block_restore (block, &saved);
647 if (!_dbus_type_writer_unrecurse (writer, &sub))
649 data_block_restore (block, &saved);
657 read_struct_of_structs_of_structs (DataBlock *block,
658 DBusTypeReader *reader)
662 check_expected_type (reader, DBUS_TYPE_STRUCT);
664 _dbus_type_reader_recurse (reader, &sub);
666 if (!read_struct_of_structs (block, &sub))
668 _dbus_type_reader_next (&sub);
669 if (!read_struct_of_structs (block, &sub))
678 ITEM_STRUCT_WITH_INT32S,
679 ITEM_STRUCT_OF_STRUCTS,
680 ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
685 typedef dbus_bool_t (* WriteItemFunc) (DataBlock *block,
686 DBusTypeWriter *writer);
687 typedef dbus_bool_t (* ReadItemFunc) (DataBlock *block,
688 DBusTypeReader *reader);
694 WriteItemFunc write_item_func;
695 ReadItemFunc read_item_func;
698 static CheckMarshalItem items[] = {
700 ITEM_INT32, write_int32, read_int32 },
701 { "struct with two int32",
702 ITEM_STRUCT_WITH_INT32S, write_struct_with_int32s, read_struct_with_int32s },
703 { "struct with three structs of two int32",
704 ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs },
705 { "struct of two structs of three structs of two int32",
706 ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS,
707 write_struct_of_structs_of_structs,
708 read_struct_of_structs_of_structs }
713 /* Array of items in the above items[]; -1 terminated */
717 static TestRun runs[] = {
718 { { ITEM_INVALID } },
721 { { ITEM_INT32, ITEM_INVALID } },
722 { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
723 { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } },
725 /* STRUCT_WITH_INT32S */
726 { { ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
727 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
728 { { ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
729 { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
730 { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } },
732 /* STRUCT_OF_STRUCTS */
733 { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
734 { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
735 { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
736 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
737 { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
738 { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } },
740 /* STRUCT_OF_STRUCTS_OF_STRUCTS */
741 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
742 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
743 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
744 { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
745 { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } },
746 { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }
751 perform_one_run (DataBlock *block,
755 DBusTypeReader reader;
756 DBusTypeWriter writer;
758 DataBlockState saved;
763 data_block_save (block, &saved);
765 data_block_init_reader_writer (block,
770 while (run->items[i] != ITEM_INVALID)
772 CheckMarshalItem *item = &items[run->items[i]];
774 _dbus_verbose ("writing %s\n", item->desc);
776 if (!(* item->write_item_func) (block, &writer))
782 while (run->items[i] != ITEM_INVALID)
784 CheckMarshalItem *item = &items[run->items[i]];
786 _dbus_verbose ("reading %s\n", item->desc);
788 if (!(* item->read_item_func) (block, &reader))
791 _dbus_type_reader_next (&reader);
799 data_block_restore (block, &saved);
804 perform_all_runs (int byte_order,
813 if (!data_block_init (&block))
816 if (!_dbus_string_lengthen (&block.signature, initial_offset))
819 if (!_dbus_string_lengthen (&block.body, initial_offset))
823 while (i < _DBUS_N_ELEMENTS (runs))
825 if (!perform_one_run (&block, byte_order, &runs[i]))
834 data_block_free (&block);
840 perform_all_items (int byte_order,
850 if (!data_block_init (&block))
854 if (!_dbus_string_lengthen (&block.signature, initial_offset))
857 if (!_dbus_string_lengthen (&block.body, initial_offset))
860 /* Create a run containing all the items */
862 while (i < _DBUS_N_ELEMENTS (items))
864 _dbus_assert (i == items[i].which);
866 run.items[i] = items[i].which;
871 run.items[i] = ITEM_INVALID;
873 if (!perform_one_run (&block, byte_order, &run))
879 data_block_free (&block);
885 recursive_marshal_test_iteration (void *data)
892 if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i))
894 if (!perform_all_runs (DBUS_BIG_ENDIAN, i))
896 if (!perform_all_items (DBUS_LITTLE_ENDIAN, i))
898 if (!perform_all_items (DBUS_BIG_ENDIAN, i))
907 dbus_bool_t _dbus_marshal_recursive_test (void);
910 _dbus_marshal_recursive_test (void)
912 _dbus_test_oom_handling ("recursive marshaling",
913 recursive_marshal_test_iteration,
921 main (int argc, char **argv)
923 _dbus_marshal_recursive_test ();
929 #endif /* DBUS_BUILD_TESTS */