/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-marshal-recursive.c Marshalling routines for recursive types * * Copyright (C) 2004 Red Hat, Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "dbus-marshal-recursive.h" #include "dbus-internals.h" /** * @addtogroup DBusMarshal * @{ */ void _dbus_type_reader_init (DBusTypeReader *reader, int byte_order, const DBusString *type_str, int type_pos, const DBusString *value_str, int value_pos) { } int _dbus_type_reader_get_value_end (DBusTypeReader *reader) { } int _dbus_type_reader_get_type_end (DBusTypeReader *reader) { } int _dbus_type_reader_get_current_type (DBusTypeReader *reader) { } int _dbus_type_reader_get_array_type (DBusTypeReader *reader) { } void _dbus_type_reader_read_basic (DBusTypeReader *reader, void *value) { } dbus_bool_t _dbus_type_reader_read_array (DBusTypeReader *reader, int type, void **array, int *array_len) { } void _dbus_type_reader_recurse (DBusTypeReader *reader) { } void _dbus_type_reader_unrecurse (DBusTypeReader *reader) { } dbus_bool_t _dbus_type_reader_next (DBusTypeReader *reader) { } void _dbus_type_writer_init (DBusTypeWriter *writer, int byte_order, DBusString *type_str, int type_pos, DBusString *value_str, int value_pos) { } dbus_bool_t _dbus_type_writer_write_basic (DBusTypeWriter *writer, int type, const void *value) { } dbus_bool_t _dbus_type_writer_write_array (DBusTypeWriter *writer, int type, const void *array, int array_len) { } dbus_bool_t _dbus_type_writer_recurse (DBusTypeWriter *writer, int container_type) { } dbus_bool_t _dbus_type_writer_unrecurse (DBusTypeWriter *writer) { } /** @} */ /* end of DBusMarshal group */ #ifdef DBUS_BUILD_TESTS #include "dbus-test.h" #include #include typedef struct { DBusString signature; DBusString body; } DataBlock; typedef struct { int saved_sig_len; int saved_body_len; } DataBlockState; static dbus_bool_t data_block_init (DataBlock *block) { if (!_dbus_string_init (&block->signature)) return FALSE; if (!_dbus_string_init (&block->body)) { _dbus_string_free (&block->signature); return FALSE; } return TRUE; } static void data_block_free (DataBlock *block) { _dbus_string_free (&block->signature); _dbus_string_free (&block->body); } static void data_block_save (DataBlock *block, DataBlockState *state) { state->saved_sig_len = _dbus_string_get_length (&block->signature); state->saved_body_len = _dbus_string_get_length (&block->body); } static void data_block_restore (DataBlock *block, DataBlockState *state) { /* These set_length should be shortening things so should always work */ if (!_dbus_string_set_length (&block->signature, state->saved_sig_len)) _dbus_assert_not_reached ("could not restore signature length"); if (!_dbus_string_set_length (&block->body, state->saved_body_len)) _dbus_assert_not_reached ("could not restore body length"); } static void data_block_init_reader_writer (DataBlock *block, int byte_order, DBusTypeReader *reader, DBusTypeWriter *writer) { _dbus_type_reader_init (reader, byte_order, &block->signature, _dbus_string_get_length (&block->signature), &block->body, _dbus_string_get_length (&block->body)); _dbus_type_writer_init (writer, byte_order, &block->signature, _dbus_string_get_length (&block->signature), &block->body, _dbus_string_get_length (&block->body)); } #define SAMPLE_INT32 12345678 #define SAMPLE_INT32_ALTERNATE 53781429 static dbus_bool_t write_int32 (DataBlock *block, DBusTypeWriter *writer) { dbus_int32_t v = SAMPLE_INT32; return _dbus_type_writer_write_basic (writer, DBUS_TYPE_INT32, &v); } static void check_expected_type (DBusTypeReader *reader, int expected) { int t; t = _dbus_type_reader_get_current_type (reader); if (t != expected) { _dbus_warn ("Read type %s while expecting %s\n", _dbus_type_to_string (t), _dbus_type_to_string (expected)); exit (1); } } static dbus_bool_t read_int32 (DataBlock *block, DBusTypeReader *reader) { dbus_int32_t v; check_expected_type (reader, DBUS_TYPE_INT32); _dbus_type_reader_read_basic (reader, (dbus_int32_t*) &v); _dbus_assert (v == SAMPLE_INT32); return TRUE; } static dbus_bool_t write_struct_with_int32s (DataBlock *block, DBusTypeWriter *writer) { dbus_int32_t v; DataBlockState saved; data_block_save (block, &saved); if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT)) return FALSE; v = SAMPLE_INT32; if (!_dbus_type_writer_write_basic (writer, DBUS_TYPE_INT32, &v)) { data_block_restore (block, &saved); return FALSE; } v = SAMPLE_INT32_ALTERNATE; if (!_dbus_type_writer_write_basic (writer, DBUS_TYPE_INT32, &v)) { data_block_restore (block, &saved); return FALSE; } if (!_dbus_type_writer_unrecurse (writer)) { data_block_restore (block, &saved); return FALSE; } return TRUE; } static dbus_bool_t read_struct_with_int32s (DataBlock *block, DBusTypeReader *reader) { dbus_int32_t v; check_expected_type (reader, DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (reader); check_expected_type (reader, DBUS_TYPE_INT32); _dbus_type_reader_read_basic (reader, (dbus_int32_t*) &v); _dbus_assert (v == SAMPLE_INT32); _dbus_type_reader_next (reader); check_expected_type (reader, DBUS_TYPE_INT32); _dbus_type_reader_read_basic (reader, (dbus_int32_t*) &v); _dbus_assert (v == SAMPLE_INT32_ALTERNATE); _dbus_type_reader_unrecurse (reader); return TRUE; } static dbus_bool_t write_struct_of_structs (DataBlock *block, DBusTypeWriter *writer) { DataBlockState saved; data_block_save (block, &saved); if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT)) return FALSE; if (!write_struct_with_int32s (block, writer)) { data_block_restore (block, &saved); return FALSE; } if (!write_struct_with_int32s (block, writer)) { data_block_restore (block, &saved); return FALSE; } if (!write_struct_with_int32s (block, writer)) { data_block_restore (block, &saved); return FALSE; } if (!_dbus_type_writer_unrecurse (writer)) { data_block_restore (block, &saved); return FALSE; } return TRUE; } static dbus_bool_t read_struct_of_structs (DataBlock *block, DBusTypeReader *reader) { check_expected_type (reader, DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (reader); if (!read_struct_with_int32s (block, reader)) return FALSE; _dbus_type_reader_next (reader); if (!read_struct_with_int32s (block, reader)) return FALSE; _dbus_type_reader_next (reader); if (!read_struct_with_int32s (block, reader)) return FALSE; _dbus_type_reader_unrecurse (reader); return TRUE; } static dbus_bool_t write_struct_of_structs_of_structs (DataBlock *block, DBusTypeWriter *writer) { DataBlockState saved; data_block_save (block, &saved); if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_STRUCT)) return FALSE; if (!write_struct_of_structs (block, writer)) { data_block_restore (block, &saved); return FALSE; } if (!write_struct_of_structs (block, writer)) { data_block_restore (block, &saved); return FALSE; } if (!_dbus_type_writer_unrecurse (writer)) { data_block_restore (block, &saved); return FALSE; } return TRUE; } static dbus_bool_t read_struct_of_structs_of_structs (DataBlock *block, DBusTypeReader *reader) { check_expected_type (reader, DBUS_TYPE_STRUCT); _dbus_type_reader_recurse (reader); if (!read_struct_of_structs (block, reader)) return FALSE; _dbus_type_reader_next (reader); if (!read_struct_of_structs (block, reader)) return FALSE; _dbus_type_reader_unrecurse (reader); return TRUE; } typedef enum { ITEM_INVALID = -1, ITEM_INT32 = 0, ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_LAST } WhichItem; typedef dbus_bool_t (* WriteItemFunc) (DataBlock *block, DBusTypeWriter *writer); typedef dbus_bool_t (* ReadItemFunc) (DataBlock *block, DBusTypeReader *reader); typedef struct { WhichItem which; WriteItemFunc write_item_func; ReadItemFunc read_item_func; } CheckMarshalItem; static CheckMarshalItem items[] = { { ITEM_INT32, write_int32, read_int32 }, { ITEM_STRUCT_WITH_INT32S, write_struct_with_int32s, read_struct_with_int32s }, { ITEM_STRUCT_OF_STRUCTS, write_struct_of_structs, read_struct_of_structs }, { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, write_struct_of_structs_of_structs, read_struct_of_structs_of_structs } }; typedef struct { /* Array of items in the above items[]; -1 terminated */ int items[20]; } TestRun; static TestRun runs[] = { { { ITEM_INVALID } }, /* INT32 */ { { ITEM_INT32, ITEM_INVALID } }, { { ITEM_INT32, ITEM_INT32, ITEM_INVALID } }, { { ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_INVALID } }, /* STRUCT_WITH_INT32S */ { { ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } }, { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } }, { { ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } }, { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } }, { { ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INT32, ITEM_INT32, ITEM_INT32, ITEM_STRUCT_WITH_INT32S, ITEM_INVALID } }, /* STRUCT_OF_STRUCTS */ { { ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS, ITEM_INVALID } }, /* STRUCT_OF_STRUCTS_OF_STRUCTS */ { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_WITH_INT32S, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INT32, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } }, { { ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_STRUCT_OF_STRUCTS_OF_STRUCTS, ITEM_INVALID } } }; static dbus_bool_t perform_one_run (DataBlock *block, int byte_order, TestRun *run) { DBusTypeReader reader; DBusTypeWriter writer; int i; DataBlockState saved; dbus_bool_t retval; retval = FALSE; data_block_save (block, &saved); data_block_init_reader_writer (block, byte_order, &reader, &writer); i = 0; while (run->items[i] != ITEM_INVALID) { CheckMarshalItem *item = &items[run->items[i]]; if (!(* item->write_item_func) (block, &writer)) goto out; ++i; } i = 0; while (run->items[i] != ITEM_INVALID) { CheckMarshalItem *item = &items[run->items[i]]; if (!(* item->read_item_func) (block, &reader)) goto out; _dbus_type_reader_next (&reader); ++i; } retval = TRUE; out: data_block_restore (block, &saved); return retval; } static dbus_bool_t perform_all_runs (int byte_order, int initial_offset) { int i; DataBlock block; dbus_bool_t retval; retval = FALSE; if (!data_block_init (&block)) return FALSE; if (!_dbus_string_lengthen (&block.signature, initial_offset)) goto out; if (!_dbus_string_lengthen (&block.body, initial_offset)) goto out; i = 0; while (i < _DBUS_N_ELEMENTS (runs)) { if (!perform_one_run (&block, byte_order, &runs[i])) goto out; ++i; } retval = TRUE; out: data_block_free (&block); return retval; } static dbus_bool_t perform_all_items (int byte_order, int initial_offset) { int i; DataBlock block; dbus_bool_t retval; TestRun run; retval = FALSE; if (!data_block_init (&block)) return FALSE; if (!_dbus_string_lengthen (&block.signature, initial_offset)) goto out; if (!_dbus_string_lengthen (&block.body, initial_offset)) goto out; /* Create a run containing all the items */ i = 0; while (i < _DBUS_N_ELEMENTS (items)) { _dbus_assert (i == items[i].which); run.items[i] = items[i].which; ++i; } run.items[i] = ITEM_INVALID; if (!perform_one_run (&block, byte_order, &run)) goto out; retval = TRUE; out: data_block_free (&block); return retval; } static dbus_bool_t recursive_marshal_test_iteration (void *data) { int i; i = 0; while (i < 18) { if (!perform_all_runs (DBUS_LITTLE_ENDIAN, i)) return FALSE; if (!perform_all_runs (DBUS_BIG_ENDIAN, i)) return FALSE; if (!perform_all_items (DBUS_LITTLE_ENDIAN, i)) return FALSE; if (!perform_all_items (DBUS_BIG_ENDIAN, i)) return FALSE; ++i; } return TRUE; } dbus_bool_t _dbus_marshal_recursive_test (void); dbus_bool_t _dbus_marshal_recursive_test (void) { _dbus_test_oom_handling ("recursive marshaling", recursive_marshal_test_iteration, NULL); return TRUE; } #if 1 int main (int argc, char **argv) { _dbus_marshal_recursive_test (); return 0; } #endif /* main() */ #endif /* DBUS_BUILD_TESTS */